unit MAIN;

// Демонстрирует алгоритм работы Sigma-Delta модулятора,
// а также алгоритм Sigma-Delta DAC (ЦАП) первого порядка.

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, Buttons, Math,
  PFilter, DDisplayTools, DDisplayGUI, DDisplayQE;

type
  TForm1 = class(TForm)
    Timer1: TTimer;
    Panel2: TPanel;
    ColorDialog1: TColorDialog;
    Panel4: TPanel;
    Panel1: TPanel;
    Label1: TLabel;
    Label6: TLabel;
    Label7: TLabel;
    Label8: TLabel;
    CBox1EnCapt: TCheckBox;
    Ed1DisplayLV: TEdit;
    CBox1EnCurrY: TCheckBox;
    CbBox1Sens: TComboBox;
    STxt1GridColor: TStaticText;
    STxt1BeamColor: TStaticText;
    STxt1DisplayColor: TStaticText;
    Panel3: TPanel;
    Image1: TImage;
    Panel5: TPanel;
    Panel6: TPanel;
    Label9: TLabel;
    Label11: TLabel;
    Label12: TLabel;
    Label13: TLabel;
    CBox2EnCapt: TCheckBox;
    Ed2DisplayLV: TEdit;
    CBox2EnCurrY: TCheckBox;
    CbBox2Sens: TComboBox;
    STxt2GridColor: TStaticText;
    STxt2BeamColor: TStaticText;
    STxt2DisplayColor: TStaticText;
    Panel7: TPanel;
    Image2: TImage;
    Panel8: TPanel;
    EdMera: TEdit;
    EdSignal: TEdit;
    Label2: TLabel;
    Label14: TLabel;
    BttReset: TButton;
    Panel9: TPanel;
    SBttStart: TSpeedButton;
    SBttStop: TSpeedButton;
    STxtBalans: TStaticText;
    Label3: TLabel;
    CbBoxInDisplay1: TComboBox;
    Label4: TLabel;
    Label15: TLabel;
    STxtOutDAC: TStaticText;
    CbBoxDisplay1Style: TComboBox;
    Label16: TLabel;
    CBox1Alert: TCheckBox;
    CBox2Alert: TCheckBox;
    Label5: TLabel;
    CbBoxDisplay2Style: TComboBox;
    BttResetAll: TButton;
    Label10: TLabel;
    CBoxTemp: TComboBox;
    Label17: TLabel;
    Label18: TLabel;
    Label19: TLabel;
    CBoxMaxStep: TComboBox;
    Label20: TLabel;
    CbBoxLPF: TComboBox;
    StxtImpP: TStaticText;
    Label21: TLabel;
    Label22: TLabel;
    StxtNumN: TStaticText;
    Label23: TLabel;
    STxtNumP: TStaticText;
    Label24: TLabel;
    Label25: TLabel;
    StxtPsubN: TStaticText;
    StxtNumSteps: TStaticText;
    Label26: TLabel;
    StxtOutSDLPF: TStaticText;
    Label27: TLabel;
    Label28: TLabel;
    Label29: TLabel;
    BitBtnParmFltR: TBitBtn;
    // -----------------------------------------
    // Обработчики событий сформированные Delphi
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure SBttStartClick(Sender: TObject);
    procedure SBttStopClick(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure CBox1EnCurrYClick(Sender: TObject);
    procedure CbBox1SensClick(Sender: TObject);
    procedure STxt1GridColorClick(Sender: TObject);
    procedure STxt1BeamColorClick(Sender: TObject);
    procedure STxt1DisplayColorClick(Sender: TObject);
    procedure CBox1EnCaptClick(Sender: TObject);
    procedure EdMeraChange(Sender: TObject);
    procedure EdSignalChange(Sender: TObject);
    procedure BttResetClick(Sender: TObject);
    procedure CBox1AlertClick(Sender: TObject);
    procedure STxt2DisplayColorClick(Sender: TObject);
    procedure STxt2BeamColorClick(Sender: TObject);
    procedure STxt2GridColorClick(Sender: TObject);
    procedure CBox2EnCaptClick(Sender: TObject);
    procedure CBox2EnCurrYClick(Sender: TObject);
    procedure CBox2AlertClick(Sender: TObject);
    procedure CbBox2SensClick(Sender: TObject);
    procedure BttResetAllClick(Sender: TObject);
    procedure CBoxTempClick(Sender: TObject);
    procedure CBoxMaxStepClick(Sender: TObject);
    procedure CbBoxLPFClick(Sender: TObject);
    procedure BitBtnParmFltRClick(Sender: TObject);
  private
    // -----------------------------------------
    // Обработчики событий для осциллографа № 1
    procedure DDisplay1OnItemDraw  (Sender : TObject; X, Y : integer;
                                    Item   : TQItem);
    procedure DDisplay1OnAlertItem (Sender : TObject; X, Y : integer;
                                    Item : TQItem);
    // -----------------------------------------
    // Обработчики событий длч осциллографа № 2
    procedure DDisplay2OnItemDraw  (Sender : TObject; X, Y : integer;
                                    Item   : TQItem);
    procedure DDisplay2OnAlertItem (Sender : TObject; X, Y : integer;
                                    Item : TQItem);
  public
    { Public declarations }
    // Инициализация DAC и ADC
    procedure InitDacAdc();
    // Сброс SD-модулятора и SD-ЦАП
    procedure ClearDacAdc();
    // ОСЦИЛЛОГРАФ 1 (Добавить выбранную точку и отобразить осциллограмму)
    procedure AddPointToOscillograph1(RqOutDAC : double);
    // ОСЦИЛЛОГРАФ 2 (Добавить выход ЦАП и отобразить осциллограмму)
    procedure AddPointToOscillograph2(RqOutDAC : double);
  end;

// ===========================================================
var  Form1: TForm1;
// ===========================================================
implementation

{$R *.dfm}
// ===========================================================
//  ОБЪЕКТНЫЕ ПЕРЕМЕННЫЕ ДИСПЛЕЕВ
const MaxDisplayPoint = 40;
var DDisplay1  : TDDisplay;  // Ссылка на объект осциллографа 1  (АЦП)
var DDisplay2  : TDDisplay;  // Ссылка на объект осциллографа 2  (ЦАП)
// ===========================================================
const DefMera   = 10;        // Значение меры по умолчанию
      DefSignal = 4;         // Значение сигнала по умолчанию

var // ОСНОВНЫЕ ПЕРЕМЕННЫЕ SD-МОДУЛЯТОРА
    Mera   : double;         // Текущее значение меры
    Signal : double;         // Текущее значение сигнала
    Balans : double;         // Баланс сигма-дельта алгоритма
    PNum   : integer;        // Счетчик положительных отклонений баланса
    NNum   : integer;        // Счетчик отрицательных отклонений баланса
    PMod   : boolean;        // Логический P-выход модулятора
    // ОСНОВНЫЕ ПЕРЕМЕННЫЕ SD-ЦАП
    SDLpfOut : double;       // Выход SIGMA-DELTA ФНЧ
    // Дополнительная цифровая фильтрация
    RqLPF    : integer;       // Вид дополнительной фильтрации
    LPF2Out  : double;        // Выход заказного ФНЧ
    LPF3Buf  : double;        // Буфер усредняющего ФНЧ
    LPF3Out  : double;        // Выход усредняющего ФНЧ
// ВСПОМОГАТЕЛЬНЫЕ ПЕРЕМЕННЫЕ SD-АЛГОРИТМА
const SBalansMin = 0.0001;   // Уровень баланса для остановки по Balans = 0
var OutDAC  : double;        // Добавляемое значение в осциллограф № 2
    RunFlag : boolean;       // Флаг - Пуск / Стоп
    MaxStep : integer;       // Максимальное число шагов до остановки
// ===========================================================
//  РЕАЛИЗАЦИЯ
// ===========================================================
// -----------------------------------------------------------
// Инициализация DAC и ADC
procedure TForm1.InitDacAdc();
begin
   // -------------------
   RunFlag := False;          // Процесс остановлен
   CBoxMaxStepClick(nil);     // Установить число шагов до остановки
   // Выполнить полный сброс
   BttResetAllClick(nil);
end;
// -----------------------------------------------------------
// Инициализация ФОРМЫ
procedure TForm1.FormCreate(Sender: TObject);
begin
   // -------------------
   // Установки SD-алгоритма по умолчанию
   Mera    := DefMera;
   EdMera.Text := FloatToStr(Mera);
   Signal  := DefSignal;
   EdSignal.Text := FloatToStr(Signal);
   // ----------------------------
   // Инициализация осциллографа 1
   DDisplayGreate(DDisplay1, Image1);
   if Assigned(DDisplay1)
   then begin
      DDisplay1.DMaxCount := MaxDisplayPoint;
      // Присоединение обработчика события -  прорисовано последнее значение
      OnOffDDisplayItemDraw(DDisplay1, False,  DDisplay1OnItemDraw);
      // Присоединение обработчика события - последнее значение выше порога
      OnOffDDisplayAlertItem(DDisplay1, True, DDisplay1OnAlertItem);
      // Начальная установка чувствительности
      CbBox1SensClick(nil);
      DDisplay1.EnCapt := CBox1EnCapt.Checked;
   end;
   // ----------------------------
   // Инициализация осциллографа 2
   DDisplayGreate(DDisplay2, Image2);
   if Assigned(DDisplay2)
   then begin
      DDisplay2.DMaxCount := MaxDisplayPoint;
      // Присоединение обработчика события -  прорисовано последнее значение
      OnOffDDisplayItemDraw(DDisplay2, False,  DDisplay2OnItemDraw);
      // Присоединение обработчика события - последнее значение выше порога
      OnOffDDisplayAlertItem(DDisplay2, True, DDisplay2OnAlertItem);
      CbBox2SensClick(nil);
      DDisplay2.EnCapt   := CBox2EnCapt.Checked;
      DDisplay2.MdAlert  := Abs(Signal);
      CBox2Alert.Checked := False;
   end;
   // ----------------------------
   // Инициализация DAC и ADC
   InitDacAdc();
end;
// -----------------------------------------------------------
// Освободить ресурсы при завершении
procedure TForm1.FormDestroy(Sender: TObject);
begin
  RunFlag := False;
  DDisplayDestroy(DDisplay1);
  DDisplayDestroy(DDisplay2);
end;

// -----------------------------------------------------------
// УПРАВЛЕНИЕ АТРИБУТАМИ ОСЦИЛЛОГРАФА 1
// -----------------------------------------------------------
// Обработчик события - прорисовка текущего значения
procedure TForm1.DDisplay1OnItemDraw (Sender : TObject;
     X, Y : integer; Item : TQItem);
begin
  Ed1DisplayLV.Text := FormatFloat('#0.000000', Item.RData);
end;
// Обработчик события - сигнал выше порога
procedure TForm1.DDisplay1OnAlertItem (Sender : TObject;
     X, Y : integer; Item : TQItem);
begin
  // Выдать ноту ЛЯ (440 hz) на динамик компьютера
  // параметры : частота (hz), продолжительность (ms)
  if CBox1Alert.Checked then Windows.Beep(440,10);
end;
// Установка цвета луча
procedure TForm1.STxt1BeamColorClick(Sender: TObject);
begin
  SetDDisplayColor(DDisplay1, ColorDialog1, 1);
  ShowCororIndicators(DDisplay1,
                      STxt1BeamColor, STxt1DisplayColor, STxt1GridColor);
end;
// Установка цвета дисплея
procedure TForm1.STxt1DisplayColorClick(Sender: TObject);
begin
  SetDDisplayColor(DDisplay1, ColorDialog1, 2);
  ShowCororIndicators(DDisplay1,
                      STxt1BeamColor, STxt1DisplayColor, STxt1GridColor);
end;
// Установка цвета линий сетки
procedure TForm1.STxt1GridColorClick(Sender: TObject);
begin
  SetDDisplayColor(DDisplay1, ColorDialog1, 3);
  ShowCororIndicators(DDisplay1,
                      STxt1BeamColor, STxt1DisplayColor, STxt1GridColor);
end;
// Включение / отключение подписей на осциллограмме
procedure TForm1.CBox1EnCaptClick(Sender: TObject);
begin
   if Assigned(DDisplay1)then DDisplay1.EnCapt := CBox1EnCapt.Checked;
end;
// Включение / отключение вывода текущх значений в поле TEdit
procedure TForm1.CBox1EnCurrYClick(Sender: TObject);
begin
 OnOffDDisplayItemDraw (DDisplay1, CBox1EnCurrY.Checked, DDisplay1OnItemDraw);
end;
// Установка порога Alert по амплитуде сигнала
procedure TForm1.CBox1AlertClick(Sender: TObject);
begin
  if Assigned(DDisplay1)
  then begin
    if CBox1Alert.Checked
    then DDisplay1.MdAlert := Abs(2*Mera)
    else DDisplay1.MdAlert := -1;
  end;
end;
// Установка чувствительности (единицы на шаг сетки)
procedure TForm1.CbBox1SensClick(Sender: TObject);
begin
  if Assigned(DDisplay1)
  then begin
     case CbBox1Sens.ItemIndex of
     0 : DDisplay1.Sens := 1;
     1 : DDisplay1.Sens := 5;
     2 : DDisplay1.Sens := 10;
     3 : DDisplay1.Sens := 50;
     end;
  end;
end;
// -----------------------------------------------------------
// УПРАВЛЕНИЕ АТРИБУТАМИ ОСЦИЛЛОГРАФА 2
// -----------------------------------------------------------
// Обработчик события - прорисовка текущего значения
procedure TForm1.DDisplay2OnItemDraw (Sender : TObject;
     X, Y : integer; Item : TQItem);
begin
  Ed2DisplayLV.Text := FormatFloat('#0.000000', Item.RData);
end;
// Обработчик события - сигнал выше порога
procedure TForm1.DDisplay2OnAlertItem (Sender : TObject;
     X, Y : integer; Item : TQItem);
begin
  // Выдать ноту ЛЯ (440 hz) на динамик компьютера
  // параметры : частота (hz), продолжительность (ms)
  if CBox2Alert.Checked then Windows.Beep(440,10);
end;

// Установка цвета луча
procedure TForm1.STxt2BeamColorClick(Sender: TObject);
begin
  SetDDisplayColor(DDisplay2, ColorDialog1, 1);
  ShowCororIndicators(DDisplay2,
                      STxt2BeamColor, STxt2DisplayColor, STxt2GridColor);
end;
// Установка цвета дисплея
procedure TForm1.STxt2DisplayColorClick(Sender: TObject);
begin
  SetDDisplayColor(DDisplay2, ColorDialog1, 2);
  ShowCororIndicators(DDisplay1,
                      STxt2BeamColor, STxt2DisplayColor, STxt2GridColor);
end;
// Установка цвета линий сетки
procedure TForm1.STxt2GridColorClick(Sender: TObject);
begin
  SetDDisplayColor(DDisplay2, ColorDialog1, 3);
  ShowCororIndicators(DDisplay1,
                      STxt2BeamColor, STxt2DisplayColor, STxt2GridColor);
end;
// Включение / отключение подписей на осциллограмме
procedure TForm1.CBox2EnCaptClick(Sender: TObject);
begin
  if Assigned(DDisplay2)then DDisplay2.EnCapt := CBox2EnCapt.Checked;
end;
// Включение / отключение вывода текущх значений в поле TEdit
procedure TForm1.CBox2EnCurrYClick(Sender: TObject);
begin
  OnOffDDisplayItemDraw (DDisplay2, CBox2EnCurrY.Checked, DDisplay2OnItemDraw);
end;
// Установка порога Alert по амплитуде сигнала
procedure TForm1.CBox2AlertClick(Sender: TObject);
begin
  if Assigned(DDisplay2)
  then begin
    if CBox2Alert.Checked
    then DDisplay2.MdAlert := Abs(Signal)
    else DDisplay2.MdAlert := -1;
  end;
end;
// Установка чувствительности (единицы на шаг сетки)
procedure TForm1.CbBox2SensClick(Sender: TObject);
begin
  if Assigned(DDisplay2)
  then begin
     case CbBox2Sens.ItemIndex of
     0 : DDisplay2.Sens := 1;
     1 : DDisplay2.Sens := 5;
     2 : DDisplay2.Sens := 10;
     3 : DDisplay2.Sens := 50;
     end;
  end;
end;
// ===========================================================
// ЗАПИСЬ В ОСЦИЛЛОГРАФЫ
// ===========================================================
// ОСЦИЛЛОГРАФ 1 (Добавить выбранную точку и отобразить осциллограмму)
procedure TForm1.AddPointToOscillograph1(RqOutDAC : double);
var Y : double;
begin
   Y := 0;
   if Assigned(DDisplay1)
   then begin
     // Выбор входа
     case CbBoxInDisplay1.ItemIndex of
     0: if PMod then Y := 1 else Y := 0;       // Модуляция (P)
     1: Y := Balans;                           // Значение Balans
     2: Y := PNum;                             // Значение PNum
     3: Y := NNum;                             // Значение NNum
     4: Y := PNum -NNum;                       // Значение PNum - NNum
     5: Y := RqOutDAC;                         // Вых. ЦАП
     end;
     // Добавить выбранную точку и отобразить осциллограмму
     AddPointToDDisplay(DDisplay1, CbBoxDisplay1Style.ItemIndex, Y);
   end;
end;
// ОСЦИЛЛОГРАФ 2 (Добавить выход ЦАП и отобразить осциллограмму)
procedure TForm1.AddPointToOscillograph2(RqOutDAC : double);
begin
  // Добавить точку в конец осциллограммы и отобразить осциллограмму
  AddPointToDDisplay(DDisplay2, CbBoxDisplay2Style.ItemIndex, RqOutDAC);
end;

// ===========================================================
// УПРАВЛЕНИЕ ПРОЦЕССОМ
// ===========================================================
// ТЕМП ПРОЦЕССА
procedure TForm1.CBoxTempClick(Sender: TObject);
begin
   case CBoxTemp.ItemIndex of
   0 : Timer1.Interval := 500;
   1 : Timer1.Interval := 400;
   2 : Timer1.Interval := 300;
   3 : Timer1.Interval := 200;
   4 : Timer1.Interval := 100;
   5 : Timer1.Interval := 50;
   6 : Timer1.Interval := 20;
   end;
end;
// ВКЛЮЧЕНИЕ ПРОЦЕССА
procedure TForm1.SBttStartClick(Sender: TObject);
begin
   if Assigned(DDisplay1)
   then begin
       RunFlag := True;   // Запустить процесс
   end;
end;
// ОСТАНОВКА ПРОЦЕССА
procedure TForm1.SBttStopClick(Sender: TObject);
begin
   RunFlag := False;     // Остановить процесс
end;
// Полный сброс текущего процесса
procedure TForm1.BttResetAllClick(Sender: TObject);
begin
   SBttStop.Down := True;
   SBttStart.Down := False;
   RunFlag := False;
   ClearDacAdc();
   if Assigned(DDisplay1) then DDisplay1.DisplayClear;
   if Assigned(DDisplay2) then DDisplay2.DisplayClear;
end;

// ===========================================================
//   SD-модулятор (АЦП), SD-ЦАП
// ===========================================================
// Сброс SD-модулятора и SD-ЦАП
procedure TForm1.ClearDacAdc();
var Ind : integer;
begin
   // ----------------------------
   // Сброс SD-модулятора и SD-АЦП
   PMod    := False;
   Balans  := 0;                 // Весы в уравновешенном состоянии
   PNum    := 0;                 // Счетчик перевесов в сторону уравновешивания
   NNum    := 0;                 // Счетчик перевесов в сторону меры
   // Сброс индикаторов
   STxtBalans.Caption := '';
   STxtNumP.Caption   := '';
   StxtNumN.Caption   := '';
   StxtImpP.Color := clBtnFace;
   // ----------------------------
   // Сброс SD-ЦАП
   SDLpfOut := 0;       // Выход SIGMA-DELTA ФНЧ
   OutDAC   := 0;
   // ----------------------------
   // Сброс альтернативных ФНЧ
   // ----------------------------
   LPF2Out  := 0;       // Выход рекурсивного ФНЧ
   FormPFilter.ClearFilter();
   // ----------------------------
   LPF3Buf  := 0;       // Буфер усредняющего ФНЧ
   LPF3Out  := 0;       // Выход усредняющего ФНЧ
   // ----------------------------
   // Сброс индикаторов
   StxtPsubN.Caption := '';
   StxtNumSteps.Caption := '';
   StxtOutSDLPF.Caption := '';
   STxtOutDAC.Caption := '';

   // ----------------------------
   // ОСЦИЛЛОГРАФ 1 (Добавить выбранную точку и отобразить осциллограмму)
   AddPointToOscillograph1(OutDAC);
   // ОСЦИЛЛОГРАФ 2 (Добавить выход ЦАП и отобразить осциллограмму)
   AddPointToOscillograph2(OutDAC);
end;

// -----------------------------------------------------------
// ОСНОВНАЯ ФУНКЦИЯ SD-модулятора (АЦП)
// (Сигма-Дельта-алгоритм)
procedure SDMOD();
begin
   if Balans > 0
   then begin
      // Перевес в сторону уравновешивания
      // Добавить меру на сторону сигнала
      Balans := Balans - (Mera + Signal);
      NNum := NNum + 1;
      PMod := False;
   end
   else begin
     // Перевес в сторону сигнала
     // добавить меру на сторону уравновешивания
     Balans  := Balans + Mera - Signal;
     PNum := PNum + 1;
     PMod := True;
   end;
end;
// ОСНОВНАЯ ФУНКЦИЯ SD-ЦАП
// (Цифровой ФНЧ)
function SDDAC () : double;
begin
   // -----------------------------------------
   // SIGMA-DELTA цифровая фильтрация (ЦАП)
   if PNum + NNum > 0
   then Result := Mera * (PNum - NNum) /( PNum + NNum)
   else Result := 0;
   // -----------------------------------------
   // Альтернативные варианты цифровой фильтрации
   // -----------------------------------------
   // Заказной ФНЧ
   if PMod
   then LPF2Out := FormPFilter.RunFilter(Mera)
   else LPF2Out := FormPFilter.RunFilter(-Mera);

   // -----------------------------------------
   // Усредняющий ФНЧ
   if PNum + NNum > 0
   then begin
      if PMod
      then LPF3Buf := LPF3Buf + Mera
      else LPF3Buf := LPF3Buf - Mera;
      LPF3Out := LPF3Buf / (PNum + NNum);
   end;
end;

// ===========================================================
// УПРАВЛЕНИЕ ДЛЯ SD-Модулятора и SD-ЦАП
// ===========================================================
// Сброс SD-модулятора и SD-ЦАП
procedure TForm1.BttResetClick(Sender: TObject);
begin
  ClearDacAdc();
end;
// Установка новой меры для SD-Модулятора и SD-ЦАП
procedure TForm1.EdMeraChange(Sender: TObject);
var SMera : double;
begin
  SMera := Mera;
  if EditTextToFloat(Mera, EdMera)
  then begin
      if Mera > 0
      then begin
          if (Mera > Signal)
          then begin
            // Все ОК!
            ClearDacAdc();
            if Assigned(DDisplay1) then DDisplay1.MdAlert := Abs(2*Mera);
          end
          else begin
            ShowMessage ('Мера не может быть меньше сигнала');
            Mera := SMera;
            ClearDacAdc();
            EdMera.Text := FloatToStr(Mera);
          end;
      end
      else begin
         ShowMessage ('Мера всегда должна быть ненулевой и положительной');
         Mera := SMera;
         ClearDacAdc();
         EdMera.Text := FloatToStr(Mera);
      end;
   end;
end;
// Установка нового сигнала для SD-Модулятора
procedure TForm1.EdSignalChange(Sender: TObject);
var SSignal : double;
begin
   SSignal := Signal;
   if EditTextToFloat(Signal, EdSignal)
   then begin
      if (Signal >=0) and (Mera >Signal)
      then begin
        // Все ОК!
        ClearDacAdc();
        if Assigned(DDisplay2) then DDisplay2.MdAlert := Abs(Signal);
      end
      else begin
        ShowMessage ('Сигнал должен быть положительным и меньше меры');
        Signal := SSignal;
        ClearDacAdc();
        EdSignal.Text := FloatToStr(Signal);
      end;
   end;
end;
// Изменить структуру цифрового SD-ФНЧ (SD-ЦАП)
procedure TForm1.CbBoxLPFClick(Sender: TObject);
begin
   RqLPF   := CbBoxLPF.ItemIndex;
   if RqLPF = 1
   then BitBtnParmFltR.Visible := True
   else BitBtnParmFltR.Visible := False;
end;
// Вызов формы параметров заказного фильтра
procedure TForm1.BitBtnParmFltRClick(Sender: TObject);
begin
   FormPFilter.Show;
end;
// Максимальное число шагов до остановки
procedure TForm1.CBoxMaxStepClick(Sender: TObject);
begin
   case CBoxMaxStep.ItemIndex of
   0 : MaxStep := -1;       // Число шагов неограничено
   1 : MaxStep := 0;        // До перехода баланса через ноль
   2 : MaxStep := 1;        // Пошаговый режим
   3 : MaxStep := 10;
   4 : MaxStep := 20;
   5 : MaxStep := 40;
   6 : MaxStep := 80;
   7 : MaxStep := 100;
   8 : MaxStep := 200;
   9 : MaxStep := 400;
  10 : MaxStep := 800;
  11 : MaxStep := 1000;
  12 : MaxStep := 2000;
  13 : MaxStep := 4000;
  14 : MaxStep := 8000;
  15 : MaxStep := 10000;
   end;
end;

// ===========================================================
//   ОСНОВНОЙ ЦИКЛ ПРОЦЕССА
// ===========================================================
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  if RunFlag
  then begin
     // -----------------------------------------
     if Balans > 0
     then StxtImpP.Color := clBtnFace
     else StxtImpP.Color := clLime;
     // ОДИН ШАГ ДЛЯ SD-модулятора (АЦП)
     SDMOD();           // Сформировать новые значения SD-модулятора
     // Вывод значения нового баланса шага
     STxtBalans.Caption := FormatFloat('#0.000000000000',Balans);
     STxtNumP.Caption   := FloatToStr(PNum);
     StxtNumN.Caption   := FloatToStr(NNum);
     // -----------------------------------------
     // ОДИН ШАГ ДЛЯ SD-ЦАП
     SDLpfOut := SDDAC();          // Вых. ЦАП
     StxtPsubN.Caption := FloatToStr(PNum - NNum);
     StxtNumSteps.Caption  := FloatToStr(PNum + NNum);
     // Выход SIGMA-DELTA ФНЧ
     StxtOutSDLPF.Caption := FormatFloat('#0.00000',SDLpfOut);
     // Выход ЦАП
     case CbBoxLPF.ItemIndex of
     0 : OutDAC := SDLpfOut; // SD-ФНЧ
     1 : OutDAC := LPF2Out;  // рекурсивный ФНЧ
     2 : OutDAC := LPF3Out;  // усредняющий ФНЧ
     end;
     STxtOutDAC.Caption := FormatFloat('#0.00000',OutDAC);
     // -----------------------------------------
     // ОСЦИЛЛОГРАФ 1 (Добавить выбранную точку и отобразить осциллограмму)
     AddPointToOscillograph1(OutDAC);
     // ОСЦИЛЛОГРАФ 2 (Добавить выход ЦАП и отобразить осциллограмму)
     AddPointToOscillograph2(OutDAC);
     // -----------------------------------------
     // Управление остановками
     if (MaxStep = 0) and (PNum + NNum > 0) and (Abs(Balans) < SBalansMin)
     then begin
        // Выполнить остановку по условию (Balans = 0)
        SBttStop.Down := True;
        SBttStart.Down := False;
        RunFlag := False;
     end
     else begin
       // -----------------------------------------
       // Остановка по числу заказанных шагов
       if (MaxStep > 0) and (MaxStep <= PNum + NNum)
       then begin
          // Выполнить остановку
          SBttStop.Down := True;
          SBttStart.Down := False;
          RunFlag := False;
       end;
     end;

     // -----------------------------------------
  end;
end;
// ===========================================================
// ===========================================================
end.
