unit PFilter;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls;

type
  TFormPFilter = class(TForm)
    Panel1: TPanel;
    Image1: TImage;
    Label1: TLabel;
    Panel2: TPanel;
    Panel3: TPanel;
    EditB1: TEdit;
    Lbb1: TLabel;
    EditB2: TEdit;
    Lbb2: TLabel;
    EditB3: TEdit;
    Lbb3: TLabel;
    Lbb4: TLabel;
    EditB4: TEdit;
    Lbb5: TLabel;
    EditB5: TEdit;
    Lbb6: TLabel;
    EditB6: TEdit;
    Lbb7: TLabel;
    EditB7: TEdit;
    Lbb8: TLabel;
    EditB8: TEdit;
    EditA1: TEdit;
    EditA2: TEdit;
    EditA3: TEdit;
    EditA4: TEdit;
    EditA5: TEdit;
    EditA6: TEdit;
    EditA7: TEdit;
    EditA8: TEdit;
    Lba1: TLabel;
    Lba2: TLabel;
    Lba3: TLabel;
    Lba4: TLabel;
    Lba5: TLabel;
    Lba6: TLabel;
    Lba7: TLabel;
    Lba8: TLabel;
    EditB0: TEdit;
    CbBoxInitB: TComboBox;
    CbBoxInitA: TComboBox;
    BttOK: TButton;
    BttCancel: TButton;
    Label2: TLabel;
    Lbb0: TLabel;
    Label3: TLabel;
    Label4: TLabel;
    Label5: TLabel;
    Label6: TLabel;
    EditM: TEdit;
    Button2: TButton;
    Label7: TLabel;
    Label8: TLabel;
    Label9: TLabel;
    Label10: TLabel;
    Label11: TLabel;
    procedure BttCancelClick(Sender: TObject);
    procedure BttOKClick(Sender: TObject);
    procedure EditChange(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure CbBoxInitBClick(Sender: TObject);
    procedure CbBoxInitAClick(Sender: TObject);
    procedure FormActivate(Sender: TObject);
  private
    { Private declarations }
    // Отобразить текущие коэффициенты
    procedure ShowAllKoeff();
    // Сформировать коэффициенты B
    procedure InitKoeffB(RqB0 : double);
    // Сформировать коэффициенты A
    procedure InitKoeffA();
    // Вычислить масштаб фильтра
    procedure CalcScale();
  public
    { Public declarations }
    // Инициировать рабочие коэффициенты по умолчанию
    procedure InitFilterKoeff();
    // Очистить отсчеты цифрового фильтра
    procedure ClearFilter();
    // ОДИН ТАКТ ЦИФРОВОГО ФИЛЬТРА
    function RunFilter(RqX : double) : double;
  end;

const MaxOrder = 8; // Максимальный порядок фильтра
type TFLT  = record
     BI    : array [0..MaxOrder] of double;
     BIS   : array [0..MaxOrder] of double;
     X     : array [0..MaxOrder] of double;
     AI    : array [0..MaxOrder] of double;
     AIS   : array [0..MaxOrder] of double;
     Y     : array [0..MaxOrder] of double;
     YOut  : double;
end;

var
  FormPFilter : TFormPFilter;
  FLT1        : TFLT;

implementation

{$R *.dfm}
// -------------------------------------------------------------------
// РЕДАКТИРОВАНИЕ КОЭФФИЦИЕНТОВ ФИЛЬТРА
// Преобразование Edit.Text в цифру
function EditTextToFloat (var RqData : double; RqEdit : TEdit) : boolean;
var BufData  : double;
begin
  Result := False;     // Песимистический прогноз операции
  if (Length(RqEdit.Text) = 1) and (RqEdit.Text = '-')
  then begin
       RqData := 0;
       Result := True;    // Операция завершилась успешно
  end
  else begin
    try
       BufData := StrToFloat(RqEdit.Text);
       RqEdit.Color := clWindow;
       RqData := BufData;
       Result := True;    // Операция завершилась успешно
    except
       RqEdit.Color := TColor($00A0A0FF);
       ShowMessage('НЕ МОГУ ПРЕОБРАЗОВАТЬ В ЦИФРУ');
    end;
  end;
end;
// Редактирование буферных значений коэффициентов фильтра
procedure TFormPFilter.EditChange(Sender: TObject);
begin
   if not (Sender is TEdit) then Exit;
   with FLT1 do
   begin
      case (Sender as TEdit).Tag of
      // Редактирование коэффициентов B
      10  : EditTextToFloat (BI[0],(Sender as TEdit));
      11  : EditTextToFloat (BI[1],(Sender as TEdit));
      12  : EditTextToFloat (BI[2],(Sender as TEdit));
      13  : EditTextToFloat (BI[3],(Sender as TEdit));
      14  : EditTextToFloat (BI[4],(Sender as TEdit));
      15  : EditTextToFloat (BI[5],(Sender as TEdit));
      16  : EditTextToFloat (BI[6],(Sender as TEdit));
      17  : EditTextToFloat (BI[7],(Sender as TEdit));
      18  : EditTextToFloat (BI[8],(Sender as TEdit));
      // Редактирование коэффициентов A
      20  : EditTextToFloat (AI[0],(Sender as TEdit));  // Масштаб
      21  : EditTextToFloat (AI[1],(Sender as TEdit));
      22  : EditTextToFloat (AI[2],(Sender as TEdit));
      23  : EditTextToFloat (AI[3],(Sender as TEdit));
      24  : EditTextToFloat (AI[4],(Sender as TEdit));
      25  : EditTextToFloat (AI[5],(Sender as TEdit));
      26  : EditTextToFloat (AI[6],(Sender as TEdit));
      27  : EditTextToFloat (AI[7],(Sender as TEdit));
      28  : EditTextToFloat (AI[8],(Sender as TEdit));
      end;
   end;
end;
// Отобразить текущие коэффициенты
procedure TFormPFilter.ShowAllKoeff();
begin
  with FLT1 do
  begin
     // Отображение коэффициентов В
     EditB0.Text := FloatToStr(BI[0]);
     EditB1.Text := FloatToStr(BI[1]);
     EditB2.Text := FloatToStr(BI[2]);
     EditB3.Text := FloatToStr(BI[3]);
     EditB4.Text := FloatToStr(BI[4]);
     EditB5.Text := FloatToStr(BI[5]);
     EditB6.Text := FloatToStr(BI[6]);
     EditB7.Text := FloatToStr(BI[7]);
     EditB8.Text := FloatToStr(BI[8]);
     // Отображение коэффициентов А
     EditM.Text  := FloatToStr(AI[0]);  // Масштаб
     EditA1.Text := FloatToStr(AI[1]);
     EditA2.Text := FloatToStr(AI[2]);
     EditA3.Text := FloatToStr(AI[3]);
     EditA4.Text := FloatToStr(AI[4]);
     EditA5.Text := FloatToStr(AI[5]);
     EditA6.Text := FloatToStr(AI[6]);
     EditA7.Text := FloatToStr(AI[7]);
     EditA8.Text := FloatToStr(AI[8]);
  end;
end;

// Вычислить масштаб фильтра
procedure TFormPFilter.CalcScale();
var Ind     : integer;
    SS1     : double;
begin
  with FLT1 do
  begin
     SS1 := 0;
     for Ind := Low(BI)     to High(BI) do SS1 := SS1 + BI[Ind];
     for Ind := Low(AI) + 1 to High(AI) do SS1 := SS1 + AI[Ind];
     if Abs(SS1) > 0 then AIS[Low(AI)]:= (1 / SS1) else AIS[Low(AI)]:= 0;
     EditM.Text  := FloatToStr(AIS[Low(AI)]);
  end;
end;

// Сформировать коэффициенты А
procedure TFormPFilter.InitKoeffA();
var Ind  : integer;
begin
  with FLT1 do
  begin
    case CbBoxInitA.ItemIndex of
    0: for Ind := Low(AI)+1 to High(AI)
       do begin
          AI[Ind]:= exp(-(Ind-1));
          AIS[Ind]:= AI[Ind];
       end;
    1: for Ind := Low(AI)+1 to High(AI)
       do begin
         AI[Ind]:= cos((Pi/2)*(Ind-1)/(High(AI)+1));
         AIS[Ind]:= AI[Ind];
       end;
    end;
  end;
end;
// Сформировать коэффициенты B
procedure TFormPFilter.InitKoeffB(RqB0 : double);
var Ind  : integer;
begin
  with FLT1 do
  begin
    case CbBoxInitB.ItemIndex of
    0: for Ind := Low(BI) to High(BI)
       do begin
          BI[Ind]:= RqB0 * exp(-Ind);
          BIS[Ind]:= BI[Ind];
       end;
    1: for Ind := Low(BI) to High(BI)
       do begin
          BI[Ind]:= RqB0 * cos((Pi/2)*Ind/(High(BI)+1));
          BIS[Ind]:= BI[Ind];
       end;
    end;
  end;
end;
// Переустановка коэффициентов В
procedure TFormPFilter.CbBoxInitBClick(Sender: TObject);
begin
  InitKoeffB(FLT1.BI[0]);
  CalcScale();     // Вычислить масштаб фильтра
  ShowAllKoeff();  // Отобразить текущие коэффициенты
end;
// Переустановка коэффициентов A
procedure TFormPFilter.CbBoxInitAClick(Sender: TObject);
begin
  InitKoeffA();
  CalcScale();     // Вычислить масштаб фильтра
  ShowAllKoeff();  // Отобразить текущие коэффициенты
end;
// Вычислить масштаб фильтра
procedure TFormPFilter.Button2Click(Sender: TObject);
begin
  CalcScale();
end;


// Очистить отсчеты цифрового фильтра
procedure TFormPFilter.ClearFilter();
var Ind : integer;
begin
  with FLT1 do
  begin
    for Ind := Low(X) to High(X) do X[Ind]:= 0;
    for Ind := Low(Y) to High(Y) do Y[Ind]:= 0;
    YOut := 0;
  end;
end;
// -------------------------------------------------------------------
// ОДИН ТАКТ ЦИФРОВОГО ФИЛЬТРА
function TFormPFilter.RunFilter(RqX : double) : double;
var Ind    : integer;
    SumBX  : double;
    SumAY  : double;
begin
  SumBX := 0;
  SumAY := 0;
  with FLT1 do
  begin
     for Ind := High(X) downto Low(X)-1 do  X[Ind]:= X[Ind -1];
     X[Low(X)] := RqX;
     for Ind := Low(BI)   to High(BI) do SumBX := SumBX + BI[Ind]*X[Ind];

     for Ind := Low(AI)+1 to High(AI) do SumAY := SumAY + AI[Ind]*Y[Ind];
     for Ind := High(Y) downto Low(Y)-1 do  Y[Ind]:= Y[Ind -1];
     Y[Low(Y)] := (SumBX + SumAY)* AI[Low(AI)];
     YOut := Y[Low(Y)];
     Result := YOut;
  end;
end;
// -------------------------------------------------------------------
// Сохранить все коэффициенты в буферные массивы
procedure SaveKoeff();
var Ind : integer;
begin
  with FLT1 do
  begin
    for Ind := Low(BI) to High(BI) do BIS[Ind]:= BI[Ind];
    for Ind := Low(AI) to High(AI) do AIS[Ind]:= AI[Ind];
  end;
end;
// Восстановить все коэффициенты из буферных массивов
procedure RestoreKoeff();
var Ind : integer;
begin
  with FLT1 do
  begin
    for Ind := Low(BI) to High(BI) do  BI[Ind]:= BIS[Ind];
    for Ind := Low(AI) to High(AI) do  AI[Ind]:= AIS[Ind];
  end;
end;

// Инициировать коэффициенты при создании формы
procedure TFormPFilter.InitFilterKoeff();
const DefB0 = 0.05;
begin
   FLT1.BI[0] :=DefB0;
   CbBoxInitB.ItemIndex := 1;
   InitKoeffB(FLT1.BI[0]);
   CbBoxInitA.ItemIndex := 1;
   InitKoeffA();
   CalcScale();     // Вычислить масштаб фильтра
   SaveKoeff();     // Сохранить все коэффициенты в буферные массивы
   ShowAllKoeff();  // Отобразить текущие коэффициенты
end;
// Начальные установки
procedure TFormPFilter.FormCreate(Sender: TObject);
begin
  InitFilterKoeff();
end;
// При активации формы сохранить текущие коэффициенты
procedure TFormPFilter.FormActivate(Sender: TObject);
begin
  SaveKoeff();     // Сохранить все коэффициенты в буферные массивы
  ShowAllKoeff();  // Отобразить текущие коэффициенты
end;
// Выход по Cancel
procedure TFormPFilter.BttCancelClick(Sender: TObject);
begin
  RestoreKoeff(); // Восстановить все коэффициенты из буферных массивов
  Close;
end;
// Выход по ОК
procedure TFormPFilter.BttOKClick(Sender: TObject);
begin
  Close;
end;



end.
