ЭТАП 4 - Написание программы ПИД-регулятора для ЦВМ
Не затрагивая вопрос выбора ЦВМ, скажем, что это может быть периферийный контроллер (PIC), микроЭВМ (8051, AVR, ...), ЭВМ (x86, ...), промышленный контроллер, DSP (ADSP-21xxx, TMS320, ...) или схема на жесткой логике. Составление программы выполняющей расчет рекурсивного уравнения (*) обычно не вызывает затруднений, если ЦВМ имеет команды деления и умножения чисел (желательно с большой мантиссой и плавающей точкой).
В табл. 1 и 2 представлены программы рекурсивного цифрового фильтра второго порядка. Они написаны на языках C++ и Паскале в средах разработки Borland C++Builder 4 и Borland Delphi 4 в соответствии с технологией создания моделей пользователя для программы VisSim. При трансляции получается файл pid.dll, главная функция которого "zW" может быть включена в модель программы VisSim с помощью блока "userFunction" (см. рис. 7). При записи коэффициентов РУ (*) в параметры блока и стробировании частотой 2000 Гц - это и будет модель искомого дискретного ПИД-регулятора.

Рис. 7
Таблица 1
Файл pid.cpp | |
#include <math.h> #include <condefs.h> #pragma hdrstop #define EXPORT32 __declspec(dllexport) //--------------------------------------------------------------------------- struct z_TF_INFO { double k; // коэффициент усиления double b0,b1,b2; // коэффициенты полинома числителя double a0,a1,a2; // коэффициенты полинома знаменателя }; //--------------------------------------------------------------------------- extern "C" { double buffer_x[2]={0,0}, buffer_y[]={0,0}; double c, help_y; //************ Функция размещения параметров ******************************** //************ Вызывается VisSim-ом при создании блока ********************** EXPORT32 long WINAPI zWPA(short FAR *ppCount){ *ppCount=7; // число записываемых в файл vsm параметров модели пользователя return sizeof(z_TF_INFO); } //************ Процедура инициализации параметров *************************** //************ Вызывается VisSim-ом после PA функции ************************ EXPORT32 void WINAPI zWPI(z_TF_INFO *zTF){ zTF->k=31.9016459416667; zTF->b0=1; zTF->b1=-1.9894401341982; zTF->b2=0.98945592544195; zTF->a0=1; zTF->a1=-1.3333333333333; zTF->a2=0.33333333333333; } //************ Функция изменения параметров ********************************* //************ Вызывается VisSim-ом при нажатии правой клавиши мыши ********* EXPORT32 LPSTR WINAPI zWPC(z_TF_INFO *zTF){ return "k;b0;b1;b2;a0;a1;a2"; } //************ Процедура Simulation Start *********************************** //************ Вызывается VisSim-ом на первом шаге моделирования ************ EXPORT32 long WINAPI zWSS(z_TF_INFO *zTF, long *runCount){ buffer_x[0]=0; buffer_x[1]=0; buffer_y[0]=0; buffer_y[1]=0; help_y=0; c=0; return 0; } //************ Процедура Simulation End ************************************* //************ Вызывается VisSim-ом на последнем шаге моделирования ********* EXPORT32 long WINAPI zWSE(z_TF_INFO *zTF, long *runCount){ return 0; } //************ Это базовая процедура в DLL ********************************** //************ Вызывается VisSim-ом на каждом шаге моделирования ************ EXPORT32 void WINAPI zW(z_TF_INFO *zTF, double FAR x[], double FAR y[]){ if (x[0]==1 && c==0) { // Непосредственный алгоритм с двумя буферами help_y=(zTF->k*(x[1]*zTF->b0+buffer_x[0]*zTF->b1+buffer_x[1]*zTF->b2) -(buffer_y[0]*zTF->a1+buffer_y[1]*zTF->a2)) / zTF->a0; buffer_x[1]=buffer_x[0]; buffer_x[0]=x[1]; buffer_y[1]=buffer_y[0]; buffer_y[0]=help_y; // Непосредственный алгоритм с одним буфером /* double help; help=(x[1]-(buffer_x[0]*zTF->a1+buffer_x[1]*zTF->a2))/zTF->a0; help_y=(help*zTF->b0+buffer_x[0]*zTF->b1+buffer_x[1]*zTF->b2)*zTF->k; buffer_x[1]=buffer_x[0]; buffer_x[0]=help;*/ } y[0]=help_y; c=x[0]; // организованна синхронизация блока по фронту }; //--------------------------------------------------------------------------- }// end extern "C" { //--------------------------------------------------------------------------- int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*){ return 1; } |
Таблица 2
Файл pid.dpr |
library PID; type InVector = array [0..9] of Double; { тип входной переменной: входов - 10 } OutVector = array [0..9] of Double; { тип выходной переменной: выходов - 10 } Global = record { запись параметров, и координат "dll"-модели } k : double; b0, b1, b2 : double; a0, a1, a2 : double; end; var buffer_x, buffer_y : array [0..1] of double; c, help_y : double; {/************ Это базовая процедура в DLL ****************************/} {/************ Вызывается VisSim- ом на каждом шаге моделирования ******/} procedure zW(var zTF:Global; var x:InVector; var y:OutVector); export; stdcall; var help : double; begin if (x[0]=1)and(c=0) then begin { Непосредственный алгоритм с двумя буферами } help_y:=(zTF.k*(x[1]*zTF.b0+buffer_x[0]*zTF.b1+buffer_x[1]*zTF.b2) -(buffer_y[0]*zTF.a1+buffer_y[1]*zTF.a2))/zTF.a0; buffer_x[1]:=buffer_x[0]; buffer_x[0]:=x[1]; buffer_y[1]:=buffer_y[0]; buffer_y[0]:=help_y;{} { Непосредственный алгоритм с одним буфером } { help:=(x[1]-(buffer_x[0]*zTF.a1+buffer_x[1]*zTF.a2))/zTF.a0; help_y:=(help*zTF.b0+buffer_x[0]*zTF.b1+buffer_x[1]*zTF.b2)*zTF.k; buffer_x[1]:=buffer_x[0]; buffer_x[0]:=help;{} end; y[0]:=help_y; c:=x[0]; { организованна синхронизация блока по фронту } end; {/************ Функция размещения параметров **************************/} {/************ Вызывается VisSim-ом при создании блока ****************/} function zWPA( var pCount:integer):Longint; export; stdcall; begin pCount := 7; { число записываемых в файл параметров диалогового окна } zWPA := sizeof(Global); { размер памяти необходимый под параметры } end; {/************ Процедура инициализации параметров *********************/} {/************ Вызывается VisSim-ом после PA функции ******************/} procedure zWPI( var zTF:Global ); export; stdcall; begin zTF.k:=31.9016459416667; zTF.b0:=1; zTF.b1:=-1.9894401341982; zTF.b2:=0.98945592544195; zTF.a0:=1; zTF.a1:=-1.3333333333333; zTF.a2:=0.33333333333333; end; {/************ Функция изменения параметров ***************************/} {/************ Вызывается VisSim-ом при нажатии правой клавиши мыши ***/} function zWPC( var zTF:Global ):Pchar; export; stdcall; begin zWPC :='k;b0;b1;b2;a0;a1;a2'; { названия могут быть любые } end; {/************ Процедура Simulation Start *****************************/} {/************ Вызывается VisSim-ом на первом шаге моделирования ******/} procedure zWSS( var zTF:Global; var runCount:longint); export; stdcall; begin buffer_x[0]:=0; buffer_x[1]:=0; buffer_y[0]:=0; buffer_y[1]:=0; help_y:=0; c:=0; end; {/************ Процедура Simulation End *******************************/} {/************ Вызывается VisSim-ом на последнем шаге моделирования ***/} procedure zWSE( var zTF:Global; var runCount:longint); export; stdcall; begin end; exports zW index 1,{ Имя базовой процедуры в DLL Его нужно будет указать в блоке userFunction } zWPA index 2,{ Список вспомогательных процедур и функций для экспорта. Они будут } zWPI index 3,{ вызываться Vissim-ом по окончаниям PA,PI,PC,SS,SE для базового имени. } zWPC index 4, zWSS index 5, zWSE index 6; begin end. |