unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ExtCtrls, Math;

type
  TFunc = function (x : Double) : Double;

  TForm1 = class(TForm)
    Label1: TLabel;
    cmbS: TComboBox;
    Label2: TLabel;
    Label3: TLabel;
    txtL: TEdit;
    Label4: TLabel;
    Label5: TLabel;
    txtF: TEdit;
    Label6: TLabel;
    Label7: TLabel;
    txtBits: TEdit;
    Label8: TLabel;
    pbxPreview: TPaintBox;
    Button1: TButton;
    Bevel1: TBevel;
    Label9: TLabel;
    txtDAC: TEdit;
    Label10: TLabel;
    cmbOnda: TComboBox;
    cmbRectificacion: TComboBox;
    Label11: TLabel;
    Label12: TLabel;
    txtDesde: TEdit;
    Label13: TLabel;
    txtHasta: TEdit;
    Label14: TLabel;
    Button2: TButton;
    procedure FormCreate(Sender: TObject);
    procedure pbxPreviewPaint(Sender: TObject);
    procedure RefrescarPreview(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    function getFuncOnda: TFunc;
    function getFuncRectif: TFunc;
    { Private declarations }
  public
    { Public declarations }
    property func_onda : TFunc read getFuncOnda;
    property func_rectif : TFunc read getFuncRectif;
    function CalcularDAC (metros : Double) : Integer;
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
  DecimalSeparator := '.';
  cmbOnda.ItemIndex := 0;
  cmbRectificacion.ItemIndex := 0;
end;

function func_sin (x : Double) : Double;
begin
  Result := Sin(2.0*PI*x);
end;

function func_square (x : Double) : Double;
begin
  If  x - Floor (x) < 0.5 Then
    Result := 1.0
  Else
    Result := -1.0;
end;

function rectif_none (x : Double) : Double;
begin
  Result := x;
end;

function rectif_zero (x : Double) : Double;
begin
  If x < 0.0 Then
    Result := 0.0
  Else
    Result := x;
end;

function rectif_abs (x : Double) : Double;
begin
  Result := Abs (x);
end;

function TForm1.getFuncOnda: TFunc;
begin
  Case cmbOnda.ItemIndex of
  0:
    Result := func_sin;
  1:
    Result := func_square;
  else
    raise Exception.Create ('Selecciona un tipo de onda, imbécil');
  end;
end;

function TForm1.getFuncRectif: TFunc;
begin
  Case cmbRectificacion.ItemIndex of
  0:
    Result := rectif_zero;
  1:
    Result := rectif_abs;
  2:
    Result := rectif_none;
  else
    raise Exception.Create ('Selecciona un rectificador, pelotudo ignorante');
  end;
end;

procedure TForm1.pbxPreviewPaint(Sender: TObject);
var
  func, rectif : TFunc;
  i : Integer;
  t, s, l, f, a1, a2, da : Double;
  lp1, lp2, lp3, p1, p2, p3 : TPoint;
begin
  func := func_onda;
  rectif := func_rectif;
  try
    s := StrToFloat (cmbS.Text);
    l := StrToFloat (txtL.Text);
    f := StrToFloat (txtF.Text);
    For i := 0 To pbxPreview.Width-1 do
    begin
      t := i * 0.000001; // microsegundos
      a1 := func(f*t);
      a2 := func(f*(t - l / s));
      p1.x := i;
      p2.x := i;
      p3.x := i;
      p1.y := Trunc(pbxPreview.Height * 0.5 - pbxPreview.Height * 0.25 * a1);
      p2.y := Trunc(pbxPreview.Height * 0.5 - pbxPreview.Height * 0.25 * a2);
      da := rectif (a1 - a2);
      p3.y := Trunc(pbxPreview.Height * 0.5 - pbxPreview.Height * 0.25 * da);
      If i > 0 Then
      begin
        pbxPreview.Canvas.Pen.Color := clSilver;
        pbxPreview.Canvas.MoveTo (lp1.x, lp1.y);
        pbxPreview.Canvas.LineTo (p1.x, p1.y);
        pbxPreview.Canvas.Pen.Color := clBlack;
        pbxPreview.Canvas.MoveTo (lp2.x, lp2.y);
        pbxPreview.Canvas.LineTo (p2.x, p2.y);
        pbxPreview.Canvas.Pen.Color := clRed;
        pbxPreview.Canvas.MoveTo (lp3.x, lp3.y);
        pbxPreview.Canvas.LineTo (p3.x, p3.y);
      end;
      lp1 := p1;
      lp2 := p2;
      lp3 := p3;
    end;
    txtDAC.Text := IntToStr(CalcularDAC(l));
  except
    pbxPreview.Canvas.MoveTo (0, 0);
    pbxPreview.Canvas.LineTo (pbxPreview.Width, pbxPreview.Height);
    pbxPreview.Canvas.MoveTo (pbxPreview.Width, 0);
    pbxPreview.Canvas.LineTo (0, pbxPreview.Height);
    txtDAC.Text := '---';
  end;
end;

function TForm1.CalcularDAC(metros: Double): Integer;
var
  i, lpow, ldac : Integer;
  sum, a1, a2, da, f, t, s : Double;
  func, rectif : TFunc;
  delta_t : Double;
begin
  s := StrToFloat (cmbS.Text);
  func := func_onda;
  rectif := func_rectif;
  // Calcular el valor del DAC
  sum  := 0.0;
  delta_t := 1.0 / (9999 + 1);
  f := StrToFloat(txtF.Text);
  For i := 0 To 9999 do
  begin
    t := (i * delta_t) / f;
    a1 := func(f*t);
    a2 := func(f*(t - metros/s));
    da := rectif (a1 - a2);
    sum := sum + da * delta_t;
  end;
  lpow := (1 shl StrToInt(txtBits.Text)) - 1;
  ldac := Trunc (sum * lpow);
  If ldac < 0 Then ldac := 0;
  If ldac > lpow Then ldac := lpow;
  Result := ldac;
end;

procedure TForm1.RefrescarPreview(Sender: TObject);
begin
  pbxPreview.Repaint;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  pt : TPoint;
  s, e : Double;
  i, lpow : Integer;
begin
  pbxPreview.Canvas.Brush.Color := Color;
  pbxPreview.Canvas.FillRect (Rect (0, 0, pbxPreview.Width, pbxPreview.Height));
  s := StrToFloat (txtDesde.Text);
  e := StrToFloat (txtHasta.Text);
  lpow := (1 shl StrToInt(txtBits.Text)) - 1;
  For i := 0 To pbxPreview.Width-1 do
  begin
    pt.x := i;
    pt.y := pbxPreview.Height - 1 - CalcularDAC (s + (e - s) / (pbxPreview.Width-1) * i) * (pbxPreview.Height - 1 ) div lpow;
    If i = 0 Then
      pbxPreview.Canvas.MoveTo (pt.x, pt.y)
    Else
      pbxPreview.Canvas.LineTo (pt.x, pt.y);
  end;
end;

end.

