Программная реализация модального управления для линейных стационарных систем
Наряду с общими методами синтеза оптимальных законов управления для стационарных объектов всё большее применение находят методы, основанные на решении задачи о размещении корней характеристического уравнения замкнутой системы в желаемое положение. Этого можно добиться надлежащим выбором матрицы обратной связи по состоянию. Решение указанной задачи является предметом теории модального управления (термин связан с тем, что корням характеристического уравнения соответствуют составляющие свободного движения, называемые модами).
Алгоритм модального управления.
Соглашения:
Задаваемый объект управления математически описывается уравнением
, (1)
где и - матрицы действительных коэффициентов,
- n-мерный вектор состояния
- скалярное управление,
- порядок системы (1).
Обратная связь по состоянию имеет вид
, (2)
где- матрица обратной связи.
Система с введенной обратной связью описывается уравнением
(3)
Характеристическое уравнение системы (1) имеет вид
(4)
Характеристическое уравнение системы (3) с задаваемыми (желаемыми) корнями имеет вид
(5)
Алгоритм:
1. Для исходной системы (1) составляем матрицу управляемости
2. Обращаем матрицу , т.е. вычисляем .
Если не существует (т.е. матрица - вырожденная), то прекращаем вычисления: полное управление корнями характеристического уравнения (5) не возможно.
3. Вычисляем матрицу
4. Составляем матрицу
5. Вычисляем матрицу, обратную матрице , т.е.
6. Вычисляем матрицу - матрицу в канонической форме фазовой переменной:
где - коэффициенты характеристического уравнения (4).
Матрица в канонической форме имеет вид
7. Составляем вектор , элементам которого являются коэффициенты характеристического уравнения (4), т.е. , ,
где - элементы матрицы .
8. Находим коэффициенты характеристического уравнения (5) (см. пояснения) и составляем из них вектор .
9. Вычисляем вектор .
- искомая матрица обратной связи системы (3), но она вычислена для системы, матрицы которой заданы в канонической форме фазовой переменной ( и ).
10. Для исходной системы (3) матрица обратной связи получается по формуле
Матрица - искомая матрица обратной связи.
Пояснения к алгоритму:
В данной работе рассматривается случай, когда управление единственно и информация о переменных состояния полная. Задача модального управления тогда наиболее просто решается, если уравнения объекта заданы в канонической форме фазовой переменной.
Так как управление выбрано в виде линейной функции переменных состояния , где является матрицей строкой . В таком случае уравнение замкнутой системы приобретает вид . Здесь
Характеристическое уравнение такой замкнутой системы будет следующим
Поскольку каждый коэффициент матрицы обратной связи входит только в один коэффициент характеристического уравнения, то очевидно, что выбором коэффициентов можно получить любые коэффициенты характеристического уравнения, а значит и любое расположение корней.
Если же желаемое характеристическое уравнение имеет вид
,
то коэффициенты матрицы обратной связи вычисляются с помощью соотношений:
Если при наличии одного управления нормальные уравнения объекта заданы не в канонической форме (что наиболее вероятно), то, в соответствии с пунктами №1-6 алгоритма, от исходной формы с помощью преобразования или нужно перейти к уравнению в указанной канонической форме.
Управление возможно, если выполняется условие полной управляемости (ранг матрицы управляемости M должен быть равен ). В алгоритме об управляемости системы судится по существованию матрицы : если она существует, то ранг матрицы равен ее порядку (). Для объекта управления с единственным управлением матрица оказывается также единственной.
Для нахождения коэффициентов характеристического уравнения (5), в работе используется соотношения между корнями и коэффициентами линейного алгебраического уравнения степени :
, (k = 1, 2, ... , )
где многочлены - элементарные симметрические функции, определяемые следующим образом:
,
,
,
...
гдеSk - сумма всех произведений, каждое из которых содержит k сомножителей xjс несовпадающими коэффициентами.
Программная реализация алгоритма.
Текст программной реализации приведен в ПРИЛОЖЕНИИ №1. Вот несколько кратких пояснений.
Программа написана на языке Object Pascal при помощи средств Delphi 2.0, и состоит из следующих основных файлов:
KursovayaWork.dpr
MainUnit.pas
SubUnit.pas
Matrix.pas
Operates.pas
HelpUnit.pas
OptsUnit.pas
KursovayaWork.dpr - файл проекта, содержащий ссылки на все формы проекта и инициализирующий приложение.
В модуле MainUnit.pas находится описание главной формы приложения, а также сконцентрированы процедуры и функции, поддерживаюшие нужный интерфейс программы.
Модули SubUnit.pas и Operates.pas содержат процедуры и функции, составляющие смысловую часть программной реализации алгоритма, т.е. процедуры решения задачи модально управления, процедуры решения систем дифференциальных уравнений, процедуры отображения графиков решений систем и т.д. Там также находятся процедуры отображения результатов расчетов на экран.
В модуле Matrix.pas расположено описание класса TMatrix - основа матричных данных в программе.
Модули HelpUnit.pas и OptsUnit.pas носят в программе вспомогательный характер.
Для решения систем дифференциальных уравнений использован метод Рунге-Кутта четвертого порядка точности с фиксированным шагом. Метод был позаимствован из пакета программ NumToolBox и адаптирован под новую модель матричных данных.
Обращение матриц производится методом исключения по главным диагональным элементам (метод Гаусса). Этот метод так же был позаимствован из NumToolBox и соответствующе адаптирован.
Пориложение.
program KursovayaWork;
uses
Forms,
MainUnit in 'MainUnit.pas' {Form_Main},
OptsUnit in 'OptsUnit.pas' {Form_Options},
SubUnit in 'SubUnit.pas',
Matrix in 'Matrix.pas',
Operates in 'Operates.pas',
HelpUnit in 'HelpUnit.pas' {Form_Help};
{$R *.RES}
begin
Application.Initialize;
Application.Title := 'Модальное управление';
Application.CreateForm(TForm_Main, Form_Main);
Application.CreateForm(TForm_Options, Form_Options);
Application.CreateForm(TForm_Help, Form_Help);
Application.Run;
end.
unit MainUnit;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ComCtrls, Tabnotbk, Menus, StdCtrls, Spin, ExtCtrls, Buttons, Grids,
OleCtrls, VCFImprs, GraphSvr, ChartFX {, ChartFX3};
type
TForm_Main = class(TForm)
BevelMain: TBevel;
TabbedNotebook_Main: TTabbedNotebook;
SpinEdit_Dim: TSpinEdit;
BitBtn_Close: TBitBtn;
BitBtn_Compute: TBitBtn;
StringGrid_Ap0: TStringGrid;
StringGrid_Anp0: TStringGrid;
StringGrid_Roots: TStringGrid;
StringGrid_Kpp0: TStringGrid;
StringGrid_Bp0: TStringGrid;
RadioGroup_RootsType: TRadioGroup;
Label_A1p0: TLabel;
Label_Ap0: TLabel;
Label_mBp0: TLabel;
Label_Roots: TLabel;
Label_Kpp0: TLabel;
BevelLine: TBevel;
Label_Dim: TLabel;
StringGrid_Ap1: TStringGrid;
StringGrid_Bp1: TStringGrid;
Label_Ap1: TLabel;
Label_Bp1: TLabel;
StringGrid_Kpp1: TStringGrid;
Label_Kpp1: TLabel;
StringGrid_InCond: TStringGrid;
Label_InCond: TLabel;
Label_U: TLabel;
Edit_U: TEdit;
BitBtn_Options: TBitBtn;
BitBtn_Help: TBitBtn;
StringGrid_ABKpp1: TStringGrid;
Label_ABKpp1: TLabel;
Edit_W: TEdit;
Label_w: TLabel;
RadioGroupChart: TRadioGroup;
ChartFX: TChartFX;
LabelW1: TLabel;
StringGrid_Solve1: TStringGrid;
StringGrid_Solve2: TStringGrid;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
procedure BitBtn_CloseClick(Sender: TObject);
procedure BitBtn_OptionsClick(Sender: TObject);
procedure BitBtn_ComputeClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure SpinEdit_DimChange(Sender: TObject);
procedure StringGrid_RootsSetEditText(Sender: TObject; ACol,
ARow: Longint; const Value: string);
procedure RadioGroup_RootsTypeClick(Sender: TObject);
procedure TabbedNotebook_MainChange(Sender: TObject; NewTab: Integer;
var AllowChange: Boolean);
procedure StringGrid_SetEditText(Sender: TObject; ACol,
ARow: Longint; const Value: string);
procedure BitBtn_HelpClick(Sender: TObject);
procedure RadioGroupChartClick(Sender: TObject);
private
procedure FillFixedCellsInAllGrids;
procedure FillCellsInAllGrids;
public
procedure BindGrids;
procedure UnBindGrids;
end;
var
Form_Main: TForm_Main;
implementation
uses Matrix, SubUnit, OptsUnit, Operates, CFXOCX2, HelpUnit;
const
DefOptions = (goFixedVertLine, goFixedHorzLine,
goVertLine, goHorzLine,
goColSizing, goEditing,
goAlwaysShowEditor, goThumbTracking);
{$R *.DFM}
procedure TForm_Main.FillFixedCellsInAllGrids;
var
Order : TOrder;
i: byte;
Str: string;
begin
Order := SpinEdit_Dim.Value;
for i := 1 to Order do
begin
Str := IntToStr(i);
StringGrid_Ap0.Cells(0, i) := Str;
StringGrid_Ap0.Cells(i, 0) := Str;
StringGrid_Bp0.Cells(0, i) := Str;
StringGrid_ANp0.Cells(i, 0) := Str;
StringGrid_ANp0.Cells(0, i) := Str;
StringGrid_Roots.Cells(i, 0) := Str;
StringGrid_Kpp0.Cells(i, 0) := Str;
StringGrid_Ap1.Cells(0, i) := Str;
StringGrid_Ap1.Cells(i, 0) := Str;
StringGrid_Bp1.Cells(0, i) := Str;
StringGrid_ABKpp1.Cells(i, 0) := Str;
StringGrid_ABKpp1.Cells(0, i) := Str;
StringGrid_InCond.Cells(i, 0) := Str;
StringGrid_Kpp1.Cells(i, 0) := Str;
StringGrid_Solve1.Cells(i, 0) := 'X' + IntToStr(i);
StringGrid_Solve2.Cells(i, 0) := 'X' + IntToStr(i);
StringGrid_Solve1.Cells(0, 0) := 'Время';
StringGrid_Solve2.Cells(0, 0) := 'Время';
end;
end;
procedure TForm_Main.FillCellsInAllGrids;
var
Order : TOrder;
i, j : byte;
begin
Order := SpinEdit_Dim.Value;
for i := 1 to Order do
for j := 1 to Order do
begin
StringGrid_Ap0.Cells(j, i) := '0';
StringGrid_Ap0.Cells(i, i) := '1';
StringGrid_Bp0.Cells(1, i) := '0';
StringGrid_Roots.Cells(i, 1) := '-1';
StringGrid_Roots.Cells(i, 2) := '0';
StringGrid_Kpp0.Cells(i, 1) := '0';
StringGrid_Ap1.Cells(j, i) := '0';
StringGrid_Ap1.Cells(i, i) := '1';
StringGrid_Bp1.Cells(1, i) := '0';
StringGrid_ABKpp1.Cells(j, i) := '0';
StringGrid_ABKpp1.Cells(i, i) := '1';
StringGrid_InCond.Cells(i, 1) := '0';
StringGrid_Kpp1.Cells(i, 1) := '0';
end;
FillFixedCellsInAllGrids;
StringGrid_Roots.Cells(0, 1) := 'Re';
StringGrid_Roots.Cells(0, 2) := 'Im';
StringGrid_Bp1.Cells(1, 0) := '1';
StringGrid_Bp0.Cells(1, 0) := '1';
end;
procedure TForm_Main.BindGrids;
begin
CopyGrid(StringGrid_Ap1, StringGrid_Ap0);
CopyGrid(StringGrid_Bp1, StringGrid_Bp0);
CopyGrid(StringGrid_Kpp1, StringGrid_Kpp0);
StringGrid_Ap1.Options := DefOptions - (goEditing);
StringGrid_Bp1.Options := DefOptions - (goEditing);
StringGrid_Kpp1.Options := DefOptions - (goEditing);
end;
procedure TForm_Main.UnBindGrids;
begin
StringGrid_Ap1.Options := DefOptions;
StringGrid_Bp1.Options := DefOptions;
StringGrid_Kpp1.Options := DefOptions;
end;
procedure TForm_Main.BitBtn_CloseClick(Sender: TObject);
begin
Close;
end;
procedure TForm_Main.BitBtn_OptionsClick(Sender: TObject);
var
V0, V1, V2, V3: LongInt;
LS: TCheckBoxState;
begin
with Form_Options do
begin
V0 := SpinEdit0.Value;
V1 := SpinEdit1.Value;
V2 := SpinEdit2.Value;
V3 := SpinEdit3.Value;
LS := CheckBox_Link.State;
ShowModal;
if ModalResult = mrCancel then
begin
SpinEdit0.Value := V0;
SpinEdit1.Value := V1;
SpinEdit2.Value := V2;
SpinEdit3.Value := V3;
CheckBox_Link.State := LS;
end
else
if ((SpinEdit0.Value <> V0) or (SpinEdit1.Value <> V1)) or
((SpinEdit2.Value <> V2) or (SpinEdit3.Value <> V3)) then
begin
BitBtn_Compute.Enabled := True;
case BitBtn_Compute.Tag of
4, 5 :BitBtn_Compute.Tag := BitBtn_Compute.Tag - 4;
6, 7 :BitBtn_Compute.Tag := BitBtn_Compute.Tag - 4;
8, 9 :BitBtn_Compute.Tag := BitBtn_Compute.Tag - 8;
10, 11 :BitBtn_Compute.Tag := BitBtn_Compute.Tag - 8;
12, 13 :BitBtn_Compute.Tag := BitBtn_Compute.Tag - 12;
14, 15 :BitBtn_Compute.Tag := BitBtn_Compute.Tag - 12;
end;
end;
end;
end;
procedure TForm_Main.BitBtn_ComputeClick(Sender: TObject);
begin
BitBtn_Compute.Enabled := False;
if Form_Options.CheckBox_Link.State = cbChecked then BindGrids;
case TabbedNotebook_Main.PageIndex of
0 : begin
ComputeFromPage0;
BitBtn_Compute.Tag := BitBtn_Compute.Tag + 1;
end;
1 : begin
ComputeFromPage1;
ShowChart(Succ(RadioGroupChart.ItemIndex));
BitBtn_Compute.Tag := BitBtn_Compute.Tag + 14;
end;
2 : begin
ComputeFromPage2;
BitBtn_Compute.Tag := BitBtn_Compute.Tag + 4;
end;
3 : begin
ComputeFromPage3;
BitBtn_Compute.Tag := BitBtn_Compute.Tag + 8;
end;
end;
end;
procedure TForm_Main.FormCreate(Sender: TObject);
const
FirstColWidth = 20;
begin
StringGrid_Ap0.ColWidths (0) := FirstColWidth;
StringGrid_Anp0.ColWidths (0) := FirstColWidth;
StringGrid_Bp0.ColWidths (0) := FirstColWidth;
StringGrid_Roots.ColWidths (0) := FirstColWidth;
StringGrid_Ap1.ColWidths (0) := FirstColWidth;
StringGrid_ABKpp1.ColWidths (0) := FirstColWidth;
StringGrid_Bp1.ColWidths (0) := FirstColWidth;
StringGrid_Kpp0.ColWidths (0) := FirstColWidth;
StringGrid_Kpp1.ColWidths (0) := FirstColWidth;
StringGrid_InCond.ColWidths (0) := FirstColWidth;
FillCellsInAllGrids;
BindGrids;
end;
procedure TForm_Main.SpinEdit_DimChange(Sender: TObject);
var
Order: byte;
begin
Order := Succ(SpinEdit_Dim.Value);
StringGrid_Ap0.ColCount := Order;
StringGrid_Ap0.RowCount := Order;
StringGrid_Anp0.ColCount := Order;
StringGrid_Anp0.RowCount := Order;
StringGrid_Bp0.RowCount := Order;
StringGrid_Roots.ColCount := Order;
StringGrid_Kpp0.ColCount := Order;
StringGrid_Ap1.ColCount := Order;
StringGrid_Ap1.RowCount := Order;
StringGrid_Bp1.RowCount := Order;
StringGrid_ABKpp1.ColCount := Order;
StringGrid_ABKpp1.RowCount := Order;
StringGrid_InCond.ColCount := Order;
StringGrid_Kpp1.ColCount := Order;
FillFixedCellsInAllGrids;
BitBtn_Compute.Enabled := True;
end;
procedure TForm_Main.StringGrid_RootsSetEditText(Sender: TObject; ACol,
ARow: Longint; const Value: string);
var
Val : string;
begin
if (ARow = 2) and (Value <> '') then
begin
Val := StringGrid_Roots.Cells (ACol, ARow);
if StrToFloat (Value) <> 0 then
StringGrid_Roots.Cells(Succ(ACol),ARow):=FloatToStr(- StrToFloat(Value));
if StrToFloat (Value) = 0 then
StringGrid_Roots.Cells (Succ(ACol),ARow) := FloatToStr(0);
end;
end;
procedure TForm_Main.RadioGroup_RootsTypeClick(Sender: TObject);
var
Order: TOrder;
j: byte;
NHalf: byte;
StartAlfa, NAlfa, dAlfa: Float;
W: Float;
begin
Order := SpinEdit_Dim.Value;
W := StrToFloat (Edit_W.Text);
case RadioGroup_RootsType.ItemIndex of
0 :StringGrid_Roots.Options := DefOptions;
1 :begin
for j := 1 to Order do
begin
StringGrid_Roots.Cells (j, 1) := FloatToStr (-W);
StringGrid_Roots.Cells (j, 2) := '0';
StringGrid_Roots.Options := DefOptions - (goEditing);
end
end;
2 :begin
dAlfa := Pi / Order;
StartAlfa := Pi/2 - dAlfa/2;
NHalf := Order div 2;
for j := 1 to NHalf do
begin
NAlfa := StartAlfa + dAlfa * j;
StringGrid_Roots.Cells (j, 1) := FloatToStr (Cos (NAlfa) * W);
StringGrid_Roots.Cells (Order - Pred (j), 1) := FloatToStr (Cos (-NAlfa) * W);
StringGrid_Roots.Cells (j, 2) := FloatToStr (Sin (NAlfa) * W);
StringGrid_Roots.Cells (Order - Pred (j), 2) := FloatToStr (Sin (-NAlfa) * W);
end;
if Odd (Order) then
begin
StringGrid_Roots.Cells (NHalf +1, 1) := FloatToStr (-W);
StringGrid_Roots.Cells (NHalf +1, 2) := '0';
end;
StringGrid_Roots.Options := DefOptions - (goEditing);
end;
end;
end;
procedure TForm_Main.TabbedNotebook_MainChange(Sender: TObject;
NewTab: Integer; var AllowChange: Boolean);
begin
with BitBtn_Compute do
case NewTab of
0 :begin
SpinEdit_Dim.Enabled := True;
if Tag in (1, 3, 5, 7, 9, 11, 13, 15) then Enabled := False
else Enabled := True;
BitBtn_Compute.Caption := 'Рассчитать модальное управление';
end;
1 :begin
SpinEdit_Dim.Enabled := True;
if Tag in (2, 3, 6, 7, 10, 11, 14, 15) then Enabled := False
else Enabled := True;
BitBtn_Compute.Caption := 'Решить системы дифф. уравнений ';
if Form_Options.CheckBox_Link.State = cbChecked then BindGrids;
end;
2 :begin
SpinEdit_Dim.Enabled := False;
if Tag in (4, 5, 6, 7, 12, 13, 14, 15) then Enabled := False
else Enabled := True;
BitBtn_Compute.Caption := 'Обновить результаты решений ';
end;
3 :begin
SpinEdit_Dim.Enabled := False;
if Tag in (8, 9, 10, 11, 12, 13, 14, 15) then Enabled := False
else Enabled := True;
BitBtn_Compute.Caption := 'Обновить диаграмму решения ';
end;
end;
end;
procedure TForm_Main.StringGrid_SetEditText(Sender: TObject; ACol,
ARow: Longint; const Value: string);
begin
if not BitBtn_Compute.Enabled then
case TabbedNotebook_Main.PageIndex of
0 :if Form_Options.CheckBox_Link.State = cbChecked then
BitBtn_Compute.Tag := BitBtn_Compute.Tag - 3
else
BitBtn_Compute.Tag := BitBtn_Compute.Tag - 1;
1 :BitBtn_Compute.Tag := BitBtn_Compute.Tag - 2;
end;
BitBtn_Compute.Enabled := True;
end;
procedure TForm_Main.BitBtn_HelpClick(Sender: TObject);
begin
Form_Help.ShowModal;
end;
procedure TForm_Main.RadioGroupChartClick(Sender: TObject);
begin
case RadioGroupChart.ItemIndex of
0 :ShowChart(1);
1 :ShowChart(2);
end;
end;
end.
unit SubUnit;
interface
uses
SysUtils, Matrix, Operates, Grids;
procedure CopyGrid(AGrid, BGrid: TStringGrid);
procedure LoadMatrixSolveFromStrGrd (AMatrix: TMatrix; AGrid: TStringGrid);
procedure ComputeFromPage0;
procedure ComputeFromPage1;
procedure ComputeFromPage2;
procedure ComputeFromPage3;
procedure ShowChart(NumberOfChart: Byte);
implementation
uses
MainUnit, OptsUnit, CFXOCX2;
procedure CopyGrid(AGrid, BGrid: TStringGrid);
var
i, j: LongInt;
begin
AGrid.ColCount := BGrid.ColCount;
AGrid.RowCount := BGrid.RowCount;
for j := 0 to AGrid.ColCount do
for i := 0 to AGrid.RowCount do
AGrid.Cells(j, i) := BGrid.Cells(j, i);
end;
function CropStr (Str: String): String;
var
i: Byte;
Str_1: String;
Begin
for i := Length(Str) downto 1 do
if Str (i) = ' ' then Str := Copy(Str, 1, i-1)
else Break;
Str_1 := Str;
for i := 1 to Length(Str) do
if Str(i) = ' ' then Str_1 := Copy(Str, i+1, Length(Str) - i)
else Break;
CropStr := Str_1;
End;
procedure LoadMatrixFromStrGrd (AMatrix: TMatrix; AGrid: TStringGrid);
var
i, j: Word;
begin
AMatrix.Resize (Pred(AGrid.ColCount), Pred(AGrid.RowCount));
for i := 1 to AMatrix.RowCount do
for j := 1 to AMatrix.ColCount do
begin
if CropStr(AGrid.Cells(j, i)) = '' then AGrid.Cells(j, i) := '0';
AMatrix(j ,i) := StrToFloat(AGrid.Cells(j, i))
end
end;
procedure OutPutMatrixToStrGrd (AMatrix: TMatrix; AGrid: TStringGrid);
var
i, j: Word;
begin
AGrid.ColCount := Succ(AMatrix.ColCount);
AGrid.RowCount := Succ(AMatrix.RowCount);
for i := 1 to AMatrix.RowCount do
for j := 1 to AMatrix.ColCount do
begin
AGrid.Cells(j, 0) := IntToStr (j);
AGrid.Cells(0, i) := IntToStr (i);
AGrid.Cells(j, i) := FloatToStrF(AMatrix(j ,i),ffGeneral,5,3);
end
end;
procedure OutPutMatrixSolveToStrGrd (AMatrix: TMatrix; AGrid: TStringGrid);
var
i, j, k: Word;
begin
AGrid.ColCount := AMatrix.ColCount;
AGrid.RowCount := Succ(AMatrix.RowCount);
for i := 1 to AMatrix.RowCount do
for j := 1 to AMatrix.ColCount do
begin
if j = AMatrix.ColCount then k := 0 else k := j;
AGrid.Cells(j, 0) := 'X' + IntToStr (j);
AGrid.Cells(k, i) := FloatToStrF(AMatrix(j ,i),ffGeneral,5,3);
end;
AGrid.Cells(0, 0) := 'Время';
end;
procedure LoadMatrixSolveFromStrGrd (AMatrix: TMatrix; AGrid: TStringGrid);
var
i, j, k: Word;
begin
AMatrix.Resize (AGrid.ColCount, Pred(AGrid.RowCount));
for i := 1 to AMatrix.RowCount do
for j := 0 to AMatrix.ColCount do
begin
if j = 0 then k := AMatrix.ColCount else k := j;
if CropStr(AGrid.Cells(j, i)) = '' then AGrid.Cells(j, i) := '0';
AMatrix(k ,i) := StrToFloat(AGrid.Cells(j, i))
end
end;
procedure ComputeFromPage0;
var
Order : TOrder;
i, j : byte;
K : ShortInt;
mDummy1, mDummy2,
mA, mB, mKp,
mM, mN, mN1: TMatrix;
cvRoots: TComplexVector;
begin
with Form_Main do
begin
Order := SpinEdit_Dim.Value;
mA := TMatrix.Create(Order, Order);
mB := TMatrix.Create(1, Order);
mM := TMatrix.Create(Order, Order);
mDummy1 := TMatrix.Create(Order, Order);
mN1 := TMatrix.Create(Order, 1);
mN := TMatrix.Create(Order, Order);
mDummy2 := TMatrix.Create(Order, Order);
mKp := TMatrix.Create(Order, 1);
LoadMatrixFromStrGrd (mA, StringGrid_Ap0);
LoadMatrixFromStrGrd (mB, StringGrid_Bp0);
for j := 1 to Order do
begin
mDummy1.Assign(mA);
mDummy1.NthPower(j - 1);
mDummy1.MultFromRight(mB);
for i := 1 to Order do
mM(j, i) := mDummy1(1, i);
end;
if not mM.Inverse then
Raise ESingularMatrix.Create('Система неполностью управляема:' +
'матрица M - вырожденная !!!'#10 +
'Измените значения коэффициентов матриц А и B');
mN1.SetNull;
mN1(Order, 1) := 1;
mN1.MultFromRight(mM);
for i := 1 to Order do
begin
mDummy2.Assign(mA);
mDummy2.NthPower(i-1);
mDummy1.Assign(mN1);
mDummy1.MultFromRight(mDummy2);
for j := 1 to Order do mN(j, i) := mDummy1(j, 1);
end;
mDummy1.Assign(mN);
if not mDummy1.Inverse then
Raise ESingularMatrix.Create('Не могу обратить матрицу N !!!'#10 +
'(не разбрасывайтесь порядками коэффициентов матриц)');
mA.MultFromLeft(mN);
mA.MultFromRight(mDummy1);
OutPutMatrixToStrGrd(mA, StringGrid_Anp0);
cvRoots.Dim := Order;
for j := 1 to Order do
begin
cvRoots.Data(j).Re := StrToFloat(StringGrid_Roots.Cells(j, 1));
cvRoots.Data(j).Im := StrToFloat(StringGrid_Roots.Cells(j, 2));
end;
for j := 1 to Order do
begin
if Odd (j) then K := -1 else K := +1;
mKp(Order-Pred(j), 1) := - mA(Order-Pred(j), Order) -
K * SymmetricalFunction(cvRoots, j);
end;
mKp.MultFromRight(mN);
OutPutMatrixToStrGrd (mKp, StringGrid_Kpp0);
mDummy1.Free;
mDummy2.Free;
mA.Free;
mB.Free;
mKp.Free;
mM.Free;
mN.Free;
mN1.Free;
end;
end;
procedure ComputeFromPage1;
var
Order: TOrder;
mA, mB, mABKp, mInCond, mKp: TMatrix;
mSolutionValues: TMatrix;
LowerLimit, UpperLimit, NumReturn, NumIntervals: Word;
begin
with Form_Main do
begin
Order := SpinEdit_Dim.Value;
mA := TMatrix.Create(Order, Order);
mB := TMatrix.Create(1, Order);
mKp := TMatrix.Create(Order, 1);
mInCond := TMatrix.Create(Order, 1);
LoadMatrixFromStrGrd(mA, StringGrid_Ap1);
LoadMatrixFromStrGrd(mB, StringGrid_Bp1);
LoadMatrixFromStrGrd(mKp, StringGrid_Kpp1);
LoadMatrixFromStrGrd(mInCond, StringGrid_InCond);
mABKp := TMatrix.Create(Order, Order);
mABKp.Assign(mB);
mABKp.MultFromRight(mKp);
mABKp.AddMatrix(mA);
OutPutMatrixToStrGrd(mABKp, StringGrid_ABKpp1);
mB.MultConst(StrToFloat(Edit_U.Text));
with Form_Options do
begin
LowerLimit := SpinEdit0.Value;
UpperLimit := SpinEdit1.Value;
NumReturn := SpinEdit2.Value;
NumIntervals := SpinEdit3.Value;
end;
mSolutionValues := TMatrix.Create(1, 1);
try
DiffSystemSolve (mA, mB,
LowerLimit, UpperLimit,
mInCond,
NumReturn, NumIntervals,
mSolutionValues);
OutPutMatrixSolveToStrGrd(mSolutionValues, StringGrid_Solve1);
mSolutionValues.ReSize(1, 1);
DiffSystemSolve (mABKp, mB,
LowerLimit, UpperLimit,
mInCond,
NumReturn, NumIntervals,
mSolutionValues);
OutPutMatrixSolveToStrGrd(mSolutionValues, StringGrid_Solve2);
except
on EO: EOverflow do
begin
EO.Message := 'Не буду считать !!!'#10 +
'С уменьшите разброс коэффициентов в матрицах'#10 +
'либо измените опции (уменьшите их pls.)';
Raise;
end;
end;
mA.Free;
mB.Free;
mABKp.Free;
mInCond.Free;
mKp.Free;
mSolutionValues.Free;
end;
end;
procedure ShowChart(NumberOfChart: Byte);
var
Order, Serie: TOrder;
NumReturn, Point: Word;
mSolutionValues: TMatrix;
procedure SetAdm;
const
Divisor = 3.4E+38;
var
i, j: LongInt;
Greatest, Least: Float;
begin
Greatest := mSolutionValues(1, 1);
Least := Greatest;
for j := 1 to Order do
for i := 1 to NumReturn do
begin
if mSolutionValues(j, i) > Greatest then Greatest := mSolutionValues(j, i);
if mSolutionValues(j, i) < Least then Least := mSolutionValues(j, i);
end;
Form_Main.ChartFX.Adm(CSA_MAX) := Greatest;
Form_Main.ChartFX.Adm(CSA_MIN) := Least;
Form_Main.ChartFX.Title(CHART_TOPTIT) := 'Y = Y '' * ';
end;
begin
with Form_Main do
begin
Order := SpinEdit_Dim.Value;
NumReturn := Form_Options.SpinEdit2.Value;
mSolutionValues := TMatrix.Create(1, 1);
ComputeFromPage1;
case NumberOfChart of
1 :begin
LoadMatrixSolveFromStrGrd(mSolutionValues, StringGrid_Solve1);
SetAdm;
ChartFX.OpenDataEx(Cod_Values, Order, Pred(NumReturn));
for Serie := 1 to Order do
begin
ChartFX.SerLeg(Pred(Serie)) := 'X ' + IntToStr(Serie);
ChartFX.ThisSerie := Pred(Serie);
for Point := 0 to Pred(NumReturn) do
ChartFX.Value(Point) := mSolutionValues(Serie, Succ(Point));
end;
ChartFX.CloseData(Cod_Values);
{
ChartFX.OpenDataEx(Cod_XValues, Order, Pred(NumReturn));
for Serie := 1 to Order do
begin
ChartFX.ThisSerie := Pred(Serie);
for Point := 0 to Pred(NumReturn) do
ChartFX.XValue(Point) := mSolutionValues(1, Succ(Point));
end;
ChartFX.CloseData(Cod_XValues);
}
end;
2 :begin
LoadMatrixSolveFromStrGrd(mSolutionValues, StringGrid_Solve2);
SetAdm;
ChartFX.OpenDataEx(Cod_Values, Order, Pred(NumReturn));
for Serie := 1 to Order do
begin
ChartFX.SerLeg(Pred(Serie)) := 'X ' + IntToStr(Serie);
ChartFX.ThisSerie := Pred(Serie);
for Point := 0 to Pred(NumReturn) do
ChartFX.Value(Point) := mSolutionValues(Serie, Succ(Point));
end;
ChartFX.CloseData(Cod_Values);
end;
end;
mSolutionValues.Free;
end;
end;
procedure ComputeFromPage2;
begin
ComputeFromPage1;
end;
procedure ComputeFromPage3;
begin
case Form_Main.RadioGroupChart.ItemIndex of
0 :ShowChart(1);
1 :ShowChart(2);
end;
end;
end.
unit Matrix;
interface
uses SysUtils;
type
Float = Extended;
EMatrixOperatingError = class (Exception);
const
NearlyZero = 1E-15;
type
TMatrix = class (TObject)
private
DataPtr: Pointer;
FCols, FRows: Word;
function GetCell (ACol, ARow: Word): Float;
procedure SetCell (ACol, ARow: Word; AValue: Float);
function GetItem (NumItem: LongInt): Float;
procedure SetItem (NumItem: LongInt; AValue: Float);
procedure SwitchRows (FirstRow, SecondRow: Word);
public
constructor Create (NCols, NRows: Word);
destructor Destroy; override;
procedure Assign (AMatrix: TMatrix);
procedure ReSize (NewCols, NewRows: Word);
procedure SetNull;
procedure SetSingle;
procedure SetNegative;
procedure AddConst (AConst: Float);
procedure AddMatrix (AMatrix: TMatrix);
procedure MultConst (MConst: Float);
procedure MultFromRight (MMatrix: TMatrix);
procedure MultFromLeft (MMatrix: TMatrix);
procedure NthPower (Power: Word);
procedure Transpose;
function Inverse: Boolean;
function Determinant: Float;
function Rang: Float;
property ColCount: Word read FCols;
property RowCount: Word read FRows;
property Cells (ACol, ARow: Word): Float read GetCell write SetCell; default;
property Items (NumItem: LongInt): Float read GetItem write SetItem;
end;
implementation
uses Windows;
function IncPtr (p: Pointer; i: LongInt): Pointer;
asm
push EBX
mov EBX,EAX
add EBX,EDX
mov EAX,EBX
pop EBX
end;
function TMatrix.GetCell (ACol, ARow: Word): Float;
var
CellPtr: ^Float;
begin
CellPtr := IncPtr(DataPtr, (FRows * Pred(ACol) + Pred(ARow)) * SizeOf(Float));
Result := CellPtr^;
end;
procedure TMatrix.SetCell (ACol, ARow: Word; AValue: Float);
var
CellPtr: ^Float;
begin
CellPtr := IncPtr(DataPtr, (FRows * Pred(ACol) + Pred(ARow)) * SizeOf(Float));
CellPtr^ := AValue;
end;
function TMatrix.GetItem (NumItem: LongInt): Float;
var
CellPtr: ^Float;
begin
CellPtr := IncPtr(DataPtr, Pred(NumItem) * SizeOf(Float));
Result := CellPtr^;
end;
procedure TMatrix.SetItem (NumItem: LongInt; AValue: Float);
var
CellPtr: ^Float;
begin
CellPtr := IncPtr(DataPtr, Pred(NumItem) * SizeOf(Float));
CellPtr^ := AValue;
end;
procedure TMatrix.SwitchRows (FirstRow, SecondRow: Word);
var
i: Word;
Buffer: Float;
begin
for i := 1 to FCols do
begin
Buffer := GetCell(i, FirstRow);
SetCell(i, FirstRow, GetCell(i, SecondRow));
SetCell(i, SecondRow, Buffer);
end;
end;
constructor TMatrix.Create (NCols, NRows: Word);
begin
inherited Create;
FCols := NCols;
FRows := NRows;
DataPtr := AllocMem(FCols * FRows * SizeOf(Float));
end;
destructor TMatrix.Destroy;
begin
FreeMem(DataPtr);
inherited Destroy;
end;
procedure TMatrix.Assign (AMatrix: TMatrix);
var
NewMatrixSize: LongInt;
begin
NewMatrixSize := AMatrix.ColCount * AMatrix.RowCount * SizeOf(Float);
ReAllocMem(DataPtr, NewMatrixSize);
CopyMemory(DataPtr, AMatrix.DataPtr, NewMatrixSize);
FCols := AMatrix.ColCount;
FRows := AMatrix.RowCount
end;
procedure TMatrix.ReSize (NewCols, NewRows: Word);
var
NewMatrixSize: LongInt;
begin
NewMatrixSize := NewCols * NewRows * SizeOf(Float);
ReAllocMem(DataPtr, NewMatrixSize);
FCols := NewCols;
FRows := NewRows;
end;
procedure TMatrix.SetNull;
begin
ZeroMemory (DataPtr, FCols * FRows * SizeOf(Float));
end;
procedure TMatrix.SetSingle;
var
i: Word;
begin
if FCols <> FRows then
Raise EMatrixOperatingError.Create ('Единичная матрица должна быть '+
'квадратной')
else
begin
SetNull;
for i := 1 to FCols do SetCell (i, i, 1);
end;
end;
procedure TMatrix.SetNegative;
var
i: LongInt;
begin
for i := 1 to FCols * FRows do SetItem(i, - GetItem(i));
end;
procedure TMatrix.AddConst (AConst: Float);
var
i: LongInt;
begin
for i := 1 to FCols * FRows do SetItem (i, GetItem(i) + AConst);
end;
procedure TMatrix.AddMatrix (AMatrix: TMatrix);
var
i: LongInt;
begin
for i := 1 to FCols * FRows do SetItem (i, GetItem(i) + AMatrix.Items (i));
end;
procedure TMatrix.MultConst (MConst: Float);
var
i: LongInt;
begin
for i := 1 to FCols * FRows do SetItem (i, GetItem(i) * MConst);
end;
procedure TMatrix.MultFromRight (MMatrix: TMatrix);
var
j, i, k: Word;
DummyRes: Float;
DummyMatrix: TMatrix;
begin
DummyMatrix := TMatrix.Create (MMatrix.ColCount, FRows);
if FCols <> MMatrix.RowCount then
Raise EMatrixOperatingError.Create ('Перемножаемые матрицы должны быть '+
'соответствующей размерности')
else
for i := 1 to FRows do
for j := 1 to MMatrix.ColCount do
begin
DummyRes := 0;
for k := 1 to FCols do
DummyRes := DummyRes + Cells(k, i) * MMatrix(j, k);
DummyMatrix(j, i) := DummyRes;
end;
Assign(DummyMatrix);
DummyMatrix.Free;
end;
procedure TMatrix.MultFromLeft (MMatrix: TMatrix);
var
j, i, k: Word;
DummyRes: Float;
DummyMatrix: TMatrix;
begin
DummyMatrix := TMatrix.Create (FCols, MMatrix.RowCount);
if MMatrix.ColCount <> FRows then
Raise EMatrixOperatingError.Create ('Перемножаемые матрицы должны быть '+
'соответствующей размерности')
else
for i := 1 to MMatrix.ColCount do
for j := 1 to FCols do
begin
DummyRes := 0;
for k := 1 to MMatrix.ColCount do
DummyRes := DummyRes + MMatrix(k, i) * Cells(j, k);
DummyMatrix(j, i) := DummyRes;
end;
Assign(DummyMatrix);
DummyMatrix.Free;
end;
procedure TMatrix.NthPower (Power: Word);
var
i: Word;
DummyMatrix: TMatrix;
begin
DummyMatrix := TMatrix.Create (FCols, FRows);
DummyMatrix.Assign (Self);
if FCols <> FRows then
Raise EMatrixOperatingError.Create ('Возводимая в степень матрица должна '+
'быть квадратной')
else
case Power of
0 : SetSingle;
1 : begin end;
else
for i := 2 to Power do MultFromRight (DummyMatrix);
end;
DummyMatrix.Free;
end;
procedure TMatrix.Transpose;
var
i, j: Word;
Dummy: Float;
begin
if FCols <> FRows then
Raise EMatrixOperatingError.Create ('Транспонируемая матрица должна быть '+
'квадратной')
else
for i := 1 to FCols do
for j := 1 to FRows do
if j > i then
begin
Dummy := GetCell(j, i);
SetCell(j, i, GetCell(i, j));
SetCell(i, j, Dummy);
end
end;
function TMatrix.Inverse: Boolean;
var
DummyMatrix: TMatrix;
Divisor, Multiplier: Float;
Row, RefRow, NewRow, Term: Word;
Singular: Boolean;
begin
Singular := False;
DummyMatrix := TMatrix.Create (FCols, FRows);
if (FCols <> FRows) or (FCols = 0) then
Raise EMatrixOperatingError.Create ('Инвертируемая матрица должна быть '+
'квадратной и ненулевого размера');
if FCols = 1 then
if ABS(GetItem(1)) < NearlyZero then Singular := True
else DummyMatrix.Items(1) := 1 / GetItem(1);
if FCols > 1 then
begin
DummyMatrix.SetSingle;
RefRow := 0;
repeat
Inc(RefRow);
if ABS(Cells(RefRow, RefRow)) < NearlyZero then
begin
Singular := TRUE;
NewRow := RefRow;
repeat
Inc(NewRow);
if ABS(Cells(RefRow, NewRow)) > NearlyZero then
begin
SwitchRows(NewRow, RefRow);
DummyMatrix.SwitchRows(NewRow, RefRow);
Singular := False;
end;
until (not Singular) or (NewRow >= FCols);
end;
if not Singular then
begin
Divisor := Cells(RefRow, RefRow);
for Term := 1 to FCols do
begin
SetCell(Term, RefRow, GetCell(Term, RefRow)/Divisor);
DummyMatrix(Term, RefRow) := DummyMatrix(Term, RefRow)/Divisor;
end;
for Row := 1 to FCols do
if (Row <> RefRow) and (ABS(Cells(RefRow, Row)) > NearlyZero) then
begin
Multiplier := - Cells(RefRow, Row) / Cells(RefRow, RefRow);
for Term := 1 to FCols do
begin
SetCell(Term, Row, GetCell(Term, Row) +
Multiplier * GetCell(Term, RefRow));
DummyMatrix(Term, Row) := DummyMatrix(Term, Row) +
Multiplier * DummyMatrix(Term, RefRow);
end
end;
end;
until Singular or (RefRow >= FCols);
end;
Assign(DummyMatrix);
DummyMatrix.Free;
if not Singular then Result := True
else Result := False;
end;
function TMatrix.Determinant: Float;
begin
Result := 0;
end;
function TMatrix.Rang: Float;
begin
Result := 0;
end;
end.
unit Operates;
interface
uses Matrix, Grids, SysUtils;
const
MaxArraySize = 30;
type
Float = Extended;
TOrder = 1..MaxArraySize;
ESingularMatrix = class (Exception);
type
TComplex = record
Re, Im : Float;
end;
TComplexVector = record
Data : array (1..MaxArraySize) of TComplex;
Dim : TOrder;
end;
function SymmetricalFunction (Roots: TComplexVector; K: byte): Float;
procedure DiffSystemSolve (matrixA,
matrixB: TMatrix;
LowerLimit,
UpperLimit: Float;
InitialValues: TMatrix;
NumReturn,
NumIntervals: Word;
SolutionValues: TMatrix);
implementation
function SymmetricalFunction (Roots: TComplexVector; K: byte): Float;
var
Z: TComplex;
function SummComplex (FirstNC, SecondNC: TComplex): TComplex;
begin
Result.Re := FirstNC.Re + SecondNC.Re;
Result.Im := FirstNC.Im + SecondNC.Im;
end;
function MultComplex (FirstNC, SecondNC: TComplex): TComplex;
begin
Result.Re := FirstNC.Re * SecondNC.Re - FirstNC.Im * SecondNC.Im;
Result.Im := FirstNC.Re * SecondNC.Im + FirstNC.Im * SecondNC.Re;
end;
function DivComplex (FirstNC, SecondNC: TComplex): TComplex;
var
Z: Float;
begin
Z := Sqr(SecondNC.Re) + Sqr(SecondNC.Im);
Result.Re := (FirstNC.Re * SecondNC.Re + FirstNC.Im * SecondNC.Im) / Z;
Result.Im := (FirstNC.Im * SecondNC.Re - FirstNC.Re * SecondNC.Im) / Z;
end;
function CombinationSumm (LowLimit, HighLimit, K: byte): TComplex;
var i: byte;
begin
Result.Re := 0;
Result.Im := 0;
if LowLimit = HighLimit then Result := Roots.Data(LowLimit)
else
for i := LowLimit to HighLimit - K + 1 do
if K = 1 then Result := SummComplex(Result, Roots.Data (i))
else Result := SummComplex(Result,
MultComplex(Roots.Data (i),
CombinationSumm(i + 1,
HighLimit, K-1)));
end;
begin
Z := CombinationSumm(1, Roots.Dim, K);
Result := Z.Re;
end;
procedure DiffSystemSolve (matrixA, matrixB: TMatrix;
LowerLimit, UpperLimit: Float;
InitialValues: TMatrix;
NumReturn, NumIntervals: Word;
SolutionValues: TMatrix);
type
Ptr = ^Data;
Data = record
Values: TMatrix;
Next: Ptr;
end;
var
ValuesStack: Ptr;
Spacing, HalfSpacing: Float;
Index, Term: Word;
F1, F2, F3, F4,
CurrentValues,
TempValues: TMatrix;
NumEquations, NumTimeCol: Word;
function TargetALL (matrixA, mayrixB: TMatrix; Values: TMatrix; KRow: Word): Float;
var
j: Word;
begin
try
Result := matrixB.Items(KRow);
for j := 1 to NumEquations do
Result := Result + matrixA(j, KRow) * Values.Items(j);
except
on EO: EOverflow do EO.Message := 'Не буду считать !!!'#10 +
'С уменьшите разброс коэффициентов в матрице А'#10 +
'либо измените опции (уменьшите их pls.)';
end;
end;
procedure Push (var ValuesStack: Ptr;
CurrentValues: TMatrix);
var
NewNode : Ptr;
begin
New(NewNode);
NewNode^.Values := TMatrix.Create(NumTimeCol, 1);
NewNode^.Values.Assign(CurrentValues);
NewNode^.Next := ValuesStack;
ValuesStack := NewNode;
end; { procedure Push }
procedure Pop (var ValuesStack: Ptr;
CurrentValues: TMatrix);
var
OldNode : Ptr;
begin
OldNode := ValuesStack;
ValuesStack := OldNode^.Next;
CurrentValues.Assign(OldNode^.Values);
OldNode^.Values.Free;
Dispose(OldNode);
end; { procedure Pop }
procedure GetValues(NumReturn, NumIntervals: Word; var ValuesStack: Ptr;
SolutionValues: TMatrix);
var
Index, Term: Integer;
j: Word;
CurrValues: TMatrix;
begin
SolutionValues.ReSize(NumTimeCol, Succ(NumReturn));
CurrValues := TMatrix.Create(NumTimeCol, 1);
Term := NumIntervals;
for Index := NumReturn downto 0 do
begin
Pop(ValuesStack, CurrValues);
Dec(Term);
while (Term / NumIntervals >= Index / NumReturn) and (Term >= 0) do
begin
Pop(ValuesStack, CurrValues);
Dec(Term);
end;
for j := 1 to NumTimeCol do
SolutionValues(j, Succ(Index)) := CurrValues.Items(j);
end;
CurrValues.Free;
end; { procedure GetValues }
procedure Step(Spacing: Float; CurrentValues: TMatrix; F: TMatrix);
var
i : byte;
begin
for i := 1 to NumEquations do
F.Items(i) := Spacing * TargetALL (matrixA, matrixB, CurrentValues, i);
end; { procedure Step }
begin
NumEquations := matrixA.RowCount;
NumTimeCol := Succ(NumEquations);
ValuesStack := nil;
Spacing := (UpperLimit - LowerLimit) / NumIntervals;
CurrentValues := TMatrix.Create(1, 1);
CurrentValues.Assign(InitialValues);
CurrentValues.ReSize(NumTimeCol, 1);
CurrentValues.Items(NumTimeCol) := LowerLimit;
TempValues := TMatrix.Create(NumTimeCol, 1);
F1 := TMatrix.Create(NumTimeCol, 1);
F2 := TMatrix.Create(NumTimeCol, 1);
F3 := TMatrix.Create(NumTimeCol, 1);
F4 := TMatrix.Create(NumTimeCol, 1);
Push(ValuesStack, CurrentValues);
HalfSpacing := Spacing / 2;
for Index := 1 to NumIntervals do
begin
{ First step - calculate F1 }
Step(Spacing, CurrentValues, F1);
TempValues.Items(NumTimeCol) := CurrentValues.Items(NumTimeCol) + HalfSpacing;
for Term := 1 to NumEquations do
TempValues.Items(Term) := CurrentValues.Items(Term) + 0.5 * F1.Items(Term);
{ 2nd step - calculate F2 }
Step(Spacing, TempValues, F2);
for Term := 1 to NumEquations do
TempValues.Items(Term) := CurrentValues.Items(Term) + 0.5 * F2.Items(Term);
{ Third step - calculate F3 }
Step(Spacing, TempValues, F3);
TempValues.Items(NumTimeCol) := CurrentValues.Items(NumTimeCol) + Spacing;
for Term := 1 to NumEquations do
TempValues.Items(Term) := CurrentValues.Items(Term) + F3.Items(Term);
{ Fourth step - calculate F4(1); first equation }
Step(Spacing, TempValues, F4);
{ Combine F1, F2, F3, and F4 to get }
{ the solution at this mesh point }
CurrentValues.Items(NumTimeCol) := CurrentValues.Items(NumTimeCol) + Spacing;
for Term := 1 to NumEquations do
CurrentValues.Items(Term) := CurrentValues.Items(Term) +
(F1.Items(Term) + 2 * F2.Items(Term) +
2 * F3.Items(Term) + F4.Items(Term)) /6;
Push(ValuesStack, CurrentValues);
end;
GetValues(NumReturn, NumIntervals, ValuesStack, SolutionValues);
F1.Free;
F2.Free;
F3.Free;
F4.Free;
CurrentValues.Free;
TempValues.Free;
end;
end.
unit HelpUnit;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls, Buttons;
type
TForm_Help = class(TForm)
BitBtn1: TBitBtn;
Bevel1: TBevel;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
Label5: TLabel;
Label6: TLabel;
Label7: TLabel;
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form_Help: TForm_Help;
implementation
{$R *.DFM}
end.
unit OptsUnit;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, Spin, Buttons, ExtCtrls;
type
TForm_Options = class(TForm)
CheckBox_Link: TCheckBox;
SpinEdit1: TSpinEdit;
SpinEdit2: TSpinEdit;
SpinEdit3: TSpinEdit;
Label_UpLimit: TLabel;
Label_PointsNumber: TLabel;
Label_Intervals: TLabel;
Label_1: TLabel;
BitBtn_Ok: TBitBtn;
BitBtn_Cancel: TBitBtn;
SpinEdit0: TSpinEdit;
Label1: TLabel;
Bevel1: TBevel;
procedure SpinEdit0Change(Sender: TObject);
procedure SpinEdit2Change(Sender: TObject);
procedure CheckBox_LinkClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form_Options: TForm_Options;
implementation
uses MainUnit, SubUnit;
{$R *.DFM}
procedure TForm_Options.SpinEdit0Change(Sender: TObject);
begin
SpinEdit1.MinValue := Succ(SpinEdit0.Value);
if SpinEdit1.Value < SpinEdit1.MinValue then SpinEdit1.Value:= SpinEdit1.MinValue;
end;
procedure TForm_Options.SpinEdit2Change(Sender: TObject);
begin
SpinEdit3.MinValue := SpinEdit2.Value;
if SpinEdit3.Value < SpinEdit3.MinValue then SpinEdit3.Value:= SpinEdit3.MinValue;
end;
procedure TForm_Options.CheckBox_LinkClick(Sender: TObject);
begin
if CheckBox_Link.State = cbChecked then Form_Main.BindGrids
else Form_Main.UnBindGrids
end;
end.