unit Difs; {!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Д И Н А М И Ч Е С К И Е Б Л О К И !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!} interface uses Windows, Classes, SysUtils, gltype, glproc, MathObj, MVTU_TLB; type TCrossZeroVars = class public x: TExtArray; ModelRecord: TStartRecord; constructor Create; destructor Destroy;override; end; function TTransf0(at,adt:RealType;var time,dtime:RealType;var AU,AY:TPtrExt;var AX,ADX:array of RealType; var CU,CY : TIntArray;var Prop:TPtrArray;var Vars:Pointer;Action:Integer):Integer;export; function TTransf1(at,adt:RealType;var time,dtime:RealType;var AU,AY:TPtrExt;var AX,ADX:array of RealType; var CU,CY : TIntArray;var Prop:TPtrArray;var Vars:Pointer;Action:Integer):Integer;export; function TTransf2(at,adt:RealType;var time,dtime:RealType;var AU,AY:TPtrExt;var AX,ADX:array of RealType; var CU,CY : TIntArray;var Prop:TPtrArray;var Vars:Pointer;Action:Integer):Integer;export; function TTransf3(at,adt:RealType;var time,dtime:RealType;var AU,AY:TPtrExt;var AX,ADX:array of RealType; var CU,CY : TIntArray;var Prop:TPtrArray;var Vars:Pointer;Action:Integer):Integer;export; function TTransf4(at,adt:RealType;var time,dtime:RealType;var AU,AY:TPtrExt;var AX,ADX:array of RealType; var CU,CY : TIntArray;var Prop:TPtrArray;var Vars:Pointer;Action:Integer):Integer;export; function TTransf5(at,adt:RealType;var time,dtime:RealType;var AU,AY:TPtrExt;var AX,ADX:array of RealType; var CU,CY : TIntArray;var Prop:TPtrArray;var Vars:Pointer;Action:Integer):Integer;export; function TTransf6(at,adt:RealType;var time,dtime:RealType;var AU,AY:TPtrExt;var AX,ADX:array of RealType; var CU,CY : TIntArray;var Prop:TPtrArray;var Vars:Pointer;Action:Integer):Integer;export; function TTransf7(at,adt:RealType;var time,dtime:RealType;var AU,AY:TPtrExt;var AX,ADX:array of RealType; var CU,CY : TIntArray;var Prop:TPtrArray;var Vars:Pointer;Action:Integer):Integer;export; function TTransf8(at,adt:RealType;var time,dtime:RealType;var AU,AY:TPtrExt;var AX,ADX:array of RealType; var CU,CY : TIntArray;var Prop:TPtrArray;var Vars:Pointer;Action:Integer):Integer;export; function TState(at,adt:RealType;var time,dtime:RealType;var AU,AY:TPtrExt;var AX,ADX:array of RealType; var CU,CY : TIntArray;var Prop:TPtrArray;var Vars:Pointer;Action:Integer):Integer;export; function TFUK(at,adt:RealType;var time,dtime:RealType;var AU,AY:TPtrExt;var AX,ADX:array of RealType; var CU,CY : TIntArray;var Prop:TPtrArray;var Vars:Pointer;Action:Integer):Integer;export; function TCrossZero(at,adt:RealType;var time,dtime:RealType;var AU,AY:TPtrExt;var AX,ADX:array of RealType; var CU,CY : TIntArray;var Prop:TPtrArray;var Vars:Pointer;Action:Integer):Integer;export; {********************************************************************************************************} IMPLEMENTATION {********************************************************************************************************} type PTransfRec = ^TTransfRec; TTransfRec = record K,Y0 : TExtArray end; PTransf1Rec = ^TTransf1Rec; TTransf1Rec = record b,a : TExtArray; Y0 : TExtArray end; PTransf2Rec = ^TTransf2Rec; TTransf2Rec = record K,TT,Y0 : TExtArray end; PTransf4Rec = ^TTransf4Rec; TTransf4Rec = record K,TT : PRealType; Y0 : TExtArray end; PTransf5Rec = ^TTransf5Rec; TTransf5Rec = record T1,T2 : PRealType; Y0 : TExtArray end; PTransf3Rec = ^TTransf3Rec; TTransf3Rec = record K,TT,b : PRealType; Y0 : TExtArray end; PTransf7Rec = ^TTransf7Rec; TTransf7Rec = record K,Ymin,Ymax,Y0 : TExtArray end; PTransf8Rec = ^TTransf8Rec; TTransf8Rec = record Count : PInteger; K : TExtArray end; PStateRec = ^TStateRec; TStateRec = record xc,uc,yc : ^Integer; A_,B_,C_,D_ : TExtArray2; Y0 : TExtArray end; PFukRec = ^TFukRec; TFukRec = record ai : TExtArray; end; {--------------------------------------------------------------------------- Идеальное интегрирующее звено Блок реализует передаточную функцию: K W(s) = ----- s (интегратор). Для работы блока необходимо задать коэффициент K и вектор начальных условий Y(0). Вход и выход блока много;ильные, при этом размер входа - выхода равен размеру вектора начальных условий ---------------------------------------------------------------------------} function TTransf0Convert(Action: integer; Vars: Pointer; Prop: TPtrArray; PropStr: TStringList; BlockId: integer; var MVTU: IMVTU_Server):integer; const RecName:PChar = 'Интегратор'; var Res: integer; begin case Action of //Возвращаем ссылку на имя записи в базе МВТУ-4 cnv_GetRecName: Result:=integer(RecName); //Конвертируем и устанавливаем параметры при помощи интерфейса МВТУ cnv_Convert: begin MVTU.SetBlockProp(BlockId,'k',PChar(ConvertVector(PropStr[0])),Res); MVTU.SetBlockProp(BlockId,'x0',PChar(ConvertVector(PropStr[1])),Res); end; end; end; function TTransf0; var j : Integer; begin Result:=0; with PTransfRec(Prop.arr)^ do case Action of f_GetConvertFuncAdr: Result:=integer(@TTransf0Convert); f_EditErr : if (K.Count <> Y0.Count)then Result:=er_Count; f_GetDeriCount : Result:=Y0.Count; f_GetStateCount : Result:=0; f_GetInit : Result:=1; f_GetCount : begin CU.arr^[0]:=Y0.Count;CY.arr^[0]:=CU.arr^[0] end; f_InitMem : for j:=0 to Y0.Count-1 do AY.Ptr(0).arr^[j]:=Y0.arr^[j]; f_InitState : for j:=0 to Y0.Count-1 do begin AX[j]:=Y0.arr^[j]; AY.Ptr(0).arr^[j]:=AX[j] end; f_RestoreOuts, f_GoodStep, f_UpdateJacoby, f_UpdateOuts : for j:=0 to Y0.Count-1 do AY.Ptr(0).arr^[j]:=AX[j]; f_GetDeri : for j:=0 to Y0.Count-1 do ADX[j]:=K.arr^[j]*AU.Ptr(0).arr^[j]; // f_SteadyState: for j:=0 to Y0.Count-1 do Y0.arr^[j]:=AX[j]; end{END CASE} end;{END TTransf0} // Блок для уточнения параметров при переходе функции через 0 // предназначен для уточнения вычисления параметров при // Данный блок использует специальные адресные записи для // доступа к внутренним переменным ядра. type TCrossZeroParams = packed record c: TExtArray; //Сдвиг нулевого значения d: TExtArray; //К-ты d - для (1 - при возрастании функции,-1 - при убывании) dtol: TExtArray; //Точность по времени end; PCrossZeroParams = ^TCrossZeroParams; constructor TCrossZeroVars.Create; begin x:=TExtArray.Create(0); end; destructor TCrossZeroVars.Destroy; begin x.Free; end; function TCrossZero; var i: Integer; dt,xi,di,v,h : double; begin Result:=0; with PCrossZeroParams(Prop.arr)^ do case Action of // f_GetConvertFuncAdr: Result:=integer(@TTransf0Convert); f_EditErr : if (d.Count <> dtol.Count) or (c.Count <> dtol.Count) then Result:=er_Count; f_Create: begin Vars:=TCrossZeroVars.Create; TCrossZeroVars(Vars).ModelRecord:=TStartRecord(at); end; f_Free: begin TObject(Vars).Free; end; f_GetCount : begin CU.arr^[0]:=dtol.Count; CY.arr^[0]:=CU.arr^[0] end; f_InitMem : with TCrossZeroVars(Vars) do x.ChangeCount(dtol.Count); f_InitState : with TCrossZeroVars(Vars) do for i:=0 to dtol.Count-1 do begin x.Arr^[i]:=AU.Ptr(0).Arr^[i] - c.Arr^[i]; AY.Ptr(0).Arr^[i]:=0; end; f_GetDeri, f_RestoreOuts, f_GoodStep, f_UpdateJacoby, f_UpdateOuts : with TCrossZeroVars(Vars) do begin for i:=0 to dtol.Count - 1 do begin //Точность отработки переходов по времени может быть установлена индивидуально !!! dt:=ModelRecord.RunParams.MinStep; if dt < dtol.Arr^[i] then dt:=dtol.Arr^[i]; xi:=x.Arr^[i]; di:=d.Arr^[i]; v:=AU.Ptr(0).Arr^[i] - c.Arr^[i]; AY.Ptr(0).Arr^[i]:=0; if Action = f_GoodStep then begin //пересечение if (xi*v<=0) and (xi<>0) and (di*xi<=0) then AY.Ptr(0).Arr^[i]:=1 else if ((xi*v>0) and ((di*xi<0) or (di=0)) ) and (abs(xi)>abs(v)) then begin //прогноз длины следующего шага h:=adt*v/(xi-v); if h<3*dt then h:=h+dt/2 else if h>4*dt then h:=h-dt/2 else h:=3.5*dt; if h < dt then h:=dt; //Собственно принудительное присвоение шага интегрирования if h < ModelRecord.ModelVars.newstep then begin ModelRecord.ModelVars.newstep:=h; ModelRecord.ModelVars.fsetstep:=True; end end; x.Arr^[i]:=v; end else //Здесь выдаём внешнему методу сигнал, чтобы он сделал ещё один шаг для отработки перехода if (xi*v<=0) and (xi<>0) and (di*xi<=0) and (adt>8*dt) then Result:=er_AccuracyError; end; end; end{END CASE} end; {--------------------------------------------------------------------------- Передаточная функция общего вида Блок реализует передаточную функцию: N(s) W(s) = ------- L(s) Для работы блока необходимо задать коэффициент K и начальное условие y(0). ---------------------------------------------------------------------------} function TTransf1Convert(Action: integer; Vars: Pointer; Prop: TPtrArray; PropStr: TStringList; BlockId: integer; var MVTU: IMVTU_Server):integer; const RecName:PChar = 'Передаточная ф-я общего вида'; var Res: integer; begin case Action of //Возвращаем ссылку на имя записи в базе МВТУ-4 cnv_GetRecName: Result:=integer(RecName); //Конвертируем и устанавливаем параметры при помощи интерфейса МВТУ cnv_Convert: begin MVTU.SetBlockProp(BlockId,'b',PChar(ConvertVector(PropStr[0])),Res); MVTU.SetBlockProp(BlockId,'a',PChar(ConvertVector(PropStr[1])),Res); MVTU.SetBlockProp(BlockId,'y0',PChar(ConvertVector(PropStr[2])),Res); end; end; end; function TTransf1; var i : Integer; x : RealType; begin Result:=0; with PTransf1Rec(Prop.arr)^ do case Action of f_GetConvertFuncAdr: Result:=integer(@TTransf1Convert); f_EditErr : begin if a.count < b.count then Result:=er_order; if (a.count < 2) then Result:=er_OrderMin; if a.arr^[a.count-1] = 0 then Result:=er_parzero; end; f_GetDeriCount : Result:=a.count-1; f_GetStateCount : Result:=0; f_GetInit : if b.count < a.count then Result:=1 else Result:=0; f_GetCount : begin CU.arr^[0]:=1;CY.arr^[0]:=1 end; f_InitState : begin for i:=1 to a.count-2 do AX[i]:=0; i:=a.count-1; if (Y0.arr^[0]=0.0) or (b.arr^[0]=0.0) or (b.arr^[0]-a.arr^[0]*b.arr^[i]/a.arr^[i] = 0.0) then AX[0]:=0.0 else if b.count = a.count then AX[0]:=Y0.arr^[0]/(b.arr^[0]-a.arr^[0]*b.arr^[i]/a.arr^[i]) else AX[0]:=Y0.arr^[0]/b.arr^[0]; if b.count = a.count then AY.Ptr(0).arr^[0]:=Y0.arr^[0]+AU.Ptr(0).arr^[0]*b.arr^[i]/a.arr^[i] else AY.Ptr(0).arr^[0]:=Y0.arr^[0] end; f_GoodStep, f_RestoreOuts, f_UpdateJacoby, f_UpdateOuts : begin x:=0; for i:=0 to b.count-2 do x:=x+b.arr^[i]*AX[i]; if b.count < a.count then AY.Ptr(0).arr^[0]:=x+b.arr^[b.count-1]*AX[b.count-1] else begin AY.Ptr(0).arr^[0]:=x; x:=AU.Ptr(0).arr^[0]; for i:=0 to a.count-2 do x:=x-a.arr^[i]*AX[i]; x:=x/a.arr^[a.count-1]; AY.Ptr(0).arr^[0]:=AY.Ptr(0).arr^[0]+b.arr^[b.count-1]*x end end; f_GetDeri : begin for i:=0 to a.count-3 do ADX[i]:=AX[i+1]; ADX[a.count-2]:=AU.Ptr(0).arr^[0]; for i:=0 to a.count-2 do ADX[a.count-2]:=ADX[a.count-2]-a.arr^[i]*AX[i]; ADX[a.count-2]:=ADX[a.count-2]/a.arr^[a.count-1] end; end{END CASE} end;{END TTransf1} {--------------------------------------------------------------------------- Блок реализует передаточную функцию: K*s W(s) = ------- T*s+1 Для работы блока необходимо задать коэффициент K и начальное условие y(0). ---------------------------------------------------------------------------} function TTransf4Convert(Action: integer; Vars: Pointer; Prop: TPtrArray; PropStr: TStringList; BlockId: integer; var MVTU: IMVTU_Server):integer; const RecName:PChar = 'Инерционно-дифференцирующее звено'; var Res: integer; begin case Action of //Возвращаем ссылку на имя записи в базе МВТУ-4 cnv_GetRecName: Result:=integer(RecName); //Конвертируем и устанавливаем параметры при помощи интерфейса МВТУ cnv_Convert: begin MVTU.SetBlockProp(BlockId,'k',PChar(PropStr[0]),Res); MVTU.SetBlockProp(BlockId,'T',PChar(PropStr[1]),Res); MVTU.SetBlockProp(BlockId,'x0',PChar(PropStr[2]),Res); end; end; end; function TTransf4; begin Result:=0; with PTransf4Rec(Prop.arr)^ do case Action of f_GetConvertFuncAdr: Result:=integer(@TTransf4Convert); f_EditErr : if (k^ = 0) or (TT^ = 0) then Result:=er_parzero; f_GetDeriCount : Result:=1; f_GetStateCount : Result:=0; f_GetInit : Result:=0; f_GetCount : begin CU.arr^[0]:=1; CY.arr^[0]:=1; end; f_InitState : begin AX[0]:=-TT^/k^*Y0.arr^[0]; AY.Ptr(0).arr^[0]:=Y0.arr^[0]+AU.Ptr(0).arr^[0]*k^/TT^ end; f_UpdateJacoby, f_RestoreOuts, f_GoodStep, f_UpdateOuts : AY.Ptr(0).arr^[0]:=k^*(AU.Ptr(0).arr^[0]-AX[0])/TT^; f_GetDeri : ADX[0]:=(AU.Ptr(0).arr^[0]-AX[0])/TT^; end{END CASE} end;{END TTransf4} {--------------------------------------------------------------------------- Блок реализует передаточную функцию: T1*s+1 W(s) = ------- T2*s+1 Для работы блока необходимо задать коэффициент K и начальное условие y(0). ---------------------------------------------------------------------------} function TTransf5Convert(Action: integer; Vars: Pointer; Prop: TPtrArray; PropStr: TStringList; BlockId: integer; var MVTU: IMVTU_Server):integer; const RecName:PChar = 'Инерционно-форсирующее звено'; var Res: integer; begin case Action of //Возвращаем ссылку на имя записи в базе МВТУ-4 cnv_GetRecName: Result:=integer(RecName); //Конвертируем и устанавливаем параметры при помощи интерфейса МВТУ cnv_Convert: begin MVTU.SetBlockProp(BlockId,'T1',PChar(PropStr[0]),Res); MVTU.SetBlockProp(BlockId,'T2',PChar(PropStr[1]),Res); MVTU.SetBlockProp(BlockId,'x0',PChar(PropStr[2]),Res); end; end; end; function TTransf5; begin Result:=0; with PTransf5Rec(Prop.arr)^ do case Action of f_GetConvertFuncAdr: Result:=integer(@TTransf5Convert); f_EditErr : if (T2^ = 0) then Result:=er_parzero; f_GetDeriCount : Result:=1; f_GetStateCount : Result:=0; f_GetInit : Result:=0; f_GetCount : begin CU.arr^[0]:=1; CY.arr^[0]:=1; end; f_InitState : begin if T1^ <> T2^ then AX[0]:=Y0.arr^[0]/(1-T1^/T2^) else AX[0]:=0; AY.Ptr(0).arr^[0]:=Y0.arr^[0]+AU.Ptr(0).arr^[0]*T1^/T2^ end; f_GoodStep, f_RestoreOuts, f_UpdateJacoby, f_UpdateOuts : AY.Ptr(0).arr^[0]:=AX[0]+T1^*(AU.Ptr(0).arr^[0]-AX[0])/T2^; f_GetDeri : ADX[0]:=(AU.Ptr(0).arr^[0]-AX[0])/T2^; end{END CASE} end;{END TTransf5} {--------------------------------------------------------------------------- Апериодическое звено 1-го порядка Блок реализует передаточную функцию: K W(S) = ----------- T*s + 1 (апериодическое звено 1-го порядка). Обязательное условие: T <> 0. Для работы блока необходимо задать коэффициент усиления K, постоянную времени T и начальное условие y(0). Вход и выход блока много;ильные, при этом размер входа - выхода равен размеру вектора начальных условий ---------------------------------------------------------------------------} function TTransf2Convert(Action: integer; Vars: Pointer; Prop: TPtrArray; PropStr: TStringList; BlockId: integer; var MVTU: IMVTU_Server):integer; const RecName:PChar = 'Инерционное звено 1-го порядка'; var Res: integer; begin case Action of //Возвращаем ссылку на имя записи в базе МВТУ-4 cnv_GetRecName: Result:=integer(RecName); //Конвертируем и устанавливаем параметры при помощи интерфейса МВТУ cnv_Convert: begin MVTU.SetBlockProp(BlockId,'k',PChar(ConvertVector(PropStr[0])),Res); MVTU.SetBlockProp(BlockId,'T',PChar(ConvertVector(PropStr[1])),Res); MVTU.SetBlockProp(BlockId,'x0',PChar(ConvertVector(PropStr[2])),Res); end; end; end; function TTransf2; var j : Integer; begin Result:=0; with PTransf2Rec(Prop.arr)^ do case Action of f_GetConvertFuncAdr: Result:=integer(@TTransf2Convert); f_EditErr : begin if (K.Count <> Y0.Count)or(TT.Count <> Y0.Count) then Result:=er_Count; for j:=0 to TT.Count-1 do if (TT.arr^[j] = 0) then Result:=er_parzero; end; f_GetDeriCount : Result:=Y0.Count; f_GetStateCount : Result:=0; f_GetInit : Result:=1; f_GetCount : begin CU.arr^[0]:=Y0.Count;CY.arr^[0]:=CU.arr^[0] end; f_InitState : for j:=0 to AU.Ptr(0).Count-1 do begin AX[j]:=Y0.arr^[j]; AY.Ptr(0).arr^[j]:=AX[j]; end; f_GoodStep, f_RestoreOuts, f_UpdateJacoby, f_UpdateOuts : for j:=0 to AU.Ptr(0).Count-1 do AY.Ptr(0).arr^[j]:=AX[j]; f_GetDeri : for j:=0 to AU.Ptr(0).Count-1 do ADX[j]:=(K.arr^[j]*AU.Ptr(0).arr^[j]-AX[j])/TT.arr^[j]; // f_SteadyState: for j:=0 to Y0.Count-1 do Y0.arr^[j]:=AX[j]; end{END CASE} end;{END TTransf2} {--------------------------------------------------------------------------- Колебательное звено Блок реализует передаточную функцию: K W(s) = -------------------------------- T^2*s^2 + 2*T*b*s + 1 (колебательное звено). Обязательное условие: T <> 0. Для работы блока необходимо задать коэффициент усиления K, постоянную времени T, коэффициент демпфирования b и начальные условия y’(0) и y(0) . Блок имеет один скалярный вход и один скалярный выход ---------------------------------------------------------------------------} function TTransf3Convert(Action: integer; Vars: Pointer; Prop: TPtrArray; PropStr: TStringList; BlockId: integer; var MVTU: IMVTU_Server):integer; const RecName:PChar = 'Колебательное звено'; var SL: TStringList; Res: integer; begin case Action of //Возвращаем ссылку на имя записи в базе МВТУ-4 cnv_GetRecName: Result:=integer(RecName); //Конвертируем и устанавливаем параметры при помощи интерфейса МВТУ cnv_Convert: begin MVTU.SetBlockProp(BlockId,'k',PChar(PropStr[0]),Res); MVTU.SetBlockProp(BlockId,'T',PChar(PropStr[1]),Res); MVTU.SetBlockProp(BlockId,'b',PChar(PropStr[2]),Res); //Т.к. начальные устовия - вектор, то переводим его try SL:=TStringList.Create; //Парсим свойство заданное в одной строчке ExtractStrings([' ',';'],[' '],PChar(PropStr[3]),SL); //Присваиваем параметры для блока MVTU.SetBlockProp(BlockId,'x0',PChar(SL[0]),Res); MVTU.SetBlockProp(BlockId,'dx0',PChar(SL[1]),Res); finally SL.Free; end; end; end; end; function TTransf3; begin Result:=0; with PTransf3Rec(Prop.arr)^ do case Action of f_GetConvertFuncAdr: Result:=integer(@TTransf3Convert); f_EditErr : if (TT^ = 0) then Result:=er_parzero; f_GetDeriCount : Result:=2; f_GetStateCount : Result:=0; f_GetInit : Result:=1; f_GetCount : begin CU.arr^[0]:=1; CY.arr^[0]:=1; end; f_InitState : begin AX[0]:=Y0.arr^[0]; AX[1]:=Y0.arr^[1]; AY.Ptr(0).arr^[0]:=AX[0]; end; f_GoodStep, f_RestoreOuts, f_UpdateJacoby, f_UpdateOuts : AY.Ptr(0).arr^[0]:=AX[0]; f_GetDeri : begin ADX[1]:=(K^*AU.Ptr(0).arr^[0]-2*b^*TT^*AX[1]-AX[0])/(TT^*TT^); ADX[0]:=AX[1] end; // f_SteadyState: begin Y0.arr^[0]:=AX[0];Y0.arr^[1]:=AX[1] end; end{END CASE} end;{END TTransf3} {--------------------------------------------------------------------------- Инерционно-интегрирующее звено Блок реализует передаточную функцию: K W(s) = --------------- s*(T*s + 1) (интегратор c апериодическим звеном). Обязательное условие: T <>0. Для работы блока необходимо задать коэффициент K, постоянную времени T и начальные условия y’(0) и y(0). Блок имеет один скалярный вход и один скалярный выход ---------------------------------------------------------------------------} function TTransf6Convert(Action: integer; Vars: Pointer; Prop: TPtrArray; PropStr: TStringList; BlockId: integer; var MVTU: IMVTU_Server):integer; const RecName:PChar = 'Инерционно-интегрирующее звено'; var SL: TStringList; Res: integer; begin case Action of //Возвращаем ссылку на имя записи в базе МВТУ-4 cnv_GetRecName: Result:=integer(RecName); //Конвертируем и устанавливаем параметры при помощи интерфейса МВТУ cnv_Convert: begin MVTU.SetBlockProp(BlockId,'k',PChar(PropStr[0]),Res); MVTU.SetBlockProp(BlockId,'T',PChar(PropStr[1]),Res); try SL:=TStringList.Create; //Парсим свойство заданное в одной строчке ExtractStrings([' ',';'],[' '],PChar(PropStr[2]),SL); //Присваиваем параметры для блока MVTU.SetBlockProp(BlockId,'x0',PChar(SL[0]),Res); MVTU.SetBlockProp(BlockId,'dx0',PChar(SL[1]),Res); finally SL.Free; end; end; end; end; function TTransf6; begin Result:=0; with PTransf4Rec(Prop.arr)^ do case Action of f_GetConvertFuncAdr: Result:=integer(@TTransf6Convert); f_EditErr : if (TT^ = 0) then Result:=er_parzero; f_GetDeriCount : Result:=2; f_GetStateCount : Result:=0; f_GetInit : Result:=1; f_GetCount : begin CU.arr^[0]:=1; CY.arr^[0]:=1; end; f_InitState : begin AX[0]:=Y0.arr^[0]; AX[1]:=Y0.arr^[1]; AY.Ptr(0).arr^[0]:=AX[0]; end; f_GoodStep, f_RestoreOuts, f_UpdateJacoby, f_UpdateOuts : AY.Ptr(0).arr^[0]:=AX[0]; f_GetDeri : begin ADX[1]:=(K^*AU.Ptr(0).arr^[0]-AX[1])/TT^; ADX[0]:=AX[1] end; // f_SteadyState: begin Y0.arr^[0]:=AX[0];Y0.arr^[1]:=AX[1] end; end{END CASE} end;{END TTransf6} {--------------------------------------------------------------------------- Интегратор с ограничением Блок реализует передаточную функцию: K W(s) = ----- s с ограничением выходного сигнала. Для работы блока необходимо задать коэффициент K ,вектора максимальных Ymax, минимальных Ymin значений выходных сигналов и начальных условий Y(0). Вход и выход блока много;ильные, при этом размер входа - выхода равен размеру вектора начальных условий ---------------------------------------------------------------------------} function TTransf7Convert(Action: integer; Vars: Pointer; Prop: TPtrArray; PropStr: TStringList; BlockId: integer; var MVTU: IMVTU_Server):integer; const RecName:PChar = 'Интегратор с ограничением'; var Res: integer; begin case Action of //Возвращаем ссылку на имя записи в базе МВТУ-4 cnv_GetRecName: Result:=integer(RecName); //Конвертируем и устанавливаем параметры при помощи интерфейса МВТУ cnv_Convert: begin MVTU.SetBlockProp(BlockId,'k',PChar(ConvertVector(PropStr[0])),Res); MVTU.SetBlockProp(BlockId,'ymin',PChar(ConvertVector(PropStr[1])),Res); MVTU.SetBlockProp(BlockId,'ymax',PChar(ConvertVector(PropStr[2])),Res); MVTU.SetBlockProp(BlockId,'x0',PChar(ConvertVector(PropStr[3])),Res); end; end; end; function TTransf7; var j : Integer; begin Result:=0; with PTransf7Rec(Prop.arr)^,Y0 do case Action of f_GetConvertFuncAdr: Result:=integer(@TTransf7Convert); f_EditErr : if (Count <> Ymax.Count)or(Count <> Ymin.Count) or (Count <> K.Count)then Result:=er_Count; f_GetDeriCount : Result:=Count; f_GetStateCount : Result:=0; f_GetInit : Result:=1; f_GetCount : begin CU.arr^[0]:=Count;CY.arr^[0]:=Count end; f_InitState : for j:=0 to AU.Ptr(0).Count-1 do begin AX[j]:=arr^[j]; AY.Ptr(0).arr^[j]:=AX[j] end; f_RestoreOuts, f_UpdateJacoby, f_UpdateOuts : for j:=0 to Count-1 do begin AY.Ptr(0).arr^[j]:=AX[j]; if (AX[j] >= Ymax.arr^[j]) then AY.Ptr(0).arr^[j]:=Ymax.arr^[j]; if (AX[j] <= Ymin.arr^[j]) then AY.Ptr(0).arr^[j]:=Ymin.arr^[j] end; f_GoodStep : for j:=0 to Count-1 do begin if (AX[j] >= Ymax.arr^[j]) then AX[j]:=Ymax.arr^[j]; if (AX[j] <= Ymin.arr^[j]) then AX[j]:=Ymin.arr^[j]; AY.Ptr(0).arr^[j]:=AX[j]; end; f_GetDeri : for j:=0 to Count-1 do begin ADX[j]:=K.arr^[j]*AU.Ptr(0).arr^[j]; if (AX[j] >= Ymax.arr^[j]) and (ADX[j] > 0) then ADX[j]:=0; if (AX[j] <= Ymin.arr^[j]) and (ADX[j] < 0) then ADX[j]:=0 end; // f_SteadyState: for j:=0 to Count-1 do arr^[j]:=AX[j]; end{END CASE} end;{END TTransf7} {--------------------------------------------------------------------------- Интегратор с изменением начальных условий в процессе интегрирования Блок реализует передаточную функцию: 1 W(s) = ----- s Блок имеет три входа . Первый вход u(1) являетcя векторным интегрируемым сигналом ; второй вход u(2) - логический управляющий сигнал (0 или 1), изменение значения которого приводит к интегрированию u(1) с новыми начальными условиями, которые берутся из векторного входа u(3) в момент переключения управляющего сигнала. ---------------------------------------------------------------------------} function TTransf8Convert(Action: integer; Vars: Pointer; Prop: TPtrArray; PropStr: TStringList; BlockId: integer; var MVTU: IMVTU_Server):integer; const RecName:PChar = 'Интегратор с изменяемыми н.у.'; var Res: integer; begin case Action of //Возвращаем ссылку на имя записи в базе МВТУ-4 cnv_GetRecName: Result:=integer(RecName); //Конвертируем и устанавливаем параметры при помощи интерфейса МВТУ cnv_Convert: begin MVTU.SetBlockProp(BlockId,'n',PChar(PropStr[0]),Res); MVTU.SetBlockProp(BlockId,'minflag',PChar(PropStr[1]),Res); MVTU.SetBlockProp(BlockId,'maxflag',PChar(PropStr[2]),Res); end; end; end; function TTransf8; var j : Integer; begin Result:=0; with PTransf8Rec(Prop.arr)^ do case Action of f_GetConvertFuncAdr: Result:=integer(@TTransf8Convert); f_GetDeriCount : Result:=Count^; f_GetStateCount : Result:=0; f_GetInit : Result:=0; f_GetCount : begin CY.arr^[0]:=Count^; CU.arr^[0]:=Count^; CU.arr^[2]:=Count^; CU.arr^[1]:=Count^; end; f_InitState : begin for j:=0 to Count^-1 do begin AX[j]:=AU.Ptr(2).arr^[j]; AY.Ptr(0).arr^[j]:=AX[j] end; // if abs(AU.Ptr(1).arr^[0]-K.arr^[0]) < abs(AU.Ptr(1).arr^[0]-K.arr^[1]) // then time:=1 else time:=0; end; f_GoodStep : begin { if AU.Ptr(1).arr^[0] = K.arr^[round(time)] then begin for j:=0 to Count^-1 do AX[j]:=AU.Ptr(2).arr^[j]; if time = 1 then time:=0 else time:=1 AY.Ptr(0).arr^[j]:=AX[j]; end;} for j:=0 to Count^-1 do begin if AU.Ptr(1).arr^[j] = K.arr^[1] then AX[j]:=AU.Ptr(2).arr^[j]; AY.Ptr(0).arr^[j]:=AX[j]; end; end; f_RestoreOuts: begin for j:=0 to Count^-1 do AY.Ptr(0).arr^[j]:=AX[j]; { if abs(AU.Ptr(1).arr^[0]-K.arr^[0]) < abs(AU.Ptr(1).arr^[0]-K.arr^[1]) then time:=1 else time:=0;} end; f_UpdateJacoby, f_UpdateOuts : for j:=0 to Count^-1 do AY.Ptr(0).arr^[j]:=AX[j]; f_GetDeri : for j:=0 to Count^-1 do ADX[j]:=AU.Ptr(0).arr^[j]; end{END CASE} end;{END TTransf8} {--------------------------------------------------------------------------- Переменные состояния Блок реализует описание многомерной линейной динамической системы в матричной форме: x’ = Ax + Bu; y = Cx + Du, где A, B, C, D - матрицы: собственная, входа, выхода и обхода, соответственно; x-вектор переменных состояния; u - вектор входа; y - вектор выхода. Размерность матрицы А - n*n, матрицы B - n*m, матрицы C - p*n, матрицы D - p*m (n >= p). Входом и выходом блока являются векторные (“много;ильные”) сигналы, размерностью m и p, соответственно. Для работы блока необходимо в диалоговом окне задать матрицы А, B, C, D и вектор начальных условий xi(0) при t = 0. Блок имеет один векторный вход и один векторный выход ---------------------------------------------------------------------------} function TStateConvert(Action: integer; Vars: Pointer; Prop: TPtrArray; PropStr: TStringList; BlockId: integer; var MVTU: IMVTU_Server):integer; const RecName:PChar = 'Переменные состояния'; var Res: integer; begin case Action of //Возвращаем ссылку на имя записи в базе МВТУ-4 cnv_GetRecName: Result:=integer(RecName); //Конвертируем и устанавливаем параметры при помощи интерфейса МВТУ cnv_Convert: begin MVTU.SetBlockProp(BlockId,'xc',PChar(PropStr[0]),Res); MVTU.SetBlockProp(BlockId,'uc',PChar(PropStr[1]),Res); MVTU.SetBlockProp(BlockId,'yc',PChar(PropStr[2]),Res); MVTU.SetBlockProp(BlockId,'A',PChar(ConvertMatrix(PropStr[3])),Res); MVTU.SetBlockProp(BlockId,'B',PChar(ConvertMatrix(PropStr[4])),Res); MVTU.SetBlockProp(BlockId,'C',PChar(ConvertMatrix(PropStr[5])),Res); MVTU.SetBlockProp(BlockId,'D',PChar(ConvertMatrix(PropStr[6])),Res); MVTU.SetBlockProp(BlockId,'y0',PChar(ConvertVector(PropStr[7])),Res); end; end; end; function TState; var i,j : Integer; x : RealType; begin Result:=0; with PStateRec(Prop.arr)^ do case Action of f_GetConvertFuncAdr: Result:=integer(@TStateConvert); f_GetStateCount: Result:=0; f_GetDeriCount : Result:=xc^; f_GetInit : begin Result:=1; for i:=0 to D_.countx-1 do for j:=0 to D_.county-1 do if D_.Val(i,j) <> 0 then begin Result:=0; break end end; f_GetCount : begin CU.arr^[0]:=uc^; CY.arr^[0]:=yc^ end; f_EditErr: begin if xc^ <> A_.CountX then Result:=er_count; if xc^ <> A_.CountY then Result:=er_count; if uc^ <> B_.CountX then Result:=er_count; if xc^ <> B_.CountY then Result:=er_count; if yc^ <> C_.CountY then Result:=er_count; if xc^ <> C_.CountX then Result:=er_count; if uc^ <> D_.CountX then Result:=er_count; if yc^ <> D_.CountY then Result:=er_count; end; f_InitMem : begin for i:=0 to xc^-1 do AX[i]:=Y0.arr^[i]; for i:=0 to yc^-1 do begin AY.Ptr(0).arr^[i]:=0; for j:=0 to xc^-1 do AY.Ptr(0).arr^[i]:=AY.Ptr(0).arr^[i] + C_.val(j,i)*AX[j] end end; f_InitState : begin for i:=0 to xc^-1 do AX[i]:=Y0.arr^[i]; for i:=0 to yc^-1 do begin x:=0; for j:=0 to xc^-1 do x:=x + C_.val(j,i)*AX[j]; AY.Ptr(0).arr^[i]:=x end; for i:=0 to yc^-1 do begin x:=AY.Ptr(0).arr^[i]; for j:=0 to uc^-1 do x:=x+ D_.val(j,i)*AU.Ptr(0).arr^[j]; AY.Ptr(0).arr^[i]:=x end end; f_GoodStep, f_RestoreOuts, f_UpdateJacoby, f_UpdateOuts : begin for i:=0 to yc^-1 do begin x:=0; for j:=0 to xc^-1 do x:=x + C_.val(j,i)*AX[j]; AY.Ptr(0).arr^[i]:=x; end; for i:=0 to yc^-1 do begin x:=AY.Ptr(0).arr^[i]; for j:=0 to uc^-1 do x:=x+ D_.val(j,i)*AU.Ptr(0).arr^[j]; AY.Ptr(0).arr^[i]:=x end end; f_GetDeri : begin for i:=0 to xc^-1 do begin x:=0; for j:=0 to xc^-1 do x:=x+A_.val(j,i)*AX[j]; ADX[i]:=x end; for i:=0 to xc^-1 do begin x:=ADX[i]; for j:=0 to uc^-1 do x:=x+B_.val(j,i)*AU.Ptr(0).arr^[j]; ADX[i]:=x end end; // f_SteadyState: for i:=0 to xc^-1 do Y0.arr^[i]:=AX[i]; end{END CASE} end;{END TState} {--------------------------------------------------------------------------- Квадратичный функционал качества Блок реализует функцию: 1 у(t) = --- <интеграл от 0 до T> сумма(ai*xi(t))^2*dt T (квадратичный функционал качества). Здесь T = t - текущее модельное время; xi(t) - мгновенное значение вектора входного сигнала; ai - весовые коэффициенты; у(t) - выходной сигнал. Для работы блока необходимо задать начальное условие y(0). ---------------------------------------------------------------------------} function TFUKConvert(Action: integer; Vars: Pointer; Prop: TPtrArray; PropStr: TStringList; BlockId: integer; var MVTU: IMVTU_Server):integer; const RecName:PChar = 'Функционал квадратичный'; var Res: integer; begin case Action of //Возвращаем ссылку на имя записи в базе МВТУ-4 cnv_GetRecName: Result:=integer(RecName); //Конвертируем и устанавливаем параметры при помощи интерфейса МВТУ cnv_Convert: try //Устанавливаем к-ты MVTU.SetBlockProp(BlockId,'Ai',PChar(ConvertVector(PropStr[0])),Res); finally end; end; end; function TFUK; var j : Integer; s : RealType; begin Result:=0; with PFukRec(Prop.arr)^ do case Action of f_GetConvertFuncAdr: Result:=integer(@TFUKConvert); f_GetDeriCount : Result:=1; f_GetStateCount : Result:=0; f_GetInit : Result:=1; f_GetCount : begin CY.arr^[0]:=1;CU.arr^[0]:=Ai.Count end; f_InitMem : AY.Ptr(0).arr^[0]:=0; f_InitState : begin AX[0]:=0; AY.Ptr(0).arr^[0]:=0 end; f_GetDeri : begin s:=0; for j:=0 to Ai.Count-1 do s:=s+SQR(AU.Ptr(0).arr^[j]*Ai.arr^[j]); ADX[0]:=s end; f_UpdateOuts, f_RestoreOuts, f_UpdateJacoby, f_GoodStep : if at > 0 then AY.Ptr(0).arr^[0]:=AX[0]/at; end{END CASE} end;{END TFUK} end.