unit u_complex;

{$mode objfpc}{$H+}

interface
uses ucomplex;  // supports complex math by operator overloading

// Often used functions
function Log10(V: real): real;            { 10-base logarithm }
function Ten2Power(Exponent: real): real; { 10 to power of exponent }
function Rad2Deg(Radians: real): real;    { radians to degrees }
function Deg2Rad(Degrees: real): real;    { degrees to radians }
function Parallel(a:real; b:real): real;  {resistors parallel, capacitors in series}

// Conversions to complex
function cpxL(L, Freq: real): complex;    { inductor, Henry, Hz }
function cpxC(C, Freq: real): complex;    { capacitor, Farad, Hz }

// Conversions from complex
function cpxPhaseRad(a: complex): real;   { phase in radians over pi/2 }
function cpxPhaseDeg(a: complex): real;   { phase in degrees over +/- 180 }
function cpxMag(a: complex): real;        { magnitude }
function cpxdBMag(a: complex): real;      { dB(magnitude) }

// Complex Math extended
operator and (a, b: complex) c: complex;  			{ impedances parallel }
operator and (a: complex; b: real) c: complex;  { impedances parallel }
operator and (a: real; b: complex) c: complex;  { impedances parallel }

function cpxDerive(a: complex; Freq: real): complex; { first derivative to Freq }
function cpxIntegrate(a: complex; Freq: real): complex; { integral to Frequency }

implementation
uses math;

// Often used functions
function Log10(V: real): real;
begin
	Log10:= ln(V) / ln(10);
end;

function Ten2Power(Exponent: real): real;
begin
	Ten2Power:= Exp(Exponent * Ln(10));
end;

function Rad2Deg(Radians: real): real;
begin
	Rad2Deg:= (radians / pi) * 180;
end;

function Deg2Rad(Degrees: real): real;
begin
  Deg2Rad:= (Degrees / 180) * pi;
end;

function Parallel(a: real; b: real): real; { resistors parallel, capacitors in serie }
begin
	Parallel:= (a * b) / (a + b);
end;

// Conversions to complex

{ Inductor }
function cpxL(L, Freq: real): complex;
begin
	cpxL.re:= 0;
	cpxL.im:= L * 2 * pi * Freq;
end;

{ Capacitor }
function cpxC(C, Freq: real): complex;
begin
	cpxC.re := 0;
  cpxC.im := 0;
  if (C = 0) or (Freq = 0) then exit; // prevent division by zero
	cpxC.im := - 1 / (2 * pi * Freq * C);
end;


// Conversions from complex to real

{ Phase in radians}
function cpxPhaseRad(a: complex): real;
begin
	cpxPhaseRad:= arctan2(a.im, a.re);
end;

{ Phase in degrees}
function cpxPhaseDeg(a: complex): real;
begin
	cpxPhaseDeg:= Rad2Deg(arctan2(a.im, a.re));
end;

{ Magnitude }
function cpxMag(a: complex): real;
begin
	cpxMag:= sqrt(sqr(a.re) + sqr(a.im));
end;

{ dB magnitude}
function cpxdBMag(a:complex): real;
begin
	cpxdBmag:= 20 * log10(cpxMag(a));
end;

// Complex math extended

{ impedances parallel }
operator and (a, b: complex) c: complex;
begin
	c:= (a * b) / (a + b);
end;

{ impedances parallel }
operator and (a: complex; b:real) c: complex;
begin
	c:= (a * b) / (a + b);
end;

{ impedances parallel }
operator and (a: real; b: complex) c: complex;
begin
	c:= (a * b) / (a + b);
end;

{ first derivative to frequency }
function cpxDerive(a: complex; Freq: real): complex;
begin
  cpxDerive.re:= -a.im * Freq * 2 * pi;
  cpxDerive.im:= a.re * Freq * 2 * pi;
end;

{ integral to frequency }
function cpxIntegrate(a: complex; Freq: real): complex;
begin
  if Freq = 0 then exit; // prevent division by zero
  cpxIntegrate.re:= a.im / Freq / 2 / pi;
  cpxIntegrate.im:= -a.re / Freq / 2 / pi;
end;

end.

