Клиначёв Николай Васильевич

Технология создания внешних "dll-моделей"
для моделирующей программы VisSim

Актуальность наличия технологий решения задач моделирования, мониторинга и управления сложными технологическими объектами не вызывает сомнений. Сегодня у научных и инженерно-технических работников в наличии имеется большое количество программных продуктов в основном зарубежного производства. Полноценное их использование в силу не полной документированности или дороговизны отдельных составляющих модулей (библиотек) затруднительно. Поэтому наличие возможности самостоятельного расширения пакетов конечным пользователем всегда представляет особый интерес. "MathConnex" в пакете "Mathcad 2000", и "VisSim" - возможно наиболее известные моделирующие программы, имеющие интерфейсы для расширений.

Существуют несколько технологий расширений. Первая - внедрение ActiveX объектов других программных продуктов (см. "MathConnex"). Вторая - динамический обмен данными между программами посредством DDE или OPC серверов / клиентов. Третья - создание библиотечных модулей с новыми для пакетов процедурами и функциями. Пакет VisSim имеет все три механизма. Первые два интуитивно понятны и хорошо описаны в документации. Методика подключения внешних, динамически загружаемых библиотек - dll документирована не полностью, поэтому вызывает затруднения у пользователей, хотя способна существенно расширить возможности пакета. Пользователь сможет, используя известный ему язык программирования С, С++, Pascal (Delphi), Basic, Fortran создавать новые линейные, нелинейные, дискретные, частотно зависимые элементы, расширяя библиотеку стандартных; разрабатывать собственные процедуры и функции измерений, анализа, работы с базами данных; подключать как собственные, так и стандартные платы сбора данных (DAQ-board) или OPC сервера для исследования, мониторинга, управления внешним объектом.

Постановка задачи. Необходимо создать "dll-модель" (согласно меню VisSim-а "userFunction") (см. рис. 1), которая имеет два выхода и выполняет две операции: интегрирование и синтез синусоидальной функции. Модель должна иметь: вход для интегратора, вход для временного сигнала, и вход для передачи значения шага моделирования.

Демонстрация результатов моделирования с использованием пользовательской функции "myF", подключенной с помощью блока "userFunction" из библиотеки Project2.dll, написанной с использованием зыка программирования Pascal (Delphi)

Рис. 1

Модель должна иметь следующие начальные условия и параметры: 1) начальное значение, присваиваемое интегратору в начале моделирования, 2) амплитудное значение, 3) частоту и 4) фазу синтезируемого синусоидального сигнала. Т.е. при нажатии правой клавиши мыши на блоке "Project2.dll.myF", должно появится диалоговое окно - см. рис. 2.

 
 

Рис. 2

Все, что требуется - это написать библиотечную программу на языке Pascal в соответствии с определенными правилами, скомпилировать в файл Project2.dll (имя библиотеки значения не имеет) и подключить его к рабочему файлу пакета VisSim с помощью блока "userFunction". Для создания dll-библиотеки выбран язык Pascal (Delphi), поскольку в примерах пакета есть исходные файлы для языка С. Приведем распечатку файла Project2.dpr.

Файл: Project2.dpr

library Project2;

type
  InVector = array [0..9] of Double; { тип входной переменной: входов - 10    }
  OutVector = array [0..9] of Double; { тип выходной переменной: выходов - 10 }
  Global = record { запись параметров, и координат "dll"-модели }
    Uo : double;   { Начальное условие для интегратора ID1 }
    Am : double;   { Амплитуда синусоиды }
    freq : double; { частота синусоиды }
    faza : double; { фаза синусоиды }
end;

var ID1 : double; { вспомогательные переменные "dll"-модели }

{/************ Это базовая процедура в DLL ****************************/}
{/************ Вызывается VisSim-ом на каждом шаге моделирования ******/}
procedure myF(var P:Global; var inV:InVector; var outV:OutVector); export; stdcall;
begin
{ Расчеты, выполняемые на каждом шаге моделирования }
  ID1:=ID1+inV[0]*inV[2]/2; outV[0]:=ID1;              { интегрирование }
  outV[1]:=P.Am*sin(2*Pi*inV[1]*P.freq+P.faza); { синтез синусоидального сигнала  }
end;

{/************ Функция размещения параметров **************************/}
{/************ Вызывается VisSim-ом при создании блока ****************/}
function myFPA( var pCount:integer):Longint; export; stdcall;
begin
  pCount := 4; { число первых по списку параметров записываемых в файл *.vsm }
  myFPA := sizeof(Global);    { размер памяти необходимый под параметры }
end;

{/************ Процедура инициализации параметров *********************/}
{/************ Вызывается VisSim-ом после PA функции ******************/}
procedure myFPI( var P:Global ); export; stdcall;
begin
  { Инициализация параметров (координат) модели.
  значения постоянных времени, напряжений, токов ...}
  P.Uo:=0;
  P.Am:=10;
  P.freq:=2;
  P.faza:=0;
end;

{/************ Функция изменения параметров ***************************/}
{/************ Вызывается VisSim-ом при нажатии правой клавиши мыши ***/}
function myFPC( var P:Global ):Pchar; export; stdcall;
begin
  { Изменение параметров модели:
  соответствующий очередности список названий параметров }
  myFPC :='Начальное условие;Am;freq;faza';{ названия могут быть любые }
end;

{/************ Процедура Simulation Start *****************************/}
{/************ Вызывается VisSim-ом на первом шаге моделирования ******/}
procedure myFSS( var P:Global; var runCount:longint); export; stdcall;
begin
  { присвоение начальных условий интеграторам:
  напряжений на конденсаторах, токов в индуктивностях ...}
  ID1:=P.Uo;
end;

{/************ Процедура Simulation End *******************************/}
{/************ Вызывается VisSim-ом на последнем шаге моделирования ***/}
procedure myFSE( var P:Global; var runCount:longint); export; stdcall;
begin
  { сохранение значений интеграторов для повторного запуска
  при многоэтапном моделировании:
  напряжений на конденсаторах, токов в индуктивностях ...}
end;

exports
  myF   index 1,{ Имя базовой процедуры в DLL Его нужно будет указать в блоке userFunction }
  myFPA index 2,{ Список вспомогательных процедур и функций для экспорта. Они будут        }
  myFPI index 3,{ вызываться Vissim-ом по окончаниям PA,PI,PC,SS,SE для базового имени.    }
  myFPC index 4,
  myFSS index 5,
  myFSE index 6;

begin
end.

По тексту программы видно, что для базовой функции (процедуры) с именем "myF" пользователь должен написать минимум еще пять процедур и функций, назначение которых ясно из комментариев. Следует отметить, что откомпилированная, тридцатидвухразрядная библиотека подключается ко всем версиям пакета VisSim начиная со 2-ой (текущая 4.5 Beta).

К сожалению VisSim не создает экземпляров dll-библиотек, поэтому повторное использование dll-библиотеки требует размножения файла *.dll (*.dll, *1.dll, *2.dll, ...). Этот прием демонстрирует модель сигма-дельта аналогово-цифрового преобразователя (см. в архиве (files) дискуссионной e-группы). Цифровой фильтр модели состоит из трех одинаковых звеньев. Одно звено это одна dll-библиотека.

Любой из частотных анализов неприменим для dll-библиотек. Поскольку VisSim не производит виртуальных измерений, а анализирует модели используя передаточные функции.

При написании dll-библиотек пользователю предоставляется еще две, интересные возможности. Первая заключена в использовании глобальных переменных и процедур непосредственно файла Vissim32.exe, что избавляет от необходимости передавать в и из "dll-модели" пользователя переменные и сигналы "шаг моделирования", "время моделирования", "остановить моделирование", "ошибка в dll-модели". Вторая заключена в направлении потока событий (Event) в "dll-модель", что позволяет пользовательской модели реагировать как на события стандартных устройств ввода / вывода: клавиатуры, мыши, так и на события пакета VisSim: "получить имя модели", "получить описание параметров", "установить локальный временной шаг моделирования", "выполнить пред-моделирование", "выполнить пост-моделирование", и т.д.

25.08.2000