Математическое ядро K2.SimKernel

Математическое ядро K2.SimKernel предназначено для динамического создания в памяти ЭВМ разнообразных, масштабируемых конфигураций исполняемого кода математических моделей динамических систем. Каждая конкретная конфигурация исполняемого кода либо программируется скриптом, либо определяется тем или иным SimML-файлом модели. В процессе исполнения кода модели интерфейс пользователя обеспечивают серверы визуализации и online-воздействий.

Ядро K2.SimKernel вместе с набором серверов визуализации и online-воздействий являются внутрипроцессорными COM-серверами и реализованы в виде динамически подключаемой библиотеки Klinachyov2.dll. Они могут быть встроены в любую программу-контейнер для элементов ActiveX. К таким программам относятся все программы MS Office, MS Visio, MS Internet Explorer, и многие другие.

Инсталляция математического ядра K2.SimKernel
(библиотеки Klinachyov2.dll)

Математическое ядро K2.SimKernel (библиотека Klinachyov2.dll) распространяется через Интернет и может быть автоматически установлена или обновлена на компьютере пользователя при посещении той или иной HTML-страницы. Устанавливается библиотека в директории для загружаемых браузером MS Internet Explorer программ:

...\WINDOWS\Downloaded Program Files\

Вместе с файлом Klinachyov2.dll устанавливается данный файл контекстной справки (K2SimKernel.chm).

Примечание 1: Каждая из программ контейнеров корпорации Microsoft, при обращении к библиотеке, создает ее файлы-образы в директории временных файлов ОС Windows (Klinachyov2Lib.EXD, или Klinachyov2Lib.TWD). Файл Klinachyov2Lib.TWD создается только программой Visio 5.0 и его надо искать в директории загружаемых браузером MS Internet Explorer программ. Версия пакета MS Office 97 не удаляет эти временные файлы, что вызывает конфликты при обновлении библиотеки. В такой ситуации временные файлы следует найти и удалить вручную.

Примечание 2: ActiveX-элементы библиотеки управляются скриптами, поэтому, если вы будете запускать содержащие их рабочие файлы программ MS Office, то вы будете предупреждены о наличии в них скриптов. При первом запуске вам следует деактивировать скрипты, и, проверив код, убедится в его безопасности (Alt+F11). При последующих запусках следует соглашаться с активацией скриптов.

Деинсталляция библиотеки Klinachyov2.dll

Для деинсталляции библиотеки вам нужно запустить браузер MS Internet Explorer, выбрать команду меню: Сервис > Свойства Обозревателя... На вкладке "Общие" надо нажать кнопку "Параметры...", за тем "Просмотр Объектов...". В открывшемся окне следует найти программу "Klinachyov's K2.SimKernel" и удалить с помощью контекстного меню.

Функционирование математического ядра K2.SimKernel

Математическое ядро K2 интенсивно передает данные серверам визуализации и получает управление от серверов online-воздействий. В силу этой причины эти компоненты не разделены для управления на уровне скриптов. Серверам визуализации и online-воздействий требуется очередь сообщений ОС Windows. Данный факт определяет формы совместного существования K2-ядра и серверов визуализации:

  1. Отдельное, исполняемое в пакетном режиме, exe-приложение (имеет собственную очередь сообщений).
  2. Интерактивно управляемый ведущим приложением (в типовом случае скриптами редакторов векторной графики, например, MS Visio) внешнепроцессорный exe-COM-сервер (Add-On).
  3. Внутрипроцессорный dll-COM-сервер (Add-In), получающий очередь сообщений от ведущего приложения (MS Visio).

Версия ядра K2.exe является не управляемым скриптами приложением (т.е. уровень интерактивности, снижен из-за невозможности воспользоваться сервисами шлюза Visio2SimKernel). После запуска программы появляется иконка "K2" в системной области строки "Пуск" ОС Windows. При клике по иконке другой клавишей мыши появляется меню с командами загрузки SimML-файла модели, управления процессом симуляции и выгрузки программы. Успешная загрузка рабочего файла сопровождается появлением одного или нескольких окон серверов визуализации и online-воздействий. Прибегнув к меню или горячим клавишам, можно выполнить процесс симуляции модели. На этом, собственно, описание процедур эксплуатации K2-ядра завершено. Если требуется внести изменения в SimML-файл модели, то следует воспользоваться библиотекой SimLib4Visio для редактирования модели или свойств симуляции и пересохранить файл с помощью шлюза библиотеки Visio2SimML (т.е. с помощью соответствующего пункта меню).

Архитектура математического ядра K2.SimKernel

Ядро K2 реализует классическую поточную модель управления процессом исполнения математических функций составляющих динамическую модель. Т.е. очередность их исполнения устанавливается фактом готовности аргументов.

В первом приближении можно утверждать, что K2-ядро реализуют три Си-класса: CBlkTemplate, CSimSpider и CSimRunner. Первый полиморфный класс CBlkTemplate, в соответствии с названием, представляет собой шаблон с виртуальными методами, реализуемыми библиотекой математических классов-потомков. Объект, порожденный от класса CSimSpider, как "Паук" порождает требуемое количество объектов, используя упомянутую библиотеку математических классов, и "плетет сеть" передачи аргументов между ними, настраивая указатели на возвращаемые данные. Дополнительной задачей возложенной на "Паука" является сортировка и упорядочивание порожденных объектов в массиве согласно приоритету исполнения (готовности аргументов) (см. Листинг 1). Последний объект, порожденный от класса CSimRunner, подключает к настроенной сети (к массиву) математических функций явный и неявный (итерационный) решатели требуемой размерности или же библиотеку идентификации и анализа, а так же имеет методы для управления процессом симуляции (см. Листинг 2). Сервера визуализации и online-воздействий подключаются к модели согласно той же технологии, что и любая математическая функция — с помощью соответствующих классов-потомков полиморфного класса CBlkTemplate.

Листинг 1 - Задачи решаемые "Пауком"

   // Разворачивание массива объектов-математических функций:
        MathBlock[0] = new CBlkTemplate::CLibEl_701(0,1,2); // объект-функция 1(t-dT)
        MathBlock[1] = new CBlkTemplate::CLibEl_100(2,1,2); // объект-функция Sum
        MathBlock[2] = new CBlkTemplate::CLibEl_107(2,1,0); // объект-функция Div
        MathBlock[3] = new CBlkTemplate::CLibEl_957(2,1,2); // объект-функция 1/z+clk
        MathBlock[4] = new CBlkTemplate::CLibEl_150(0,1,2); // объект-функция pulsTrain
        // ...
        // где аргументами конструкторов являются количества входов, выходов, параметров
        
        // + Настройка указателей на аргументы:
        //         MathBlock[i].pInput[j] = &MathBlock[k].Output[g];
        // ...

        // + Сортировка объектов в массиве MathBlock[i]

        // Резюме: Любая модель в K2-ядре представляется массивом объектов, 
        //         за каждым из которых (в реализации виртуального метода)
        //         закреплена та или иная математическая функция

Листинг 2 - Процедура исполнения шага симуляции, исполняемая "Рунером"

   for (i=0; i < numBlock; i++) {
                MathBlock[i]->Calc(); // вызов математических функций составляющих модель
        }
        // Примечание: virtual void CBlkTemplate::Calc() = 0; 
        //             - как видно, в шаблоне всех библиотечных 
        //             классов-потомков метод Calc() виртуальный.
        //             Он реализован индивидуально у каждого потомка

В среднем, в отличие от программ-калькуляторов (Mathcad, и др.) динамические решатели требуют в сотни и тысячи раз больше процессорного времени. Это связано с тем, что программы-калькуляторы исполняют код листинга 1 только один раз, а динамические решатели исполняют тот же код заданное количество раз, причем возможен запуск ими нескольких сессий этого кода в соответствии с тем или иным сценарием. В связи с этим процесс симуляции модели запускается "Рунером" K2-ядра в отдельном потоке. По завершению каждого шага симуляции, вызывается функция WinAPI Sleep(0), отдающая ЦПУ другим потокам / процессам. В связи с тем, что исполнение одного шага симуляции даже на младших Пентиумах редко затягивается более чем на 0.01 секунды, известное эмпирическое правило об 0.1 секунде для многозадачных ОС легко выполняется, и устройства ввода вывода компьютера (клавиатура, мышь, дисплей) не блокируются. Если же "Паук" ядра получает задание создать модель, содержащую очень большое количество объектов-функций, то через каждую сотню в массив MathBlock[i] он внедряет вспомогательный объект технического назначения, чей метод Calc() содержит функцию Sleep(0).

Описанная архитектура K2-ядра позволяет практически с предельным быстродействием осуществлять симуляцию динамических моделей, так как интерпретация задания (рабочего SimML-файла модели) осуществляется до симуляции во время работы "Паука". Известна возможность использования динамических решателей для автоматической генерации Си-кода с моделей пользователя. Реализация подобного расширения для K2-ядра легко осуществима. Расширение появится в будущих версиях для программирования DSP (цифровых сигнальных процессоров), однако выигрыша в быстродействии получить не позволит (летать быстрее света затруднительно :-)

Статические переменные и константы математического ядра K2.SimKernel

При функционировании K2-ядра возникает потребность в наличии переменных, доступных всем экземплярам объектов порожденных от библиотечных математических классов. Эту потребность удовлетворяют статические переменные объявленные в полиморфном классе CBlkTemplate (см. Листинг 3).

Листинг 3 - Статические переменные K2-ядра

   // Структура для хранения параметров симуляции
        struct SIM_INFO {
                double timeStart;    // Начальное время симуляции
                double timeEnd;      // Конечное время симуляции
                double time;         // Текущее время симуляции
                double dt;           // Шаг симуляции
                double dt05;         // Половина шага симуляции для операций "if"
                BOOL FirstStep;      // Признак первого шага
                ULONG sampleIndx;    // Текущий индекс выборки в окне
                ULONG samplesAmount; // Количество точек симуляции
                BOOL Continuously;   // Признак непрерывной работы
                INT runCount;        // Счетчик повторных симуляций
                BOOL firstCall;      // Признак первого вызова блоков с эффектом памяти
                BOOL rad;            // Признак величины измерения частоты: 1-Rad, 0-Hz
                INT RandomSeed;      // Инициирующее число генератора псевдослучайных чисел
                // ...
        };

        // Объявление статических переменных в полиморфном классе CBlkTemplate
        static double ERR;           // величина ошибки для математических операций
        static SIM_INFO SimProp;
        // ...

        // Обращение к статическим переменным полиморфного класса CBlkTemplate
        CBlkTemplate::ERR = DBL_EPSILON;
        CBlkTemplate::SimProp.timeStart = timeStart;
        CBlkTemplate::SimProp.timeEnd = timeEnd;
        CBlkTemplate::SimProp.time = timeStart;
        CBlkTemplate::SimProp.dt = T;
        CBlkTemplate::SimProp.dt05 = T / 2;
        CBlkTemplate::SimProp.FirstStep = true;
        CBlkTemplate::SimProp.sampleIndx = 0;
        // ...

Данный факт был бы мало интересен конечному пользователю, если бы те же самые переменные не использовались в моделях. Например, если бы у пользователя, при составлении блок-схем, не было бы блока SimKernelVar (см. библиотеку SimLib4Visio), который предоставляет доступ к глобальным переменным K2-ядра и в том числе к величине шага симуляции, то при каждом бы изменении свойств симуляции требовалась бы модификация всех дифференцирующих звеньев блок-схемы и ряда других субмоделей. Таким образом, блок SimKernelVar существенно облегчает построение гибких моделей и унифицированных субмоделей.

Рабочие файлы моделей для ядра K2.SimKernel

Функционирование математического ядра K2 характеризуется интенсивным использованием ОЗУ компьютера для создания разнообразных динамических конфигураций исполняемого кода. Данный процесс полностью определяется информацией, хранимой в рабочих SimML-файлах. Однако, их информационная структура не соответствует линейной как того требует K2-ядро (для разворачивания модели в памяти в виде массива MathBlock[i]), поскольку содержит дополнительную (излишнюю для ядра) информацию о графическом представлении модели.

Для решения задачи трансформации иерархической XML-разметки в линейную используется движок реляционной базы данных — MSXML парсер и соответствующий XSLT-сценарий рекурсивной обработки. Ее результатом как раз таки и пользуется "Паук" K2-ядра для разворачивания массива MathBlock[i].

Известно, что при отображении блок-схем принято использовать не только математические блоки: позиционер линии "wirePositioner", "субМодель", входной и выходной разъемы субобласти "sTerminal" и "dTerminal", а так же глобальные, инкапсулированные иерархической ветвью и внутриуровневые переменные пользователя. Кроме того что названные блоки нематематические, их особенность в том, что в отличие от блока текстовая "Метка" (тоже нематематический) они передают сигналы, а следовательно не могут быть просто отброшены "Пауком". Однако, все же их нужно исключить из массива MathBlock[i], дабы избежать затрат времени связанных с пустым перекопированием данных. Эту задачу решает уже упомянутый XSLT-сценарий рекурсивной обработки SimML-файла. Таким образом XSLT-сценарий не только трансформирует структуру хранилища модели, но и модифицирует данные в нем.

Генераторы псевдослучайных последовательностей ядра K2.SimKernel

В практике моделирования возникает потребность в генераторах случайной величины с разным распределением выборок на интервале. Все генераторы случайных величин при реализации на ЦВМ используют один базовый датчик, имеющий равномерное распределение. Его блок-схема показана на рисунке.

Генератор псевдослучайной бинарной последовательности

Рис. 1. Пяти-разрядный датчик псевдослучайной последовательности с равномерным распределением

Датчик представляет собой n-разрядный регистр сдвига, охваченный обратной связью посредствам элемента Исключающее ИЛИ (Xor). Если за выход датчика принять сам регистр, то можно получить псевдослучайную равномерно распределенную в интервале от 1 до 2n последовательность длинной (с периодом повторения) в 2n-1 выборок (нулевой код блокирует датчик). Если же за выход датчика принять любой разряд регистра, то получим генератор псевдослучайной бинарной последовательности той же длинны.

Длина псевдослучайной последовательности определяется разрядностью регистра и будет предельной лишь при определенной конфигурации обратной связи. В таблице исключений указаны номера разрядов регистра, которые должны быть использованы для формирования ОС посредствам многовходового элемента Исключающее ИЛИ при разной длине регистра.

Таблица исключений для обратной связи
 n  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20
  3
2
4
3
5
3
6
5
7
4
8
7
5
3
9
5
10
7
11
9
12
11
8
6
13
10
6
4
14
13
8
4
15
14
16
14
13
11
17
14
18
11
19
18
17
14
20
17

Математическое ядро K2 использует 15-ти разрядный датчик математической библиотеки msvcrt.dll. И сколько бы генераторов псевдослучайных последовательностей ни было установлено в вашей модели, все они обращаются к одному датчику. Поэтому длина его последовательности (предположительно 215) делится между генераторами. Следует учитывать этот факт и выбирать количество шагов симуляции или емкость памяти модели меньше длины последовательности приходящейся на генератор, дабы последняя не могла отличить псевдослучайную последовательность от истинно случайной.

Необходимо так же принимать во внимание, что не всем генераторам псевдослучайных величин подходят последовательно сгенерированные выборки датчика, что является причиной утечки длины его последовательности. Например, для трансформации равномерно распределенной величины в нормально распределенную, каждые две последовательные выборки датчика U и V, приведенные к интервалу от -1 до 1, отбрасываются до тех пор, пока не выполнится условие: S = U2+V2 < 1. Далее происходит трансформация выборок: U*(-2*ln(S))/S и V*(-2*ln(S))/S, результатом которой являются два независимых нормально pаспpеделенных псевдослучайных числа.

Легко сообразить, что кольцо псевдослучайной последовательности датчика можно сместить на любую позицию. Данная процедура может быть полезна для моделей самообучающихся систем с памятью, сохраняемой между повторными симуляциями.

Для смещения кольца последовательности нужно установить новое значение параметра "Random Seed" (инициирующее число для регистра датчика) в свойствах симуляции модели. Если данному параметру будет присвоена величина -1, то при запуске каждой следующей симуляции регистр датчика будет инициироваться словом, считанным с системных часов компьютера, которое изменяется каждую секунду.

При использовании генераторов псевдослучайных величин надо четко понимать, что все они имеют распределения соответствующие их названию лишь с определенным допуском.