move Phases from StatusApi.csproj to Units.csproj
This commit is contained in:
parent
13942bfaf5
commit
fd1b479783
|
@ -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
|
||||
|
|
|
@ -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"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></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>
|
|
@ -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;
|
||||
|
|
@ -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();
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
using InnovEnergy.Lib.Units.Composite;
|
||||
|
||||
namespace InnovEnergy.Lib.StatusApi.Connections;
|
||||
|
||||
public interface IAc1Connection
|
||||
{
|
||||
Ac1Phase Ac1 { get; }
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
using InnovEnergy.Lib.Units.Composite;
|
||||
|
||||
namespace InnovEnergy.Lib.StatusApi.Connections;
|
||||
|
||||
public interface IAc3Connection
|
||||
{
|
||||
Ac1Phase Ac3 { get; }
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
using InnovEnergy.Lib.Units.Composite;
|
||||
|
||||
namespace InnovEnergy.Lib.StatusApi.Connections;
|
||||
|
||||
|
||||
public interface IDcConnection
|
||||
{
|
||||
DcPhase Dc { get; }
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
using InnovEnergy.Lib.Units.Composite;
|
||||
|
||||
namespace InnovEnergy.Lib.StatusApi.Connections;
|
||||
|
||||
public interface IPvConnection
|
||||
{
|
||||
IReadOnlyList<DcPhase> Strings { get; }
|
||||
}
|
|
@ -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);
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
using InnovEnergy.Lib.Units.Composite;
|
||||
|
||||
namespace InnovEnergy.Lib.StatusApi;
|
||||
|
||||
public abstract record DcDcConverterStatus(DcPhase Left, DcPhase Right) : DeviceStatus;
|
||||
|
||||
|
||||
|
|
@ -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", "");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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);
|
|
@ -1,10 +0,0 @@
|
|||
using InnovEnergy.Lib.StatusApi.Connections;
|
||||
|
||||
namespace InnovEnergy.Lib.StatusApi.Devices;
|
||||
|
||||
public abstract record DcDcConverter
|
||||
(
|
||||
DcConnection Left,
|
||||
DcConnection Right
|
||||
)
|
||||
: Device;
|
|
@ -1,5 +0,0 @@
|
|||
using InnovEnergy.Lib.StatusApi.Connections;
|
||||
|
||||
namespace InnovEnergy.Lib.StatusApi.Devices;
|
||||
|
||||
public abstract record DcDevice(DcConnection Dc) : Device;
|
|
@ -1,5 +0,0 @@
|
|||
using InnovEnergy.Lib.StatusApi.Connections;
|
||||
|
||||
namespace InnovEnergy.Lib.StatusApi.Devices;
|
||||
|
||||
public abstract record GridMeter(ThreePhaseAcConnection Ac) : ThreePhaseAcDevice(Ac);
|
|
@ -1,8 +0,0 @@
|
|||
using InnovEnergy.Lib.StatusApi.Connections;
|
||||
|
||||
namespace InnovEnergy.Lib.StatusApi.Devices;
|
||||
|
||||
public interface IPvCoupledDevice
|
||||
{
|
||||
IReadOnlyList<DcConnection> Strings { get; }
|
||||
}
|
|
@ -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;
|
|
@ -1,6 +0,0 @@
|
|||
using InnovEnergy.Lib.StatusApi.Connections;
|
||||
|
||||
namespace InnovEnergy.Lib.StatusApi.Devices;
|
||||
|
||||
|
||||
public abstract record SinglePhaseAcDevice(SinglePhaseAcConnection Ac) : Device;
|
|
@ -1,7 +0,0 @@
|
|||
using InnovEnergy.Lib.StatusApi.Connections;
|
||||
|
||||
namespace InnovEnergy.Lib.StatusApi.Devices;
|
||||
|
||||
public abstract record SinglePhaseInverter(SinglePhaseAcConnection Ac, DcConnection Dc);
|
||||
|
||||
|
|
@ -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;
|
|
@ -1,5 +0,0 @@
|
|||
using InnovEnergy.Lib.StatusApi.Connections;
|
||||
|
||||
namespace InnovEnergy.Lib.StatusApi.Devices;
|
||||
|
||||
public abstract record ThreePhaseAcDevice(ThreePhaseAcConnection Ac) : Device;
|
|
@ -1,12 +0,0 @@
|
|||
|
||||
|
||||
using InnovEnergy.Lib.StatusApi.Connections;
|
||||
|
||||
namespace InnovEnergy.Lib.StatusApi.Devices;
|
||||
|
||||
public abstract record ThreePhaseInverter
|
||||
(
|
||||
ThreePhaseAcConnection Ac,
|
||||
DcConnection Dc
|
||||
)
|
||||
: Device;
|
|
@ -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;
|
|
@ -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;
|
||||
|
||||
|
|
@ -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
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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
|
||||
);
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../Protocols/Modbus/Modbus.csproj" />
|
||||
<ProjectReference Include="..\Units\Units.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -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;
|
||||
|
|
@ -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;
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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()
|
||||
};
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
namespace InnovEnergy.Lib.Units.Composite;
|
||||
|
||||
public record Ac1Phase
|
||||
(
|
||||
Voltage Voltage,
|
||||
Current Current,
|
||||
Angle Phi,
|
||||
Frequency Frequency
|
||||
) :
|
||||
AcPhase(Voltage, Current, Phi);
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
namespace InnovEnergy.Lib.Units.Composite;
|
||||
|
||||
public record DcPhase(Voltage Voltage, Current Current) : Phase(Voltage, Current)
|
||||
{
|
||||
public Power Power => Current * Voltage;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
namespace InnovEnergy.Lib.Units.Composite;
|
||||
|
||||
public abstract record Phase
|
||||
(
|
||||
Voltage Voltage,
|
||||
Current Current
|
||||
);
|
|
@ -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
|
||||
}
|
|
@ -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>
|
||||
{
|
|
@ -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>
|
||||
{
|
|
@ -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>
|
||||
{
|
|
@ -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>
|
||||
{
|
|
@ -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
|
||||
|
||||
}
|
|
@ -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
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
||||
}
|
|
@ -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()
|
||||
};
|
||||
}
|
|
@ -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>
|
|
@ -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
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -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("%");
|
||||
|
||||
}
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue