From 36af2775592dad74952bd9e917d33417713c2833 Mon Sep 17 00:00:00 2001 From: ig Date: Tue, 25 Apr 2023 11:27:57 +0200 Subject: [PATCH] use Double for Units. DecimalEx lib had too many bugs --- csharp/Lib/Units/Angle.cs | 15 ++--- csharp/Lib/Units/Angle.generated.cs | 15 ++--- csharp/Lib/Units/ApparentPower.cs | 2 +- csharp/Lib/Units/ApparentPower.generated.cs | 15 ++--- csharp/Lib/Units/Composite/Ac1Bus.cs | 29 ++++++--- csharp/Lib/Units/Composite/Ac3Bus.cs | 17 ++--- csharp/Lib/Units/Composite/AcPhase.cs | 64 +------------------ csharp/Lib/Units/Composite/AcPower.cs | 34 ++++++++++ .../Lib/Units/Composite/{IBus.cs => Bus.cs} | 6 +- csharp/Lib/Units/Composite/DcBus.cs | 14 ++-- csharp/Lib/Units/Current.cs | 2 +- csharp/Lib/Units/Current.generated.cs | 15 ++--- csharp/Lib/Units/Energy.cs | 6 +- csharp/Lib/Units/Energy.generated.cs | 15 ++--- csharp/Lib/Units/Frequency.cs | 2 +- csharp/Lib/Units/Frequency.generated.cs | 15 ++--- csharp/Lib/Units/Generator/Template.txt | 15 ++--- csharp/Lib/Units/Percent.cs | 2 +- csharp/Lib/Units/Percent.generated.cs | 15 ++--- csharp/Lib/Units/Power.cs | 6 +- csharp/Lib/Units/Power.generated.cs | 15 ++--- csharp/Lib/Units/ReactivePower.cs | 2 +- csharp/Lib/Units/ReactivePower.generated.cs | 15 ++--- csharp/Lib/Units/Resistance.cs | 2 +- csharp/Lib/Units/Resistance.generated.cs | 15 ++--- csharp/Lib/Units/Temperature.cs | 2 +- csharp/Lib/Units/Temperature.generated.cs | 15 ++--- csharp/Lib/Units/Units.cs | 21 +++--- csharp/Lib/Units/Voltage.cs | 2 +- csharp/Lib/Units/Voltage.generated.cs | 15 ++--- 30 files changed, 176 insertions(+), 232 deletions(-) create mode 100644 csharp/Lib/Units/Composite/AcPower.cs rename csharp/Lib/Units/Composite/{IBus.cs => Bus.cs} (53%) diff --git a/csharp/Lib/Units/Angle.cs b/csharp/Lib/Units/Angle.cs index 87a3ed2b4..14b269eb2 100644 --- a/csharp/Lib/Units/Angle.cs +++ b/csharp/Lib/Units/Angle.cs @@ -1,6 +1,5 @@ -using DecimalMath; using InnovEnergy.Lib.Units.Generator; -using InnovEnergy.Lib.Utils; +using static System.Math; namespace InnovEnergy.Lib.Units; @@ -10,16 +9,12 @@ public readonly partial struct Angle public static String Unit => "rad"; public static String Symbol => "∠"; - public static readonly Angle Pi = new Angle(DecimalEx.Pi); - - - public Angle(Decimal value) + public Angle(Double value) { - var modulo = value.Modulo(DecimalEx.TwoPi); + var modulo = value % Tau; // tau is 2pi - Value = modulo > DecimalEx.Pi - ? modulo - DecimalEx.TwoPi + Value = modulo > PI + ? modulo - Tau : modulo; } - } \ No newline at end of file diff --git a/csharp/Lib/Units/Angle.generated.cs b/csharp/Lib/Units/Angle.generated.cs index ccc8722f8..0a7764526 100644 --- a/csharp/Lib/Units/Angle.generated.cs +++ b/csharp/Lib/Units/Angle.generated.cs @@ -15,14 +15,14 @@ using T = Angle; [JsonConverter(typeof(AngleConverter))] public readonly partial struct Angle { - public Decimal Value { get; } + public Double Value { get; } public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit; // scalar multiplication - public static T operator *(Decimal scalar, T t) => new T(scalar * t.Value); - public static T operator *(T t, Decimal scalar) => new T(scalar * t.Value); - public static T operator /(T t, Decimal scalar) => new T(t.Value / scalar); + public static T operator *(Double scalar, T t) => new T(scalar * t.Value); + public static T operator *(T t, Double scalar) => new T(scalar * t.Value); + public static T operator /(T t, Double scalar) => new T(t.Value / scalar); // addition @@ -41,10 +41,7 @@ public readonly partial struct Angle // conversion - public static implicit operator T(Decimal d) => new T(d); - public static implicit operator T(Double d) => new T((Decimal)d); - public static implicit operator T(Int32 i) => new T(i); - public static implicit operator Decimal(T t) => t.Value; + public static implicit operator T(Double d) => new T(d); // equality @@ -59,7 +56,7 @@ internal class AngleConverter : JsonConverter { public override Angle Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - return new Angle(reader.GetDecimal()); + return new Angle(reader.GetDouble()); } public override void Write(Utf8JsonWriter writer, Angle value, JsonSerializerOptions options) diff --git a/csharp/Lib/Units/ApparentPower.cs b/csharp/Lib/Units/ApparentPower.cs index b2a5bba6c..605ac5b49 100644 --- a/csharp/Lib/Units/ApparentPower.cs +++ b/csharp/Lib/Units/ApparentPower.cs @@ -8,7 +8,7 @@ public readonly partial struct ApparentPower public static String Unit => "VA"; public static String Symbol => "S"; - public ApparentPower(Decimal value) + public ApparentPower(Double value) { if (value < 0) throw new ArgumentException("Apparent power cannot be negative", nameof(value)); Value = value; diff --git a/csharp/Lib/Units/ApparentPower.generated.cs b/csharp/Lib/Units/ApparentPower.generated.cs index 68d418277..d192def16 100644 --- a/csharp/Lib/Units/ApparentPower.generated.cs +++ b/csharp/Lib/Units/ApparentPower.generated.cs @@ -15,14 +15,14 @@ using T = ApparentPower; [JsonConverter(typeof(ApparentPowerConverter))] public readonly partial struct ApparentPower { - public Decimal Value { get; } + public Double Value { get; } public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit; // scalar multiplication - public static T operator *(Decimal scalar, T t) => new T(scalar * t.Value); - public static T operator *(T t, Decimal scalar) => new T(scalar * t.Value); - public static T operator /(T t, Decimal scalar) => new T(t.Value / scalar); + public static T operator *(Double scalar, T t) => new T(scalar * t.Value); + public static T operator *(T t, Double scalar) => new T(scalar * t.Value); + public static T operator /(T t, Double scalar) => new T(t.Value / scalar); // addition @@ -41,10 +41,7 @@ public readonly partial struct ApparentPower // conversion - public static implicit operator T(Decimal d) => new T(d); - public static implicit operator T(Double d) => new T((Decimal)d); - public static implicit operator T(Int32 i) => new T(i); - public static implicit operator Decimal(T t) => t.Value; + public static implicit operator T(Double d) => new T(d); // equality @@ -59,7 +56,7 @@ internal class ApparentPowerConverter : JsonConverter { public override ApparentPower Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - return new ApparentPower(reader.GetDecimal()); + return new ApparentPower(reader.GetDouble()); } public override void Write(Utf8JsonWriter writer, ApparentPower value, JsonSerializerOptions options) diff --git a/csharp/Lib/Units/Composite/Ac1Bus.cs b/csharp/Lib/Units/Composite/Ac1Bus.cs index b968d72e9..23b81aec4 100644 --- a/csharp/Lib/Units/Composite/Ac1Bus.cs +++ b/csharp/Lib/Units/Composite/Ac1Bus.cs @@ -1,12 +1,26 @@ -using System.Diagnostics.CodeAnalysis; namespace InnovEnergy.Lib.Units.Composite; -public record Ac1Bus : AcPhase +public class Ac1Bus : AcPhase { - public Frequency Frequency { get; init; } + public Double Frequency { get; internal init; } - // [SuppressMessage("ReSharper", "RedundantCast")] + + public static Ac1Bus FromVoltageCurrentFrequencyPhi(Double voltageRms, + Double currentRms, + Double frequency, + Double phi) => new() + { + Frequency = frequency, + Current = currentRms, + Voltage = voltageRms, + Power = AcPower.FromVoltageCurrentPhi(voltageRms, currentRms, phi) + }; +} + + + + // [SuppressMessage("ReSharper", "RedundantCast")] // public static Ac1Bus operator |(Ac1Bus left, Ac1Bus right) // { // var f = left.Frequency | right.Frequency; @@ -19,9 +33,4 @@ public record Ac1Bus : AcPhase // Voltage = p.Voltage, // Phi = p.Phi // }; - // } - -} - - - + // } \ No newline at end of file diff --git a/csharp/Lib/Units/Composite/Ac3Bus.cs b/csharp/Lib/Units/Composite/Ac3Bus.cs index bdd505a07..358cc2af8 100644 --- a/csharp/Lib/Units/Composite/Ac3Bus.cs +++ b/csharp/Lib/Units/Composite/Ac3Bus.cs @@ -1,19 +1,16 @@ -using static DecimalMath.DecimalEx; namespace InnovEnergy.Lib.Units.Composite; #pragma warning disable CS8618 -public record Ac3Bus +public class Ac3Bus { - public AcPhase L1 { get; init; } - public AcPhase L2 { get; init; } - public AcPhase L3 { get; init; } - public Frequency Frequency { get; init; } + public AcPhase L1 { get; internal init; } + public AcPhase L2 { get; internal init; } + public AcPhase L3 { get; internal init; } - public ApparentPower ApparentPower => L1.ApparentPower + L2.ApparentPower + L3.ApparentPower; - public ReactivePower ReactivePower => L1.ReactivePower + L2.ReactivePower + L3.ReactivePower; - public Power ActivePower => L1.ActivePower + L2.ActivePower + L3.ActivePower; - public Angle Phi => ATan2(ReactivePower, ActivePower); + public AcPower Power { get; internal init; } + + public Double Frequency { get; internal init; } } \ No newline at end of file diff --git a/csharp/Lib/Units/Composite/AcPhase.cs b/csharp/Lib/Units/Composite/AcPhase.cs index d57b68aa8..da0023fcc 100644 --- a/csharp/Lib/Units/Composite/AcPhase.cs +++ b/csharp/Lib/Units/Composite/AcPhase.cs @@ -1,66 +1,8 @@ -using static DecimalMath.DecimalEx; - namespace InnovEnergy.Lib.Units.Composite; +#pragma warning disable CS8618 -public record AcPhase : IBus +public class AcPhase : Bus { - private readonly Voltage _Voltage; - public Voltage Voltage - { - get => _Voltage; - init => _Voltage = value >= 0m ? value : throw new ArgumentException("RMS value cannot be negative"); - } - - private readonly Current _Current; - public Current Current - { - get => _Current; - init => _Current = value >= 0m ? value : throw new ArgumentException("RMS value cannot be negative"); - } - - public Angle Phi { get; init; } - - public ApparentPower ApparentPower => Voltage.Value * Current.Value ; - public Power ActivePower => ApparentPower.Value * PowerFactor; - public ReactivePower ReactivePower => ApparentPower.Value * Sin(Phi); - public Decimal PowerFactor => Cos(Phi); - - - // public static AcPhase operator |(AcPhase left, AcPhase right) - // { - // // the Voltages of two phases are expected to be in phase and equal - // - // var v = left.Voltage | right.Voltage; - // - // // currents (RMS) can be different and out of phase - // // https://www.johndcook.com/blog/2020/08/17/adding-phase-shifted-sine-waves/ - // - // // IF - // // left(t) = ILeft sin(ωt) - // // right(t) = IRight sin(ωt + φ). - // // sum(t) = left(t) + right(t) = ISum sin(ωt + ψ). - // - // // THEN - // // ψ = arctan( IRight * sin(φ) / (ILeft + IRight cos(φ)) ). - // // C = IRight * sin(φ) / sin(ψ). - // - // // in this calculation left(t) has zero phase shift. - // // we can shift both waves by -left.Phi, so - // // φ := right.phi - left.phi - // - // - // var phi = right.Phi - left.Phi; - // var phiSum = ATan2(right.Current * Sin(phi), left.Current + right.Current * Cos(phi)); - // var iSum = right.Current * Sin(phi) / Sin(phiSum); - // - // return new AcPhase - // { - // Voltage = v, - // Current = iSum, - // Phi = phiSum - // }; - // } - - + public AcPower Power { get; internal init; } } \ No newline at end of file diff --git a/csharp/Lib/Units/Composite/AcPower.cs b/csharp/Lib/Units/Composite/AcPower.cs new file mode 100644 index 000000000..e9302be3e --- /dev/null +++ b/csharp/Lib/Units/Composite/AcPower.cs @@ -0,0 +1,34 @@ +using static System.Math; + +namespace InnovEnergy.Lib.Units.Composite; + +public class AcPower +{ + public Double Apparent { get; internal init; } + public Double Active { get; internal init; } + public Double Reactive { get; internal init; } + public Double Phi { get; internal init; } + public Double CosPhi { get; internal init; } + + public static AcPower FromVoltageCurrentPhi(Double voltageRms, Double currentRms, Double phi) + { + if (voltageRms < 0) throw new ArgumentException("RMS value cannot be negative", nameof(voltageRms)); + if (currentRms < 0) throw new ArgumentException("RMS value cannot be negative", nameof(currentRms)); + + phi = NormalizePhi(phi); + + var cosPhi = Cos(phi); + var apparent = voltageRms * currentRms; + + return new AcPower + { + Apparent = apparent, + Active = apparent * cosPhi, + Reactive = apparent * Sin(phi), + Phi = phi, + CosPhi = cosPhi + }; + } + + private static Double NormalizePhi(Double phi) => (phi + PI) % Tau - PI; // Tau is 2pi +} \ No newline at end of file diff --git a/csharp/Lib/Units/Composite/IBus.cs b/csharp/Lib/Units/Composite/Bus.cs similarity index 53% rename from csharp/Lib/Units/Composite/IBus.cs rename to csharp/Lib/Units/Composite/Bus.cs index 8b9694972..7562c1c3b 100644 --- a/csharp/Lib/Units/Composite/IBus.cs +++ b/csharp/Lib/Units/Composite/Bus.cs @@ -4,8 +4,8 @@ namespace InnovEnergy.Lib.Units.Composite; [SuppressMessage("ReSharper", "MemberCanBeProtected.Global")] -public interface IBus +public abstract class Bus { - public Voltage Voltage { get; } - public Current Current { get; } + public Double Voltage { get; internal init; } + public Double Current { get; internal init; } } \ No newline at end of file diff --git a/csharp/Lib/Units/Composite/DcBus.cs b/csharp/Lib/Units/Composite/DcBus.cs index 8fbdd9802..efcf436b8 100644 --- a/csharp/Lib/Units/Composite/DcBus.cs +++ b/csharp/Lib/Units/Composite/DcBus.cs @@ -1,9 +1,13 @@ namespace InnovEnergy.Lib.Units.Composite; -public record DcBus : IBus +public class DcBus : Bus { - public Voltage Voltage { get; init; } - public Current Current { get; init; } - - public Power Power => Current * Voltage; + public Double Power { get; internal init; } + + public static DcBus FromVoltageCurrent(Double voltage, Double current) => new() + { + Voltage = voltage, + Current = current, + Power = current * voltage, + }; } \ No newline at end of file diff --git a/csharp/Lib/Units/Current.cs b/csharp/Lib/Units/Current.cs index 07b473c24..997fb5428 100644 --- a/csharp/Lib/Units/Current.cs +++ b/csharp/Lib/Units/Current.cs @@ -8,7 +8,7 @@ public readonly partial struct Current public static String Unit => "A"; public static String Symbol => "I"; - public Current(Decimal value) => Value = value; + public Current(Double value) => Value = value; // P=UI public static Power operator *(Current current, Voltage voltage) => new Power(current.Value * voltage.Value); diff --git a/csharp/Lib/Units/Current.generated.cs b/csharp/Lib/Units/Current.generated.cs index b8b19963c..6496827fe 100644 --- a/csharp/Lib/Units/Current.generated.cs +++ b/csharp/Lib/Units/Current.generated.cs @@ -15,14 +15,14 @@ using T = Current; [JsonConverter(typeof(CurrentConverter))] public readonly partial struct Current { - public Decimal Value { get; } + public Double Value { get; } public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit; // scalar multiplication - public static T operator *(Decimal scalar, T t) => new T(scalar * t.Value); - public static T operator *(T t, Decimal scalar) => new T(scalar * t.Value); - public static T operator /(T t, Decimal scalar) => new T(t.Value / scalar); + public static T operator *(Double scalar, T t) => new T(scalar * t.Value); + public static T operator *(T t, Double scalar) => new T(scalar * t.Value); + public static T operator /(T t, Double scalar) => new T(t.Value / scalar); // addition @@ -41,10 +41,7 @@ public readonly partial struct Current // conversion - public static implicit operator T(Decimal d) => new T(d); - public static implicit operator T(Double d) => new T((Decimal)d); - public static implicit operator T(Int32 i) => new T(i); - public static implicit operator Decimal(T t) => t.Value; + public static implicit operator T(Double d) => new T(d); // equality @@ -59,7 +56,7 @@ internal class CurrentConverter : JsonConverter { public override Current Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - return new Current(reader.GetDecimal()); + return new Current(reader.GetDouble()); } public override void Write(Utf8JsonWriter writer, Current value, JsonSerializerOptions options) diff --git a/csharp/Lib/Units/Energy.cs b/csharp/Lib/Units/Energy.cs index ab05ba6c4..f949f9975 100644 --- a/csharp/Lib/Units/Energy.cs +++ b/csharp/Lib/Units/Energy.cs @@ -9,8 +9,8 @@ public readonly partial struct Energy public static String Unit => "kWh"; public static String Symbol => "E"; - public Energy(Decimal value) => Value = value; + public Energy(Double value) => Value = value; - public static Power operator /(Energy energy, TimeSpan timeSpan) => energy.Value * 1000m / (Decimal) timeSpan.TotalHours ; - public static Power operator /(Energy energy, UnixTimeSpan timeSpan) => energy.Value * 3_600_000m / timeSpan.Ticks; + public static Power operator /(Energy energy, TimeSpan timeSpan) => energy.Value * 1000 / timeSpan.TotalHours ; + public static Power operator /(Energy energy, UnixTimeSpan timeSpan) => energy.Value * 3_600_000 / timeSpan.Ticks; } \ No newline at end of file diff --git a/csharp/Lib/Units/Energy.generated.cs b/csharp/Lib/Units/Energy.generated.cs index dabe6ed16..9e8a95005 100644 --- a/csharp/Lib/Units/Energy.generated.cs +++ b/csharp/Lib/Units/Energy.generated.cs @@ -15,14 +15,14 @@ using T = Energy; [JsonConverter(typeof(EnergyConverter))] public readonly partial struct Energy { - public Decimal Value { get; } + public Double Value { get; } public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit; // scalar multiplication - public static T operator *(Decimal scalar, T t) => new T(scalar * t.Value); - public static T operator *(T t, Decimal scalar) => new T(scalar * t.Value); - public static T operator /(T t, Decimal scalar) => new T(t.Value / scalar); + public static T operator *(Double scalar, T t) => new T(scalar * t.Value); + public static T operator *(T t, Double scalar) => new T(scalar * t.Value); + public static T operator /(T t, Double scalar) => new T(t.Value / scalar); // addition @@ -41,10 +41,7 @@ public readonly partial struct Energy // conversion - public static implicit operator T(Decimal d) => new T(d); - public static implicit operator T(Double d) => new T((Decimal)d); - public static implicit operator T(Int32 i) => new T(i); - public static implicit operator Decimal(T t) => t.Value; + public static implicit operator T(Double d) => new T(d); // equality @@ -59,7 +56,7 @@ internal class EnergyConverter : JsonConverter { public override Energy Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - return new Energy(reader.GetDecimal()); + return new Energy(reader.GetDouble()); } public override void Write(Utf8JsonWriter writer, Energy value, JsonSerializerOptions options) diff --git a/csharp/Lib/Units/Frequency.cs b/csharp/Lib/Units/Frequency.cs index f34b83334..6f7e2c075 100644 --- a/csharp/Lib/Units/Frequency.cs +++ b/csharp/Lib/Units/Frequency.cs @@ -9,7 +9,7 @@ public readonly partial struct Frequency public static String Unit => "Hz"; public static String Symbol => "f"; - public Frequency(Decimal value) + public Frequency(Double value) { if (value < 0) throw new ArgumentException(nameof(Frequency) + " cannot be negative", nameof(value)); diff --git a/csharp/Lib/Units/Frequency.generated.cs b/csharp/Lib/Units/Frequency.generated.cs index 6bdfb8ded..06e4d7fce 100644 --- a/csharp/Lib/Units/Frequency.generated.cs +++ b/csharp/Lib/Units/Frequency.generated.cs @@ -15,14 +15,14 @@ using T = Frequency; [JsonConverter(typeof(FrequencyConverter))] public readonly partial struct Frequency { - public Decimal Value { get; } + public Double Value { get; } public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit; // scalar multiplication - public static T operator *(Decimal scalar, T t) => new T(scalar * t.Value); - public static T operator *(T t, Decimal scalar) => new T(scalar * t.Value); - public static T operator /(T t, Decimal scalar) => new T(t.Value / scalar); + public static T operator *(Double scalar, T t) => new T(scalar * t.Value); + public static T operator *(T t, Double scalar) => new T(scalar * t.Value); + public static T operator /(T t, Double scalar) => new T(t.Value / scalar); // addition @@ -41,10 +41,7 @@ public readonly partial struct Frequency // conversion - public static implicit operator T(Decimal d) => new T(d); - public static implicit operator T(Double d) => new T((Decimal)d); - public static implicit operator T(Int32 i) => new T(i); - public static implicit operator Decimal(T t) => t.Value; + public static implicit operator T(Double d) => new T(d); // equality @@ -59,7 +56,7 @@ internal class FrequencyConverter : JsonConverter { public override Frequency Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - return new Frequency(reader.GetDecimal()); + return new Frequency(reader.GetDouble()); } public override void Write(Utf8JsonWriter writer, Frequency value, JsonSerializerOptions options) diff --git a/csharp/Lib/Units/Generator/Template.txt b/csharp/Lib/Units/Generator/Template.txt index c23e0820a..d88787a50 100644 --- a/csharp/Lib/Units/Generator/Template.txt +++ b/csharp/Lib/Units/Generator/Template.txt @@ -15,14 +15,14 @@ using T = Template; [JsonConverter(typeof(TemplateConverter))] public readonly partial struct Template { - public Decimal Value { get; } + public Double Value { get; } public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit; // scalar multiplication - public static T operator *(Decimal scalar, T t) => new T(scalar * t.Value); - public static T operator *(T t, Decimal scalar) => new T(scalar * t.Value); - public static T operator /(T t, Decimal scalar) => new T(t.Value / scalar); + public static T operator *(Double scalar, T t) => new T(scalar * t.Value); + public static T operator *(T t, Double scalar) => new T(scalar * t.Value); + public static T operator /(T t, Double scalar) => new T(t.Value / scalar); // addition @@ -41,10 +41,7 @@ public readonly partial struct Template // conversion - public static implicit operator T(Decimal d) => new T(d); - public static implicit operator T(Double d) => new T((Decimal)d); - public static implicit operator T(Int32 i) => new T(i); - public static implicit operator Decimal(T t) => t.Value; + public static implicit operator T(Double d) => new T(d); // equality @@ -59,7 +56,7 @@ internal class TemplateConverter : JsonConverter