Hi!
Für alle, die komplexe Schaltungsberechnung mit Widerständen, Kondensatoren und Spulen in Delphi suchen: meine Bibliothek berechnet diese Schaltungen und bietet einige Zusatzfunktionen wie z.B. die Berechnung von Resonanzfrequenzen.
Grundlage des Ganzen ist meine Unit zur komplexen Rechnung:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259: 260: 261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: 279: 280: 281: 282: 283: 284: 285: 286: 287: 288: 289: 290: 291: 292: 293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322:
| unit cmpxutil;
interface
uses Math; const e = 2.71828182846; type TComplexNumber = record Real, Imaginary: Double; AbsoluteV, Phase: Double; end;
TComplexNumberArray = Array of TComplexNumber; const j: TComplexNumber = (Real: 0; Imaginary: 1; AbsoluteV: 1; Phase: Pi / 2); minus_j: TComplexNumber = (Real: 0; Imaginary: -1; AbsoluteV: 1; Phase: 3 * Pi / 2); one: TComplexNumber = (Real: 1; Imaginary: 0; AbsoluteV: 1; Phase: 0); minus_one: TComplexNumber = (Real: -1; Imaginary: 0; AbsoluteV: 1; Phase: Pi); zero: TComplexNumber = (Real: 0; Imaginary: 0; AbsoluteV: 0; Phase: 0); procedure RealPhase(var ANumber: TComplexNumber); function CreateComplexNumber_Comp(Real, Imaginary: Double): TComplexNumber; function CreateComplexNumber_Polar(AbsoluteV, Phase: Double): TComplexNumber; procedure SetReal(var ANumber: TComplexNumber; AValue: Double); procedure SetImaginary(var ANumber: TComplexNumber; AValue: Double); procedure SetAbsoluteV(var ANumber: TComplexNumber; AValue: Double); procedure SetPhase(var ANumber: TComplexNumber; AValue: Double); procedure Conjunct(var ANumber: TComplexNumber); function Conjunct2(ANumber: TComplexNumber): TComplexNumber; procedure Invert(var ANumber: TComplexNumber); procedure InvertAll(var AnArray: TComplexNumberArray);
function CompToPolar(var ANumber: TComplexNumber): Boolean; function PolarToComp(var ANumber: TComplexNumber): Boolean;
function ComplexAdd(Number1, Number2: TComplexNumber): TComplexNumber; function ComplexAdd2(Numbers: TComplexNumberArray): TComplexNumber; function ComplexSub(Number1, Number2: TComplexNumber): TComplexNumber; function ComplexMul(Number1, Number2: TComplexNumber): TComplexNumber; function ComplexDiv(Number1, Number2: TComplexNumber): TComplexNumber;
function ComplexPowerSimple(ANumber: TComplexNumber; APower: Double): TComplexNumber; function ComplexSqrt(ANumber: TComplexNumber; ARoot: Double): TComplexNumber; function ComplexSqrtEx(ANumber: TComplexNumber; ARoot: Integer): TComplexNumberArray; function ComplexLn(ANumber: TComplexNumber; ABase: Double = e): TComplexNumber; function ComplexExp(ANumber: TComplexNumber): TComplexNumber; function ComplexPower(ANumber1, ANumber2: TComplexNumber): TComplexNumber;
function ComplexSin(ANumber: TComplexNumber): TComplexNumber; function ComplexCos(ANumber: TComplexNumber): TComplexNumber; function ComplexSinh(ANumber: TComplexNumber): TComplexNumber; function ComplexCosh(ANumber: TComplexNumber): TComplexNumber;
function MaxReal(Numbers: TComplexNumberArray): Double; function MaxImg(Numbers: TComplexNumberArray): Double; function MaxAbs(Numbers: TComplexNumberArray): Double;
implementation
procedure RealPhase(var ANumber: TComplexNumber); begin ANumber.Phase := Frac(ANumber.Phase / (2 * Pi)) * 2 * Pi; while ANumber.Phase < 0 do ANumber.Phase := ANumber.Phase + 2 * Pi; end;
function CompToPolar(var ANumber: TComplexNumber): Boolean; begin Result := true; try with ANumber do begin AbsoluteV := Sqrt(Sqr(Real) + Sqr(Imaginary)); Phase := ArcTan2(Imaginary, Real); RealPhase(ANumber); end; except Result := false; end; end;
function PolarToComp(var ANumber: TComplexNumber): Boolean; begin Result := true; try RealPhase(ANumber); with ANumber do begin Real := AbsoluteV * Cos(Phase); Imaginary := AbsoluteV * Sin(Phase); end; except Result := false; end; end;
function ComplexAdd(Number1, Number2: TComplexNumber): TComplexNumber; begin Result.Real := Number1.Real + Number2.Real; Result.Imaginary := Number1.Imaginary + Number2.Imaginary; CompToPolar(Result); end;
function ComplexAdd2(Numbers: TComplexNumberArray): TComplexNumber; var i: Integer; begin Result := zero; for i := Low(Numbers) to High(numbers) do Result := ComplexAdd(Result, numbers[i]); end;
function ComplexSub(Number1, Number2: TComplexNumber): TComplexNumber; begin Result.Real := Number1.Real - Number2.Real; Result.Imaginary := Number1.Imaginary - Number2.Imaginary; CompToPolar(Result); end;
function ComplexMul(Number1, Number2: TComplexNumber): TComplexNumber; begin Result.AbsoluteV := Number1.AbsoluteV * Number2.AbsoluteV; Result.Phase := Number1.Phase + Number2.Phase; PolarToComp(Result); end;
function ComplexDiv(Number1, Number2: TComplexNumber): TComplexNumber; begin Result.AbsoluteV := Number1.AbsoluteV / Number2.AbsoluteV; Result.Phase := Number1.Phase - Number2.Phase; PolarToComp(Result); end;
function ComplexPowerSimple(ANumber: TComplexNumber; APower: Double): TComplexNumber; begin Result.AbsoluteV := Power(ANumber.AbsoluteV, APower); Result.Phase := ANumber.Phase * APower; PolarToComp(Result); end;
function ComplexSqrt(ANumber: TComplexNumber; ARoot: Double): TComplexNumber; begin Result.AbsoluteV := Power(ANumber.AbsoluteV, 1 / ARoot); Result.Phase := ANumber.Phase / ARoot; PolarToComp(Result); end;
function ComplexSqrtEx(ANumber: TComplexNumber; ARoot: Integer): TComplexNumberArray; var i: Integer; begin SetLength(Result, ARoot); ComplexSqrt(Result[0], ARoot); PolarToComp(Result[0]); for i := 1 to ARoot - 1 do begin Result[i].Phase := Result[0].Phase + 2 * Pi * i / ARoot; PolarToComp(Result[i]); end; end;
function ComplexLn(ANumber: TComplexNumber; ABase: Double = e): TComplexNumber; begin Result.Real := Ln(ANumber.AbsoluteV); Result.Imaginary := ANumber.Phase; CompToPolar(Result); if not IsZero(ABase - e) then begin Result.AbsoluteV := Result.AbsoluteV / Ln(ABase); PolarToComp(Result); end; end;
function ComplexExp(ANumber: TComplexNumber): TComplexNumber; begin Result.AbsoluteV := Exp(ANumber.Real); Result.Phase := ANumber.Imaginary; CompToPolar(Result); end;
function ComplexPower(ANumber1, ANumber2: TComplexNumber): TComplexNumber; begin Result := ComplexExp(ComplexMul(ANumber2, ComplexLn(ANumber1))); end;
function ComplexSin(ANumber: TComplexNumber): TComplexNumber; begin Result.Real := Sin(ANumber.Real) * Cosh(ANumber.Imaginary); Result.Imaginary := Cos(ANumber.Real) * Sinh(ANumber.Imaginary); CompToPolar(Result); end;
function ComplexCos(ANumber: TComplexNumber): TComplexNumber; begin Result.Real := Cos(ANumber.Real) * Cosh(ANumber.Imaginary); Result.Imaginary := -Sin(ANumber.Real) * Sinh(ANumber.Imaginary); CompToPolar(Result); end;
function ComplexSinh(ANumber: TComplexNumber): TComplexNumber; begin Result.Real := Sinh(ANumber.Real) * Cos(ANumber.Imaginary); Result.Imaginary := Cosh(ANumber.Real) * Sin(ANumber.Imaginary); CompToPolar(Result); end;
function ComplexCosh(ANumber: TComplexNumber): TComplexNumber; begin Result.Real := Cosh(ANumber.Real) * Cos(ANumber.Imaginary); Result.Imaginary := Sinh(ANumber.Real) * Sin(ANumber.Imaginary); CompToPolar(Result); end;
function MaxReal(Numbers: TComplexNumberArray): Double; var i: Integer; begin Result := 0; for i := Low(Numbers) to High(Numbers) do begin if Abs(Numbers[i].Real) > Result then Result := Abs(Numbers[i].Real); end; end;
function MaxImg(Numbers: TComplexNumberArray): Double; var i: Integer; begin Result := 0; for i := Low(Numbers) to High(Numbers) do begin if Abs(Numbers[i].Imaginary) > Result then Result := Abs(Numbers[i].Imaginary); end; end;
function MaxAbs(Numbers: TComplexNumberArray): Double; var i: Integer; begin Result := 0; for i := Low(Numbers) to High(Numbers) do begin if Abs(Numbers[i].AbsoluteV) > Result then Result := Abs(Numbers[i].AbsoluteV); end; end;
function CreateComplexNumber_Comp(Real, Imaginary: Double): TComplexNumber; begin Result.Real := Real; Result.Imaginary := Imaginary; CompToPolar(Result); end;
function CreateComplexNumber_Polar(AbsoluteV, Phase: Double): TComplexNumber; begin Result.AbsoluteV := AbsoluteV; Result.Phase := Phase; PolarToComp(Result); end;
procedure SetReal(var ANumber: TComplexNumber; AValue: Double); begin ANumber.Real := AValue; CompToPolar(ANumber); end;
procedure SetImaginary(var ANumber: TComplexNumber; AValue: Double); begin ANumber.Imaginary := AValue; CompToPolar(ANumber); end;
procedure SetAbsoluteV(var ANumber: TComplexNumber; AValue: Double); begin ANumber.AbsoluteV := AValue; PolarToComp(ANumber); end;
procedure SetPhase(var ANumber: TComplexNumber; AValue: Double); begin ANumber.Phase := AValue; PolarToComp(ANumber); end;
procedure Conjunct(var ANumber: TComplexNumber); begin ANumber.Phase := -ANumber.Phase; PolarToComp(ANumber); end;
function Conjunct2(ANumber: TComplexNumber): TComplexNumber; begin Conjunct(ANumber); Result := ANumber; end;
procedure Invert(var ANumber: TComplexNumber); begin ANumber := ComplexDiv(one, ANumber); end;
procedure InvertAll(var AnArray: TComplexNumberArray); var i: Integer; begin for i := Low(AnArray) to High(AnArray) do Invert(AnArray[i]); end;
end. |
Dazu eine Unit, die der eigentlichen Schaltungsberechnungsunit bei der Berechnung etwas unter die Arme greift:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90:
| unit circutil;
interface
uses cmpxutil;
function GetAngularFrequency(AFrequency: Double): Double; function GetFrequency(AnAngularFrequency: Double): Double;
function Get_R(U, I: TComplexNumber): TComplexNumber; function Get_U(R, I: TComplexNumber): TComplexNumber; function Get_I(U, R: TComplexNumber): TComplexNumber;
function GetAppearentValue(AValue: TComplexNumber): Double; function GetReactiveValue(AValue: TComplexNumber): Double; function GetEffectiveValue(AValue: TComplexNumber): Double; function GetPhase(AValue: TComplexNumber): Double; function GetAppearentPower(U, I: TComplexNumber): TComplexNumber;
function GetResonantCircuitResonanceFrequency(L, C: Double): Double; function GetHighLowPassResonanceFrequency(R, C: Double): Double;
implementation
function GetAngularFrequency(AFrequency: Double): Double; begin Result := 2 * Pi * AFrequency; end;
function GetFrequency(AnAngularFrequency: Double): Double; begin Result := AnAngularFrequency / (2 * Pi); end;
function Get_R(U, I: TComplexNumber): TComplexNumber; begin Result := ComplexDiv(U, I); end;
function Get_U(R, I: TComplexNumber): TComplexNumber; begin Result := ComplexMul(R, I); end;
function Get_I(U, R: TComplexNumber): TComplexNumber; begin Result := ComplexDiv(U, R); end;
function GetAppearentValue(AValue: TComplexNumber): Double; begin Result := AValue.AbsoluteV; end;
function GetReactiveValue(AValue: TComplexNumber): Double; begin Result := AValue.Imaginary; end;
function GetEffectiveValue(AValue: TComplexNumber): Double; begin Result := AValue.Real; end;
function GetPhase(AValue: TComplexNumber): Double; begin Result := AValue.Phase; end;
function GetAppearentPower(U, I: TComplexNumber): TComplexNumber; begin Result := ComplexMul(U, Conjunct2(I)); end;
function GetResonantCircuitResonanceFrequency(L, C: Double): Double; begin Result := GetFrequency(1 / Sqrt(L * C)); end;
function GetHighLowPassResonanceFrequency(R, C: Double): Double; begin Result := GetFrequency(1 / (R * C)); end;
end. |
Zwischenbemerkung: die englischen Wörter klingen leider hin und wieder sehr seltsam -
dict.leo.org schafft Abhilfe
.
So, nun zur eigentlichen Unit:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158:
| unit circcalc;
interface
uses cmpxutil, circutil;
type TCustomCircuitElement = class private FElementValue: Double; public function GetImpedance: TComplexNumber; virtual; abstract; constructor Create(AnElementValue: Double); published property ElementValue: Double read FElementValue write FElementValue; property Impedance: TComplexNumber read GetImpedance; end;
TCustomCircuitElementArray = Array of TCustomCircuitElement;
TResistor = class (TCustomCircuitElement) public function GetImpedance: TComplexNumber; override; end;
TCapacitor = class (TCustomCircuitElement) public function GetImpedance: TComplexNumber; override; end;
TCoil = class (TCustomCircuitElement) public function GetImpedance: TComplexNumber; override; end;
TCircuitElementGroup = class (TCustomCircuitElement) private FElements: TCustomCircuitElementArray; FParallel: Boolean; function GetElement(Index: Integer): TCustomCircuitElement; procedure SetElement(Index: Integer; AValue: TCustomCircuitElement); public function GetImpedance: TComplexNumber; override; constructor Create; destructor Destroy; override; property Items[Index: Integer]: TCustomCircuitElement read GetElement write SetElement; procedure AddElement(AnElement: TCustomCircuitElement); procedure DeleteElement(Index: Integer); published property Parallel: Boolean read FParallel write FParallel; end;
function GetImpedanceAsComplexNumbers(Elements: TCustomCircuitElementArray): TComplexNumberArray;
var GlobalCircularFrequency: Double = 2 * Pi * 50; implementation
constructor TCustomCircuitElement.Create(AnElementValue: Double); begin inherited Create; FElementValue := AnElementValue; end;
function TResistor.GetImpedance: TComplexNumber; begin Result := CreateComplexNumber_Comp(ElementValue, 0); end;
function TCapacitor.GetImpedance: TComplexNumber; var x: Double; begin x := 1 / (GlobalCircularFrequency * ElementValue); Result := ComplexMul(minus_j, CreateComplexNumber_Comp(x, 0)); end;
function TCoil.GetImpedance: TComplexNumber; var x: Double; begin x := GlobalCircularFrequency * ElementValue; Result := ComplexMul(j, CreateComplexNumber_Comp(x, 0)); end;
constructor TCircuitElementGroup.Create; begin inherited Create(0); SetLength(FElements, 0); FParallel := false; end;
destructor TCircuitElementGroup.Destroy; var i: Integer; begin for i := Low(FElements) to High(FElements) do FElements[i].Free; SetLength(FElements, 0); inherited; end;
function TCircuitElementGroup.GetElement(Index: Integer): TCustomCircuitElement; begin Result := FElements[Index]; end;
procedure TCircuitElementGroup.SetElement(Index: Integer; AValue: TCustomCircuitElement); begin FElements[Index] := AValue; end;
procedure TCircuitElementGroup.AddElement(AnElement: TCustomCircuitElement); begin SetLength(FElements, Length(FElements) + 1); FElements[High(FElements)] := AnElement; end;
procedure TCircuitElementGroup.DeleteElement(Index: Integer); var i: Integer; begin FElements[Index].Free; for i := Index to High(FElements) - 1 do FElements[i] := FElements[i + 1]; SetLength(FElements, Length(FElements) - 1); end;
function TCircuitElementGroup.GetImpedance: TComplexNumber; var impedancearray: TComplexNumberArray; begin impedancearray := GetImpedanceAsComplexNumbers(FElements); if not FParallel then Result := ComplexAdd2(impedancearray) else begin InvertAll(impedancearray); Result := ComplexAdd2(impedancearray); Invert(Result); end; end;
function GetImpedanceAsComplexNumbers(Elements: TCustomCircuitElementArray): TComplexNumberArray; var i: Integer; begin SetLength(Result, Length(Elements)); for i := Low(Elements) to High(Elements) do Result[i] := Elements[i].Impedance; end;
end. |
Zu guter letzt noch etwas Beispielcode. Der ist leider nicht sehr schön, erfüllt aber seinen Zweck. Einige Bemerkungen gleich dazu:
1.) Es muss nur die äußerste Schaltungsgruppe freigegeben werden - das Freigeben der Schaltungselemente, die sich in der jeweiligen Gruppe befinden, übernimmt ein modifizierter Destruktor
2.) Schaltungsgruppen können beliebig ineinander verschachtelt sein
3.) Die Eigenschaft
Impedance liefert die Impedanz des Bauelements/der Schaltungsgruppe
4.) ElementValue eines Kondensators darf nicht 0 sein; ebenso wie eine Parallelschaltung aus mindestens einem Element bestehen muss bevor ihre Impedanz aufgerufen wird.
5.) Die Wechselspannungsfrequenz kann über die globale Variable
GlobalCircularFrequency eingestellt werden
6.) Ströme und Spannungen können mit den Routinen
Get_U bzw.
Get_I in circutil.pas berechnet werden
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23:
| procedure TCircuitCalculationForm.FormCreate(Sender: TObject); var g: TCircuitElementGroup; begin g := TCircuitElementGroup.Create; with g do begin Parallel := true; AddElement(TResistor.Create(2200)); AddElement(TCoil.Create(0.3)); AddElement(TCapacitor.Create(8E-6)); end; with TCircuitElementGroup.Create do begin Parallel := false; AddElement(TCoil.Create(0.4)); AddElement(g); with ComplexEditorFrame1 do begin Initialize; SetReadOnly(true); SetPhasor(Impedance); end; Free; end; end; |
Lizenz: Open Source; solange mein Name im Header bleibt (als ursprünglicher Autor o.ä.) kann der Code modifiziert werden. Wird der Code in einem Programm verwendet bitte in der About-Box und der Readme (falls es eine gibt) einen entsprechenden Hinweis. Verwendung in Shareware oder anderen kommerziellen Projekten ist nicht gestattet.
Der Code ist noch etwas Beta, da nicht alles getestet ist. Freue mich über Anregungen aller Art
AXMD
PS.: Hin und wieder treten Memoryleaks auf - falls jemand die Ursache findet bitte Bescheid sagen