move Phases from StatusApi.csproj to Units.csproj

This commit is contained in:
ig 2023-02-26 10:38:28 +01:00
parent 13942bfaf5
commit fd1b479783
60 changed files with 596 additions and 398 deletions

View File

@ -61,7 +61,7 @@ EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Backend", "App/Backend/Backend.csproj", "{A56F58C2-B265-435B-A985-53B4D6F49B1A}"
EndProject
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StatusData", "Lib\StatusData\StatusData.csproj", "{C04FB6DA-23C6-46BB-9B21-8F4FBA32FFF7}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Units", "Lib\Units\Units.csproj", "{C04FB6DA-23C6-46BB-9B21-8F4FBA32FFF7}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Meta", "Meta", "{AED84693-C389-44C9-B2C0-ACB560189CF2}"
ProjectSection(SolutionItems) = preProject

View File

@ -1,6 +1,8 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeEditing/SuppressNullableWarningFix/Enabled/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Interfaces/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:Boolean x:Key="/Default/CodeEditing/SuppressNullableWarningFix/Enabled/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=AMPT/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=backfill/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=beaglebone/@EntryIndexedValue">True</s:Boolean>
@ -34,4 +36,5 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=ttyusb/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=tupled/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=victronenergy/@EntryIndexedValue">True</s:Boolean>
</wpf:ResourceDictionary>

View File

@ -0,0 +1,7 @@
using InnovEnergy.Lib.StatusApi.Connections;
using InnovEnergy.Lib.Units.Composite;
namespace InnovEnergy.Lib.StatusApi;
public abstract record BatteryStatus(DcPhase Dc) : DeviceStatus, IDcConnection;

View File

@ -1,8 +0,0 @@
using InnovEnergy.Lib.StatusApi.Phases;
namespace InnovEnergy.Lib.StatusApi.Connections;
public record DcConnection(Decimal Voltage, Decimal Current) : Phase(Voltage, Current)
{
public Decimal Power => (Current * Voltage).Round3();
}

View File

@ -0,0 +1,8 @@
using InnovEnergy.Lib.Units.Composite;
namespace InnovEnergy.Lib.StatusApi.Connections;
public interface IAc1Connection
{
Ac1Phase Ac1 { get; }
}

View File

@ -0,0 +1,8 @@
using InnovEnergy.Lib.Units.Composite;
namespace InnovEnergy.Lib.StatusApi.Connections;
public interface IAc3Connection
{
Ac1Phase Ac3 { get; }
}

View File

@ -0,0 +1,9 @@
using InnovEnergy.Lib.Units.Composite;
namespace InnovEnergy.Lib.StatusApi.Connections;
public interface IDcConnection
{
DcPhase Dc { get; }
}

View File

@ -0,0 +1,8 @@
using InnovEnergy.Lib.Units.Composite;
namespace InnovEnergy.Lib.StatusApi.Connections;
public interface IPvConnection
{
IReadOnlyList<DcPhase> Strings { get; }
}

View File

@ -1,12 +0,0 @@
using InnovEnergy.Lib.StatusApi.Phases;
namespace InnovEnergy.Lib.StatusApi.Connections;
public record SinglePhaseAcConnection
(
Decimal Voltage,
Decimal Current,
Decimal Phi,
Decimal Frequency
);
//: AcPhase(Voltage, Current, Phi);

View File

@ -1,10 +0,0 @@
using InnovEnergy.Lib.StatusApi.Phases;
namespace InnovEnergy.Lib.StatusApi.Connections;
public record ThreePhaseAcConnection(AcPhase L1, AcPhase L2, AcPhase L3, Decimal Frequency)
{
public Decimal ApparentPower => L1.ApparentPower + L2.ApparentPower + L3.ApparentPower;
public Decimal ReactivePower => L1.ReactivePower + L2.ReactivePower + L3.ReactivePower;
public Decimal ActivePower => L1.ActivePower + L2.ActivePower + L3.ActivePower;
}

View File

@ -0,0 +1,8 @@
using InnovEnergy.Lib.Units.Composite;
namespace InnovEnergy.Lib.StatusApi;
public abstract record DcDcConverterStatus(DcPhase Left, DcPhase Right) : DeviceStatus;

View File

@ -1,6 +1,6 @@
namespace InnovEnergy.Lib.StatusApi.Devices;
namespace InnovEnergy.Lib.StatusApi;
public abstract record Device
public abstract record DeviceStatus
{
public String DeviceType
{
@ -11,7 +11,7 @@ public abstract record Device
while (!t!.IsAbstract)
t = t.BaseType;
return t.Name;
return t.Name.Replace("Status", "");
}
}
}

View File

@ -1,34 +0,0 @@
namespace InnovEnergy.Lib.StatusApi;
/// SIGN CONVENTION
///
/// Voltages have to be measured/indicated so that they are guaranteed to be never negative.
/// In the case of AC this is accomplished by using the RMS measurement.
/// The sign convention of the current (and hence power, since voltage defined to be never negative)
/// depends on the type of the device.
/// If the device can only produce (e.g. PV) or only consume (e.g. Loads),
/// then the current has to be 0 or positive.
/// If the device is a prosumer (e.g. inverter, battery, grid...)
/// then a positive sign denotes current (power) flow away from the grid (to the "right")
/// and a negative sign denotes current (power) flow towards the grid (to the "left")
/// the currently known DeviceTypes, to be serialized as string in JSON
public enum DeviceType
{
None,
PvOnAcIn ,
PvOnAcOut ,
PvOnDc ,
Load ,
CriticalLoad,
Battery ,
Grid ,
Inverter ,
AcInToAcOut ,
DcDc ,
DcLoad ,
Losses
}

View File

@ -1,12 +0,0 @@
using InnovEnergy.Lib.StatusApi.Connections;
namespace InnovEnergy.Lib.StatusApi.Devices;
public abstract record Battery
(
DcConnection Dc,
Decimal Soc,
Decimal Temperature
)
: DcDevice(Dc);

View File

@ -1,10 +0,0 @@
using InnovEnergy.Lib.StatusApi.Connections;
namespace InnovEnergy.Lib.StatusApi.Devices;
public abstract record DcDcConverter
(
DcConnection Left,
DcConnection Right
)
: Device;

View File

@ -1,5 +0,0 @@
using InnovEnergy.Lib.StatusApi.Connections;
namespace InnovEnergy.Lib.StatusApi.Devices;
public abstract record DcDevice(DcConnection Dc) : Device;

View File

@ -1,5 +0,0 @@
using InnovEnergy.Lib.StatusApi.Connections;
namespace InnovEnergy.Lib.StatusApi.Devices;
public abstract record GridMeter(ThreePhaseAcConnection Ac) : ThreePhaseAcDevice(Ac);

View File

@ -1,8 +0,0 @@
using InnovEnergy.Lib.StatusApi.Connections;
namespace InnovEnergy.Lib.StatusApi.Devices;
public interface IPvCoupledDevice
{
IReadOnlyList<DcConnection> Strings { get; }
}

View File

@ -1,10 +0,0 @@
using InnovEnergy.Lib.StatusApi.Connections;
namespace InnovEnergy.Lib.StatusApi.Devices;
public abstract record Mppt
(
DcConnection Dc,
IReadOnlyList<DcConnection> Strings
)
: DcDevice(Dc), IPvCoupledDevice;

View File

@ -1,6 +0,0 @@
using InnovEnergy.Lib.StatusApi.Connections;
namespace InnovEnergy.Lib.StatusApi.Devices;
public abstract record SinglePhaseAcDevice(SinglePhaseAcConnection Ac) : Device;

View File

@ -1,7 +0,0 @@
using InnovEnergy.Lib.StatusApi.Connections;
namespace InnovEnergy.Lib.StatusApi.Devices;
public abstract record SinglePhaseInverter(SinglePhaseAcConnection Ac, DcConnection Dc);

View File

@ -1,10 +0,0 @@
using InnovEnergy.Lib.StatusApi.Connections;
namespace InnovEnergy.Lib.StatusApi.Devices;
public abstract record SinglePhasePvInverter
(
SinglePhaseAcConnection Ac,
IReadOnlyList<DcConnection> Strings
)
: SinglePhaseAcDevice(Ac), IPvCoupledDevice;

View File

@ -1,5 +0,0 @@
using InnovEnergy.Lib.StatusApi.Connections;
namespace InnovEnergy.Lib.StatusApi.Devices;
public abstract record ThreePhaseAcDevice(ThreePhaseAcConnection Ac) : Device;

View File

@ -1,12 +0,0 @@
using InnovEnergy.Lib.StatusApi.Connections;
namespace InnovEnergy.Lib.StatusApi.Devices;
public abstract record ThreePhaseInverter
(
ThreePhaseAcConnection Ac,
DcConnection Dc
)
: Device;

View File

@ -1,10 +0,0 @@
using InnovEnergy.Lib.StatusApi.Connections;
namespace InnovEnergy.Lib.StatusApi.Devices;
public abstract record ThreePhasePvInverter
(
ThreePhaseAcConnection Ac,
IReadOnlyList<DcConnection> Strings
)
: ThreePhaseAcDevice(Ac), IPvCoupledDevice;

View File

@ -0,0 +1,8 @@
using InnovEnergy.Lib.StatusApi.Connections;
using InnovEnergy.Lib.Units.Composite;
namespace InnovEnergy.Lib.StatusApi;
public record MpptStatus(DcPhase Dc, IReadOnlyList<DcPhase> Strings) : IDcConnection, IPvConnection;

View File

@ -1,35 +0,0 @@
using static DecimalMath.DecimalEx;
namespace InnovEnergy.Lib.StatusApi.Phases;
public record AcPhase(Decimal Voltage, Decimal Current, Decimal Phi)
: Phase(Voltage, Current)
{
public Decimal ApparentPower => Voltage * Current;
public Decimal ActivePower => ApparentPower * PowerFactor;
public Decimal ReactivePower => ApparentPower * Sin(Phi);
public Decimal PowerFactor => Cos(Phi);
public static AcPhase FromActiveReactive
(
Decimal activePower,
Decimal reactivePower,
Decimal voltage,
Decimal current
)
{
var phi = ATan2(reactivePower, activePower);
return new AcPhase
(
Voltage: voltage,
Current: current,
Phi: phi
);
}
}

View File

@ -1,12 +0,0 @@
namespace InnovEnergy.Lib.StatusApi.Phases;
/// A phase must have at least a known Voltage and Current.
/// For DC this is already enough.
/// For AC the values have to be in RMS (not amplitude or P2P)
/// Power can be inferred, P = UI
public abstract record Phase
(
Decimal Voltage,
Decimal Current
);

View File

@ -0,0 +1,6 @@
using InnovEnergy.Lib.StatusApi.Connections;
using InnovEnergy.Lib.Units.Composite;
namespace InnovEnergy.Lib.StatusApi;
public abstract record PowerMeterStatus(Ac1Phase Ac3) : DeviceStatus, IAc3Connection;

View File

@ -0,0 +1,9 @@
using InnovEnergy.Lib.StatusApi.Connections;
using InnovEnergy.Lib.Units.Composite;
namespace InnovEnergy.Lib.StatusApi;
public abstract record SinglePhaseInverterStatus(Ac1Phase Ac1, DcPhase Dc) :
DeviceStatus,
IAc1Connection,
IDcConnection;

View File

@ -0,0 +1,9 @@
using InnovEnergy.Lib.StatusApi.Connections;
using InnovEnergy.Lib.Units.Composite;
namespace InnovEnergy.Lib.StatusApi;
public abstract record SinglePhasePvInverterStatus(Ac1Phase Ac1, IReadOnlyList<DcPhase> Strings) :
DeviceStatus,
IAc1Connection,
IPvConnection;

View File

@ -3,6 +3,7 @@
<ItemGroup>
<ProjectReference Include="../Protocols/Modbus/Modbus.csproj" />
<ProjectReference Include="..\Units\Units.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,10 @@
using InnovEnergy.Lib.StatusApi.Connections;
using InnovEnergy.Lib.Units.Composite;
namespace InnovEnergy.Lib.StatusApi;
public abstract record ThreePhaseInverterStatus(Ac1Phase Ac3, DcPhase Dc) :
DeviceStatus,
IAc3Connection,
IDcConnection;

View File

@ -0,0 +1,9 @@
using InnovEnergy.Lib.StatusApi.Connections;
using InnovEnergy.Lib.Units.Composite;
namespace InnovEnergy.Lib.StatusApi;
public abstract record ThreePhasePvInverterStatus(Ac1Phase Ac3, IReadOnlyList<DcPhase> Strings) :
DeviceStatus,
IAc3Connection,
IPvConnection;

View File

@ -1,32 +0,0 @@
namespace InnovEnergy.Lib.StatusData;
public readonly struct Current
{
public static String Unit => "A";
public static String Symbol => "I";
public Decimal Value { get; }
public Current(Decimal value) => Value = value;
public override String ToString() => Value + Unit;
// parallel
public static Current operator |(Current left, Current right) => new Current(left.Value + right.Value);
// scalar multiplication
public static Current operator *(Decimal scalar , Current current) => new Current(scalar * current.Value);
public static Current operator *(Current current, Decimal scalar) => new Current(scalar * current.Value);
public static Current operator *(Int32 scalar , Current current) => new Current(scalar * current.Value);
public static Current operator *(Current current, Int32 scalar) => new Current(scalar * current.Value);
public static Current operator /(Current current, Decimal scalar) => new Current(current.Value / scalar);
public static Current operator /(Current current, Int32 scalar) => new Current(current.Value / scalar);
// P=UI
public static Power operator *(Current current, Voltage voltage) => new Power(current.Value * voltage.Value);
// U=RI
public static Voltage operator *(Current current, Resistance resistance) => new Voltage(resistance.Value* current.Value);
}

View File

@ -1,16 +0,0 @@
using System.Text.Json.Serialization;
using InnovEnergy.Lib.StatusData.Json;
// ReSharper disable once CheckNamespace
namespace InnovEnergy.Units;
public static partial class Units
{
public static IReadOnlyList<JsonConverter> JsonConverters = new JsonConverter[]
{
new CurrentConverter(),
new VoltageConverter(),
new PowerConverter(),
new ResistanceConverter()
};
}

View File

@ -1,33 +0,0 @@
using InnovEnergy.Units;
namespace InnovEnergy.Lib.StatusData;
public readonly struct Power
{
public static String Unit => "W";
public static String Symbol => "P";
public Decimal Value { get; }
public Power(Decimal value) => Value = value;
public override String ToString() => Value + Unit;
// parallel
public static Power operator |(Power left, Power right) => new Power(left.Value + right.Value);
// series
public static Power operator +(Power left, Power right) => new Power(left.Value + right.Value);
// scalar multiplication
public static Power operator *(Decimal scalar, Power power ) => new Power(scalar * power.Value);
public static Power operator *(Power power , Decimal scalar) => new Power(scalar * power.Value);
public static Power operator *(Int32 scalar, Power power ) => new Power(scalar * power.Value);
public static Power operator *(Power power , Int32 scalar) => new Power(scalar * power.Value);
public static Power operator /(Power power , Decimal scalar) => new Power(power.Value / scalar);
public static Power operator /(Power power , Int32 scalar) => new Power(power.Value / scalar);
// P=UI
public static Voltage operator /(Power power, Current current) => new Voltage(power.Value / current.Value);
public static Current operator /(Power power, Voltage voltage) => new Current(power.Value / voltage.Value);
}

View File

@ -1,35 +0,0 @@
namespace InnovEnergy.Lib.StatusData;
public readonly struct Resistance
{
public static String Unit => "Ω";
public static String Symbol => "R";
public Decimal Value { get; }
public Resistance(Decimal value) => Value = value;
public override String ToString() => Value + Unit;
// series
public static Resistance operator +(Resistance left, Resistance right) => new Resistance(left.Value + right.Value);
// parallel
public static Resistance operator |(Resistance left, Resistance right) => new Resistance(1m / (1m / left.Value + 1m / right.Value));
// scalar multiplication
public static Resistance operator *(Decimal scalar , Resistance resistance) => new Resistance(scalar * resistance.Value);
public static Resistance operator *(Resistance resistance, Decimal scalar ) => new Resistance(scalar * resistance.Value);
public static Resistance operator *(Int32 scalar , Resistance resistance) => new Resistance(scalar * resistance.Value);
public static Resistance operator *(Resistance resistance, Int32 scalar ) => new Resistance(scalar * resistance.Value);
public static Resistance operator /(Resistance resistance, Decimal scalar ) => new Resistance(resistance.Value / scalar);
public static Resistance operator /(Resistance resistance, Int32 scalar ) => new Resistance(resistance.Value / scalar);
// U=RI
public static Voltage operator *(Resistance resistance, Current current) => new Voltage(resistance.Value* current.Value);
// public static Voltage operator /(Power power, Current current) => new Voltage(power.Value / current.Value);
// public static Current operator /(Power power, Voltage voltage) => new Current(power.Value / voltage.Value);
}

View File

@ -1,9 +0,0 @@
namespace InnovEnergy.Lib.StatusData;
public static partial class Units
{
public static Current A (this Decimal value) => new Current(value);
public static Voltage V (this Decimal value) => new Voltage(value);
public static Power W (this Decimal value) => new Power(value);
public static Resistance Ohm(this Decimal value) => new Resistance(value);
}

View File

@ -1,32 +0,0 @@
namespace InnovEnergy.Lib.StatusData;
public readonly struct Voltage
{
public static String Unit => "V";
public static String Symbol => "U";
public Decimal Value { get; }
public Voltage(Decimal value) => Value = value;
public override String ToString() => Value + Unit;
// series
public static Voltage operator +(Voltage left, Voltage right) => new Voltage(left.Value + right.Value);
public static Voltage operator *(Decimal scalar , Voltage voltage) => new Voltage(scalar * voltage.Value);
public static Voltage operator *(Voltage voltage, Decimal scalar) => new Voltage(scalar * voltage.Value);
public static Voltage operator *(Int32 scalar , Voltage voltage) => new Voltage(scalar * voltage.Value);
public static Voltage operator *(Voltage voltage, Int32 scalar) => new Voltage(scalar * voltage.Value);
public static Voltage operator /(Voltage voltage, Decimal scalar) => new Voltage(voltage.Value / scalar);
public static Voltage operator /(Voltage voltage, Int32 scalar) => new Voltage(voltage.Value / scalar);
// U=RI
public static Current operator /(Voltage voltage, Resistance resistance) => new Current(voltage.Value / resistance.Value);
// P=UI
public static Power operator *(Voltage voltage, Current current) => new Power(current.Value * voltage.Value);
}

73
csharp/Lib/Units/Angle.cs Normal file
View File

@ -0,0 +1,73 @@
using DecimalMath;
using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Units;
using T = Angle;
public readonly struct Angle
{
public static String Unit => "rad";
public static String Symbol => "∠";
public static readonly Angle Pi = new Angle(DecimalEx.Pi);
public Decimal Value { get; }
public Angle(Decimal value)
{
var modulo = value.Modulo(DecimalEx.TwoPi);
Value = modulo > DecimalEx.Pi
? modulo - DecimalEx.TwoPi
: modulo;
}
public override String ToString() => Value + Unit;
#region scalar multiplication
public static Angle operator *(Decimal scalar, Angle angle ) => new Angle(scalar * angle.Value);
public static Angle operator *(Angle angle , Decimal scalar) => new Angle(scalar * angle.Value);
public static Angle operator /(Angle angle , Decimal scalar) => new Angle(angle.Value / scalar);
#endregion
#region addition
public static T operator +(T left, T right) => new T(left.Value + right.Value);
public static T operator -(T left, T right) => new T(left.Value - right.Value);
public static T operator -(T t) => new T(-t.Value);
#endregion
#region compare
public static Boolean operator ==(T left, T right) => left.Value == right.Value;
public static Boolean operator !=(T left, T right) => left.Value != right.Value;
public static Boolean operator > (T left, T right) => left.Value > right.Value;
public static Boolean operator < (T left, T right) => left.Value < right.Value;
public static Boolean operator >=(T left, T right) => left.Value >= right.Value;
public static Boolean operator <=(T left, T right) => left.Value <= right.Value;
#endregion
#region 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;
#endregion
#region equality
public override Boolean Equals(Object? obj) => obj is T other && Equals(other);
public override Int32 GetHashCode() => Value.GetHashCode();
#endregion
}

View File

@ -0,0 +1,10 @@
namespace InnovEnergy.Lib.Units.Composite;
public record Ac1Phase
(
Voltage Voltage,
Current Current,
Angle Phi,
Frequency Frequency
) :
AcPhase(Voltage, Current, Phi);

View File

@ -0,0 +1,8 @@
namespace InnovEnergy.Lib.Units.Composite;
public record Ac3Phase(AcPhase L1, AcPhase L2, AcPhase L3, Decimal Frequency)
{
public Power ApparentPower => L1.ApparentPower + L2.ApparentPower + L3.ApparentPower;
public Power ReactivePower => L1.ReactivePower + L2.ReactivePower + L3.ReactivePower;
public Power ActivePower => L1.ActivePower + L2.ActivePower + L3.ActivePower;
}

View File

@ -0,0 +1,22 @@
using static DecimalMath.DecimalEx;
namespace InnovEnergy.Lib.Units.Composite;
public record AcPhase : Phase
{
protected AcPhase(Voltage voltage, Current current, Angle phi) : base(voltage, current)
{
if (voltage < 0) throw new ArgumentException("RMS value cannot be negative", nameof(voltage));
if (current < 0) throw new ArgumentException("RMS value cannot be negative", nameof(current));
Phi = phi;
}
public Angle Phi { get; }
public Power ApparentPower => Voltage * Current;
public Power ActivePower => ApparentPower * PowerFactor;
public Power ReactivePower => ApparentPower * Sin(Phi);
public Decimal PowerFactor => Cos(Phi);
}

View File

@ -0,0 +1,6 @@
namespace InnovEnergy.Lib.Units.Composite;
public record DcPhase(Voltage Voltage, Current Current) : Phase(Voltage, Current)
{
public Power Power => Current * Voltage;
}

View File

@ -0,0 +1,7 @@
namespace InnovEnergy.Lib.Units.Composite;
public abstract record Phase
(
Voltage Voltage,
Current Current
);

View File

@ -0,0 +1,59 @@
namespace InnovEnergy.Lib.Units;
using T = Frequency;
public readonly struct Frequency
{
public static String Unit => "Hz";
public static String Symbol => "f";
public Decimal Value { get; }
public Frequency(Decimal value) => Value = value;
public override String ToString() => Value + Unit;
#region 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);
#endregion
#region addition
public static T operator +(T left, T right) => new T(left.Value + right.Value);
public static T operator -(T left, T right) => new T(left.Value - right.Value);
public static T operator -(T t) => new T(-t.Value);
#endregion
#region compare
public static Boolean operator ==(T left, T right) => left.Value == right.Value;
public static Boolean operator !=(T left, T right) => left.Value != right.Value;
public static Boolean operator > (T left, T right) => left.Value > right.Value;
public static Boolean operator < (T left, T right) => left.Value < right.Value;
public static Boolean operator >=(T left, T right) => left.Value >= right.Value;
public static Boolean operator <=(T left, T right) => left.Value <= right.Value;
#endregion
#region 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;
#endregion
#region equality
public Boolean Equals(T other) => Value == other.Value;
public override Boolean Equals(Object? obj) => obj is T other && Equals(other);
public override Int32 GetHashCode() => Value.GetHashCode();
#endregion
}

View File

@ -1,7 +1,7 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace InnovEnergy.Lib.StatusData.Json;
namespace InnovEnergy.Lib.Units.Json;
public class CurrentConverter : JsonConverter<Current>
{

View File

@ -1,7 +1,7 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace InnovEnergy.Lib.StatusData.Json;
namespace InnovEnergy.Lib.Units.Json;
public class PowerConverter : JsonConverter<Power>
{

View File

@ -1,7 +1,7 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace InnovEnergy.Lib.StatusData.Json;
namespace InnovEnergy.Lib.Units.Json;
public class ResistanceConverter : JsonConverter<Current>
{

View File

@ -1,7 +1,7 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace InnovEnergy.Lib.StatusData.Json;
namespace InnovEnergy.Lib.Units.Json;
public class VoltageConverter : JsonConverter<Voltage>
{

66
csharp/Lib/Units/Power.cs Normal file
View File

@ -0,0 +1,66 @@
namespace InnovEnergy.Lib.Units;
using T = Power;
public readonly struct Power
{
public static String Unit => "W";
public static String Symbol => "P";
public Decimal Value { get; }
public Power(Decimal value) => Value = value;
public override String ToString() => Value + Unit;
// P=UI
public static Voltage operator /(Power power, Current current) => new Voltage(power.Value / current.Value);
public static Current operator /(Power power, Voltage voltage) => new Current(power.Value / voltage.Value);
#region 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);
#endregion
#region addition
public static T operator +(T left, T right) => new T(left.Value + right.Value);
public static T operator -(T left, T right) => new T(left.Value - right.Value);
public static T operator -(T t) => new T(-t.Value);
#endregion
#region compare
public static Boolean operator ==(T left, T right) => left.Value == right.Value;
public static Boolean operator !=(T left, T right) => left.Value != right.Value;
public static Boolean operator > (T left, T right) => left.Value > right.Value;
public static Boolean operator < (T left, T right) => left.Value < right.Value;
public static Boolean operator >=(T left, T right) => left.Value >= right.Value;
public static Boolean operator <=(T left, T right) => left.Value <= right.Value;
#endregion
#region 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;
#endregion
#region equality
public Boolean Equals(T other) => Value == other.Value;
public override Boolean Equals(Object? obj) => obj is T other && Equals(other);
public override Int32 GetHashCode() => Value.GetHashCode();
#endregion
}

View File

@ -0,0 +1,63 @@
namespace InnovEnergy.Lib.Units;
using T = Resistance;
public readonly struct Resistance
{
public static String Unit => "Ω";
public static String Symbol => "R";
public Decimal Value { get; }
public Resistance(Decimal value) => Value = value;
public override String ToString() => Value + Unit;
// U=RI
public static Voltage operator *(Resistance resistance, Current current) => new Voltage(resistance.Value * current.Value);
#region 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);
#endregion
#region addition
public static T operator +(T left, T right) => new T(left.Value + right.Value);
public static T operator -(T left, T right) => new T(left.Value - right.Value);
public static T operator -(T t) => new T(-t.Value);
#endregion
#region compare
public static Boolean operator ==(T left, T right) => left.Value == right.Value;
public static Boolean operator !=(T left, T right) => left.Value != right.Value;
public static Boolean operator > (T left, T right) => left.Value > right.Value;
public static Boolean operator < (T left, T right) => left.Value < right.Value;
public static Boolean operator >=(T left, T right) => left.Value >= right.Value;
public static Boolean operator <=(T left, T right) => left.Value <= right.Value;
#endregion
#region 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;
#endregion
#region equality
public Boolean Equals(T other) => Value == other.Value;
public override Boolean Equals(Object? obj) => obj is T other && Equals(other);
public override Int32 GetHashCode() => Value.GetHashCode();
#endregion
}

View File

@ -1,4 +1,4 @@
namespace InnovEnergy.Lib.StatusData;
namespace InnovEnergy.Lib.Units;
public readonly struct State
{
@ -9,13 +9,10 @@ public readonly struct State
public State(params String[] values) : this((IReadOnlyList<String>)values){}
public State(params State[] states) : this(states.SelectMany(s => s.Values).ToList()){}
public State(Enum e) : this(e.ToString())
{
}
public State(Enum e) : this(e.ToString()){}
public static implicit operator State(Enum e) => new State(e);
public static implicit operator State(String s) => new State(s);
// parallel
public static State operator |(State left, State right) => new State(left, right);
public static State operator +(State left, State right) => new State(left, right);
}

View File

@ -0,0 +1,61 @@
namespace InnovEnergy.Lib.Units;
using T = Temperature;
public readonly struct Temperature
{
public static String Unit => "°C";
public static String Symbol => "T";
public Decimal Value { get; }
public Temperature(Decimal value) => Value = value;
public override String ToString() => Value + Unit;
#region 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);
#endregion
#region addition
public static T operator +(T left, T right) => new T(left.Value + right.Value);
public static T operator -(T left, T right) => new T(left.Value - right.Value);
public static T operator -(T t) => new T(-t.Value);
#endregion
#region compare
public static Boolean operator ==(T left, T right) => left.Value == right.Value;
public static Boolean operator !=(T left, T right) => left.Value != right.Value;
public static Boolean operator > (T left, T right) => left.Value > right.Value;
public static Boolean operator < (T left, T right) => left.Value < right.Value;
public static Boolean operator >=(T left, T right) => left.Value >= right.Value;
public static Boolean operator <=(T left, T right) => left.Value <= right.Value;
#endregion
#region 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;
#endregion
#region equality
public Boolean Equals(T other) => Value == other.Value;
public override Boolean Equals(Object? obj) => obj is T other && Equals(other);
public override Int32 GetHashCode() => Value.GetHashCode();
#endregion
}

20
csharp/Lib/Units/Units.cs Normal file
View File

@ -0,0 +1,20 @@
using System.Text.Json.Serialization;
using InnovEnergy.Lib.Units.Json;
namespace InnovEnergy.Lib.Units;
public static class Units
{
public static Current A (this Decimal value) => new Current(value);
public static Voltage V (this Decimal value) => new Voltage(value);
public static Power W (this Decimal value) => new Power(value);
public static Resistance Ohm(this Decimal value) => new Resistance(value);
public static readonly IReadOnlyList<JsonConverter> JsonConverters = new JsonConverter[]
{
new CurrentConverter(),
new VoltageConverter(),
new PowerConverter(),
new ResistanceConverter()
};
}

View File

@ -6,4 +6,12 @@
<LangVersion>preview</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DecimalMath.DecimalEx" Version="1.0.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Utils\Utils.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,69 @@
namespace InnovEnergy.Lib.Units;
using T = Voltage;
public readonly struct Voltage
{
public static String Unit => "V";
public static String Symbol => "U";
public Decimal Value { get; }
public Voltage(Decimal value) => Value = value;
public override String ToString() => Value + Unit;
// U=RI
public static Current operator /(Voltage voltage, Resistance resistance) => new Current(voltage.Value / resistance.Value);
// P=UI
public static Power operator *(Voltage voltage, Current current) => new Power(current.Value * voltage.Value);
#region 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);
#endregion
#region addition
public static T operator +(T left, T right) => new T(left.Value + right.Value);
public static T operator -(T left, T right) => new T(left.Value - right.Value);
public static T operator -(T t) => new T(-t.Value);
#endregion
#region compare
public static Boolean operator ==(T left, T right) => left.Value == right.Value;
public static Boolean operator !=(T left, T right) => left.Value != right.Value;
public static Boolean operator > (T left, T right) => left.Value > right.Value;
public static Boolean operator < (T left, T right) => left.Value < right.Value;
public static Boolean operator >=(T left, T right) => left.Value >= right.Value;
public static Boolean operator <=(T left, T right) => left.Value <= right.Value;
#endregion
#region 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;
#endregion
#region equality
public Boolean Equals(T other) => Value == other.Value;
public override Boolean Equals(Object? obj) => obj is T other && Equals(other);
public override Int32 GetHashCode() => Value.GetHashCode();
#endregion
}

View File

@ -1,15 +0,0 @@
namespace InnovEnergy.Lib.Utils;
public static class Units
{
public static String Unit(this Object v, String unit) => $"{v} {unit}";
public static String V(this Object v) => v.Unit("V");
public static String W(this Object v) => v.Unit("W");
public static String A(this Object v) => v.Unit("A");
public static String Degrees(this Object v) => v.Unit("°");
public static String Celsius(this Object v) => v.Unit("°C");
public static String Percent(this Object v) => v.Unit("%");
}

View File

@ -79,6 +79,15 @@ public static class Utils
? res
: res + length;
}
public static Decimal Modulo(this Decimal dividend, Decimal divisor)
{
var res = dividend % divisor;
return res >= 0
? res
: res + divisor;
}
public static IEnumerable<T> Traverse<T>(this T root, Func<T, IEnumerable<T>> getChildren)
{