convert composite units to records

This commit is contained in:
ig 2023-09-01 08:54:46 +02:00
parent be452d190c
commit 05f0a7e9f9
19 changed files with 220 additions and 344 deletions

View File

@ -250,8 +250,8 @@ internal static class Program
var nInverters = record.AcDc.Devices.Count;
var powerPerInverterPhase = nInverters > 0
? AcPower.FromActiveReactive(essControl.PowerSetpoint / nInverters / 3, 0)
: AcPower.FromActiveReactive(0,0);
? essControl.PowerSetpoint / nInverters / 3
: 0;
//var powerPerInverterPhase = AcPower.Null;

View File

@ -1,6 +1,7 @@
using InnovEnergy.Lib.Protocols.Modbus.Reflection.Attributes;
using InnovEnergy.Lib.StatusApi.DeviceTypes;
using InnovEnergy.Lib.Units.Composite;
using static System.Math;
#pragma warning disable CS0649
@ -20,10 +21,6 @@ public class EmuMeterRegisters : IAc3Meter
[HoldingRegister<Float32>(9014)] private Float32 _ReactivePowerL2;
[HoldingRegister<Float32>(9016)] private Float32 _ReactivePowerL3;
[HoldingRegister<Float32>(9022)] private Float32 _ApparentPowerL1;
[HoldingRegister<Float32>(9024)] private Float32 _ApparentPowerL2;
[HoldingRegister<Float32>(9026)] private Float32 _ApparentPowerL3;
[HoldingRegister<Float32>(9102)] private Float32 _CurrentL1;
[HoldingRegister<Float32>(9104)] private Float32 _CurrentL2;
[HoldingRegister<Float32>(9106)] private Float32 _CurrentL3;
@ -34,34 +31,28 @@ public class EmuMeterRegisters : IAc3Meter
[HoldingRegister<Float32>(9310)] private Float32 _Frequency;
public Ac3Bus Ac => Ac3Bus.FromPhasesAndFrequency
(
l1: AcPhase.FromVoltageCurrentActiveReactiveApparent
(
_VoltageL1N,
_CurrentL1,
_ActivePowerL1,
_ReactivePowerL1,
_ApparentPowerL1
),
l2: AcPhase.FromVoltageCurrentActiveReactiveApparent
(
_VoltageL2N,
_CurrentL2,
_ActivePowerL2,
_ReactivePowerL2,
_ApparentPowerL2
),
l3: AcPhase.FromVoltageCurrentActiveReactiveApparent
(
_VoltageL3N,
_CurrentL3,
_ActivePowerL3,
_ReactivePowerL3,
_ApparentPowerL3
),
frequency: _Frequency
);
public Ac3Bus Ac => new Ac3Bus
{
L1 = new ()
{
Current = _CurrentL1,
Voltage = _VoltageL1N,
Phi = Atan2(_ReactivePowerL1, _ActivePowerL1)
},
L2 = new ()
{
Current = _CurrentL2,
Voltage = _VoltageL2N,
Phi = Atan2(_ReactivePowerL2, _ActivePowerL2)
},
L3 = new ()
{
Current = _CurrentL3,
Voltage = _VoltageL3N,
Phi = Atan2(_ReactivePowerL3, _ActivePowerL3)
},
Frequency = _Frequency
};
}

View File

@ -39,35 +39,7 @@ public class Iem3KGridMeterRegisters : IAc3Meter
[HoldingRegister<Float32>(9310)] private Float32 _Frequency;
public Ac3Bus Ac => Ac3Bus.FromPhasesAndFrequency
(
l1: AcPhase.FromVoltageCurrentActiveReactiveApparent
(
_VoltageL1N,
_CurrentL1,
_ActivePowerL1,
_ReactivePowerL1,
_ApparentPowerL1
),
l2: AcPhase.FromVoltageCurrentActiveReactiveApparent
(
_VoltageL2N,
_CurrentL2,
_ActivePowerL2,
_ReactivePowerL2,
_ApparentPowerL2
),
l3: AcPhase.FromVoltageCurrentActiveReactiveApparent
(
_VoltageL3N,
_CurrentL3,
_ActivePowerL3,
_ReactivePowerL3,
_ApparentPowerL3
),
frequency: _Frequency
);
public Ac3Bus Ac => throw new NotImplementedException();
}

View File

@ -1,6 +1,7 @@
using InnovEnergy.Lib.Devices.Trumpf.SystemControl;
using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes;
using InnovEnergy.Lib.Units.Composite;
using static System.Math;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc;
@ -25,35 +26,57 @@ public class AcDcDevicesRecord
get
{
if (Devices.Count == 0)
return Ac3Bus.Null;
return Ac3Bus.Zero;
var l1 = AcPhase.FromVoltageCurrentActiveReactive
(
voltageRms : Devices.Average(d => d.Status.Ac.L1.Voltage),
currentRms : Devices.Sum(d => d.Status.Ac.L1.Current),
activePower : Devices.Sum(d => d.Status.Ac.L1.Power.Active),
reactivePower: Devices.Sum(d => d.Status.Ac.L1.Power.Reactive)
);
var ac = Devices
.Select(d => d.Status.Ac)
.ToList();
var l2 = AcPhase.FromVoltageCurrentActiveReactive
(
voltageRms : Devices.Average(d => d.Status.Ac.L2.Voltage),
currentRms : Devices.Sum(d => d.Status.Ac.L2.Current),
activePower : Devices.Sum(d => d.Status.Ac.L2.Power.Active),
reactivePower: Devices.Sum(d => d.Status.Ac.L2.Power.Reactive)
);
var f = ac.Average(d => d.Frequency);
var l3 = AcPhase.FromVoltageCurrentActiveReactive
(
voltageRms : Devices.Average(d => d.Status.Ac.L3.Voltage),
currentRms : Devices.Sum(d => d.Status.Ac.L3.Current),
activePower : Devices.Sum(d => d.Status.Ac.L3.Power.Active),
reactivePower: Devices.Sum(d => d.Status.Ac.L3.Power.Reactive)
);
var u1 = ac.Average(d => d.L1.Voltage);
var i1 = ac.Sum(d => d.L1.Current);
var q1 = ac.Sum(d => d.L1.Power.Reactive);
var p1 = ac.Sum(d => d.L1.Power.Active);
var f = Devices.Average(d => d.Status.Ac.Frequency);
var l1 = new AcPhase
{
Voltage = u1,
Current = i1,
Phi = Atan2(q1, p1)
};
return Ac3Bus.FromPhasesAndFrequency(l1, l2, l3, f);
var u2 = ac.Average(d => d.L2.Voltage);
var i2 = ac.Sum(d => d.L2.Current);
var q2 = ac.Sum(d => d.L2.Power.Reactive);
var p2 = ac.Sum(d => d.L2.Power.Active);
var l2 = new AcPhase
{
Voltage = u2,
Current = i2,
Phi = Atan2(q2, p2)
};
var u3 = ac.Average(d => d.L3.Voltage);
var i3 = ac.Sum(d => d.L3.Current);
var q3 = ac.Sum(d => d.L3.Power.Reactive);
var p3 = ac.Sum(d => d.L3.Power.Active);
var l3 = new AcPhase
{
Voltage = u3,
Current = i3,
Phi = Atan2(q3, p3)
};
return new Ac3Bus
{
L1 = l1,
L2 = l2,
L3 = l3,
Frequency = f,
};
}
}
@ -62,7 +85,7 @@ public class AcDcDevicesRecord
get
{
if (Devices.Count == 0)
return DcBus.Null;
return DcBus.Zero;
var u = Devices
.Select(d => d.Status.DcVoltages.Extern)

View File

@ -1,6 +1,7 @@
using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes;
using InnovEnergy.Lib.Units.Composite;
using InnovEnergy.Lib.Utils;
using static System.Math;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Control;
@ -13,17 +14,21 @@ public class AcPowerControl
var s = _Self.PowerSetpointL1;
var cosPhi = _Self.CosPhiSetpointL1.Clamp(-1, 1);
var rpk = _Self.ReactivePowerKindL1;
var phi = cosPhi.Apply(Math.Acos) * (rpk == ReactivePowerKind.Inductive ? 1 : -1);
var sinPhi = Math.Sin(phi);
var phi = Acos(cosPhi) * (rpk == ReactivePowerKind.Inductive ? 1 : -1);
var sinPhi = Sin(phi);
return AcPower.FromActiveReactive(s * cosPhi, s * sinPhi);
return new AcPower { Active = s * cosPhi, Reactive = s * sinPhi };
}
set
{
_Self.PowerSetpointL1 = value.Apparent.Value;
_Self.CosPhiSetpointL1 = value.CosPhi;
_Self.SinPhiSetpointL1 = Math.Sin(value.Phi);
var s = value.Apparent;
var p = value.Active;
var q = value.Reactive;
_Self.PowerSetpointL1 = s;
_Self.CosPhiSetpointL1 = s == 0 ? 1 : p / s;
_Self.SinPhiSetpointL1 = s == 0 ? 0 : q / s;
_Self.ReactivePowerKindL1 = value.Reactive >= 0
? ReactivePowerKind.Inductive
: ReactivePowerKind.Capacitive;
@ -38,23 +43,28 @@ public class AcPowerControl
var s = _Self.PowerSetpointL2;
var cosPhi = _Self.CosPhiSetpointL2.Clamp(-1, 1);
var rpk = _Self.ReactivePowerKindL2;
var phi = cosPhi.Apply(Math.Acos) * (rpk == ReactivePowerKind.Inductive ? 1 : -1);
var sinPhi = Math.Sin(phi);
var phi = Acos(cosPhi) * (rpk == ReactivePowerKind.Inductive ? 1 : -1);
var sinPhi = Sin(phi);
return AcPower.FromActiveReactive(s * cosPhi, s * sinPhi);
return new AcPower { Active = s * cosPhi, Reactive = s * sinPhi };
}
set
{
_Self.PowerSetpointL2 = value.Apparent.Value;
_Self.CosPhiSetpointL2 = value.CosPhi;
_Self.SinPhiSetpointL2 = Math.Sin(value.Phi);
var s = value.Apparent;
var p = value.Active;
var q = value.Reactive;
_Self.PowerSetpointL2 = s;
_Self.CosPhiSetpointL2 = s == 0 ? 1 : p / s;
_Self.SinPhiSetpointL2 = s == 0 ? 0 : q / s;
_Self.ReactivePowerKindL2 = value.Reactive >= 0
? ReactivePowerKind.Inductive
: ReactivePowerKind.Capacitive;
}
}
public AcPower L3
{
get
@ -62,17 +72,21 @@ public class AcPowerControl
var s = _Self.PowerSetpointL3;
var cosPhi = _Self.CosPhiSetpointL3.Clamp(-1, 1);
var rpk = _Self.ReactivePowerKindL3;
var phi = cosPhi.Apply(Math.Acos) * (rpk == ReactivePowerKind.Inductive ? 1 : -1);
var sinPhi = Math.Sin(phi);
var phi = Acos(cosPhi) * (rpk == ReactivePowerKind.Inductive ? 1 : -1);
var sinPhi = Sin(phi);
return AcPower.FromActiveReactive(s * cosPhi, s * sinPhi);
return new AcPower { Active = s * cosPhi, Reactive = s * sinPhi };
}
set
{
_Self.PowerSetpointL3 = value.Apparent.Value;
_Self.CosPhiSetpointL3 = value.CosPhi;
_Self.SinPhiSetpointL3 = Math.Sin(value.Phi);
var s = value.Apparent;
var p = value.Active;
var q = value.Reactive;
_Self.PowerSetpointL3 = s;
_Self.CosPhiSetpointL3 = s == 0 ? 1 : p / s;
_Self.SinPhiSetpointL3 = s == 0 ? 0 : q / s;
_Self.ReactivePowerKindL3 = value.Reactive >= 0
? ReactivePowerKind.Inductive
: ReactivePowerKind.Capacitive;

View File

@ -2,6 +2,7 @@
using InnovEnergy.Lib.Devices.Trumpf.SystemControl.DataTypes;
using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes;
using InnovEnergy.Lib.Units.Composite;
using static System.Math;
using AlarmMessage = InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes.AlarmMessage;
using WarningMessage = InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes.WarningMessage;
@ -9,7 +10,7 @@ namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Status;
public class AcDcStatus
{
public Ac3Bus Ac => Ac3Bus.FromPhasesAndFrequency(L1, L2, L3, _Self.GridFrequency);
public Ac3Bus Ac => new Ac3Bus { L1 = L1, L2 = L2, L3 = L3, Frequency = _Self.GridFrequency };
public PowerLimit PowerLimitedBy => _Self.PowerLimitedBy;
public InverterStates InverterState => new(_Self);
public GridType ActiveGridType => _Self.ActiveGridType;
@ -74,32 +75,28 @@ public class AcDcStatus
// TODO: there are no AcDc Warnings defined in doc
private static Boolean IsAcDcWarning(WarningMessage warning) => warning != WarningMessage.NoWarning;
private AcPhase L1 => AcPhase.FromVoltageCurrentActiveReactiveApparent
(
voltageRms : _Self.GridVoltageL1,
currentRms : _Self.GridCurrentL1,
activePower : _Self.ActivePowerL1,
reactivePower: _Self.ReactivePowerL1,
apparentPower: _Self.ApparentPowerL1
);
private AcPhase L1 => new()
{
Current = _Self.GridCurrentL1,
Voltage = _Self.GridVoltageL1,
Phi = Atan2(_Self.ReactivePowerL1, _Self.ActivePowerL1)
};
private AcPhase L2 => new()
{
Current = _Self.GridCurrentL2,
Voltage = _Self.GridVoltageL2,
Phi = Atan2(_Self.ReactivePowerL2, _Self.ActivePowerL2)
};
private AcPhase L3 => new()
{
Current = _Self.GridCurrentL3,
Voltage = _Self.GridVoltageL3,
Phi = Atan2(_Self.ReactivePowerL3, _Self.ActivePowerL3)
};
private AcPhase L2 => AcPhase.FromVoltageCurrentActiveReactiveApparent
(
voltageRms : _Self.GridVoltageL2,
currentRms : _Self.GridCurrentL2,
activePower : _Self.ActivePowerL2,
reactivePower: _Self.ReactivePowerL2,
apparentPower: _Self.ApparentPowerL2
);
private AcPhase L3 => AcPhase.FromVoltageCurrentActiveReactiveApparent
(
voltageRms : _Self.GridVoltageL3,
currentRms : _Self.GridCurrentL3,
activePower : _Self.ActivePowerL3,
reactivePower: _Self.ReactivePowerL3,
apparentPower: _Self.ApparentPowerL3
);
internal AcDcStatus(AcDcRecord self) => _Self = self;

View File

@ -1,5 +1,6 @@
using InnovEnergy.Lib.Devices.Trumpf.SystemControl;
using InnovEnergy.Lib.Devices.Trumpf.TruConvertDc.Status;
using InnovEnergy.Lib.Units;
using InnovEnergy.Lib.Units.Composite;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertDc;
@ -18,7 +19,13 @@ public class DcDcDevicesRecord
Devices = devices;
}
public DcStatus Dc => new()
public DcStatus Dc
{
get
{
Voltage voltage = Devices.Average(r => r.Status.Dc.Link.Voltage.Value);
Current current = Devices.Sum(r => r.Status.Dc.Link.Current.Value);
return new()
{
Battery = Devices.Count == 0
? NoDevice
@ -30,12 +37,14 @@ public class DcDcDevicesRecord
Link = Devices.Count == 0
? NoDevice
: DcBus.FromVoltageCurrent
(
Devices.Average(r => r.Status.Dc.Link.Voltage.Value),
Devices.Sum(r => r.Status.Dc.Link.Current.Value)
)
: new()
{
Voltage = voltage,
Current = current,
}
};
}
}
public SystemControlRegisters? SystemControl { get; }
public IReadOnlyList<DcDcRecord> Devices { get; }

View File

@ -1,5 +1,4 @@
using InnovEnergy.Lib.Units;
using InnovEnergy.Lib.Units.Composite;
using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertDc.Status;

View File

@ -4,6 +4,6 @@ namespace InnovEnergy.Lib.StatusApi.Connections;
public interface IAc1Connection
{
Ac1Bus Ac { get; }
AcBus Ac { get; }
}

View File

@ -1,5 +1,4 @@
using InnovEnergy.Lib.StatusApi.Connections;
using InnovEnergy.Lib.Units.Composite;
namespace InnovEnergy.Lib.StatusApi.DeviceTypes;

View File

@ -1,5 +1,4 @@
using InnovEnergy.Lib.StatusApi.Connections;
using InnovEnergy.Lib.Units.Composite;
namespace InnovEnergy.Lib.StatusApi.DeviceTypes;

View File

@ -1,7 +0,0 @@
namespace InnovEnergy.Lib.StatusApi;
public interface IDeviceRecord<out S, out C>
{
S Status { get; }
C Control { get; }
}

View File

@ -1,22 +0,0 @@
namespace InnovEnergy.Lib.Units.Composite;
public sealed class Ac1Bus
{
public required Voltage Voltage { get; init; }
public required Current Current { get; init; }
public required AcPower Power { get; init; }
public required Frequency Frequency { get; init; }
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)
};
public static Ac1Bus Null => FromVoltageCurrentFrequencyPhi(0, 0, 0, 0);
}

View File

@ -1,25 +1,20 @@
namespace InnovEnergy.Lib.Units.Composite;
public class Ac3Bus
public record Ac3Bus
{
public required AcPhase L1 { get; init; }
public required AcPhase L2 { get; init; }
public required AcPhase L3 { get; init; }
public required AcPower Power { get; init; }
public required Frequency Frequency { get; init; }
public static Ac3Bus FromPhasesAndFrequency(AcPhase l1,
AcPhase l2,
AcPhase l3,
Frequency frequency) => new()
{
L1 = l1,
L2 = l2,
L3 = l3,
Power = AcPower.SumOf(l1.Power, l2.Power, l3.Power),
Frequency = frequency,
};
public AcPower Power => L1.Power + L2.Power + L3.Power;
public static Ac3Bus Null => FromPhasesAndFrequency(AcPhase.Null, AcPhase.Null, AcPhase.Null, 0);
public static Ac3Bus Zero => new Ac3Bus
{
Frequency = 0,
L1 = AcPhase.Zero,
L2 = AcPhase.Zero,
L3 = AcPhase.Zero,
};
}

View File

@ -0,0 +1,14 @@
namespace InnovEnergy.Lib.Units.Composite;
public record AcBus : AcPhase
{
public required Frequency Frequency { get; init; }
public new static AcBus Zero => new AcBus
{
Current = 0,
Voltage = 0,
Phi = 0,
Frequency = 0,
};
}

View File

@ -1,46 +1,23 @@
using InnovEnergy.Lib.Units.Power;
using static System.Math;
namespace InnovEnergy.Lib.Units.Composite;
public sealed class AcPhase
public record AcPhase
{
public required Voltage Voltage { get; init; }
public required Current Current { get; init; }
public required AcPower Power { get; init; }
public required Angle Phi { get; init; }
public static AcPhase FromVoltageCurrentPhi(Voltage voltageRms,
Current currentRms,
Angle phi) => new()
public AcPower Power => new()
{
Current = currentRms,
Voltage = voltageRms,
Power = AcPower.FromVoltageCurrentPhi(voltageRms, currentRms, phi)
Active = Voltage * Current * Cos(Phi),
Reactive = Voltage * Current * Sin(Phi),
};
public static AcPhase FromVoltageCurrentActiveReactive(Voltage voltageRms,
Current currentRms,
ActivePower activePower,
ReactivePower reactivePower) => new()
public static AcPhase Zero => new AcPhase
{
Current = currentRms,
Voltage = voltageRms,
Power = AcPower.FromActiveReactive(activePower, reactivePower)
Current = 0,
Voltage = 0,
Phi = 0,
};
public static AcPhase FromVoltageCurrentActiveReactiveApparent(Voltage voltageRms,
Current currentRms,
ActivePower activePower,
ReactivePower reactivePower,
ApparentPower apparentPower) => new()
{
Current = currentRms,
Voltage = voltageRms,
Power = AcPower.FromActiveReactiveApparent(activePower, reactivePower, apparentPower)
};
public static AcPhase Null => FromVoltageCurrentPhi(0, 0, 0);
}

View File

@ -4,108 +4,31 @@ using static System.Math;
namespace InnovEnergy.Lib.Units.Composite;
public sealed class AcPower
public record AcPower
{
private AcPower(){}
public required ApparentPower Apparent { get; init; }
public required ActivePower Active { get; init; }
public required ReactivePower Reactive { get; init; }
public required Angle Phi { get; init; }
public required Double CosPhi { get; init; }
public static AcPower FromActiveReactiveApparent(ActivePower activePower, ReactivePower reactivePower, ApparentPower apparentPower)
{
var q = reactivePower.Value;
var p = activePower.Value;
var s = apparentPower.Value;
var phi = Atan2(q, p);
public ApparentPower Apparent => Sqrt(Active * Active + Reactive * Reactive);
return new AcPower
public static AcPower operator +(AcPower left, AcPower right) => new AcPower
{
Active = p,
Reactive = q,
Apparent = s,
Phi = phi,
CosPhi = Cos(phi),
Active = left.Active + right.Active,
Reactive = left.Reactive + right.Reactive
};
}
public static AcPower FromActiveReactive(ActivePower activePower, ReactivePower reactivePower)
public static AcPower operator -(AcPower left, AcPower right) => new AcPower
{
var q = reactivePower.Value;
var p = activePower.Value;
var s = Sqrt(p * p + q * q);
var phi = Atan2(q, p);
return new AcPower
{
Active = p,
Reactive = q,
Apparent = s,
Phi = phi,
CosPhi = Cos(phi),
Active = left.Active - right.Active,
Reactive = left.Reactive - right.Reactive
};
}
public static AcPower FromVoltageCurrentPhi(Voltage voltageRms, Current currentRms, Angle phi)
public static AcPower operator -(AcPower p) => new AcPower
{
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));
var cosPhi = Cos(phi.Value);
var apparent = voltageRms.Value * currentRms.Value;
return new AcPower
{
Apparent = apparent,
Active = apparent * cosPhi,
Reactive = apparent * Sin(phi.Value),
Phi = phi,
CosPhi = cosPhi
Active = -p.Active,
Reactive = -p.Reactive
};
}
public static AcPower SumOf(params AcPower[] phases)
{
var p = phases.Sum(l => l.Active.Value);
var q = phases.Sum(l => l.Reactive.Value);
var s = Sqrt(p * p + q * q);
Angle phi = Atan2(q, p);
return new AcPower
{
Apparent = s,
Active = p,
Reactive = q,
Phi = phi,
CosPhi = Cos(phi.Value)
};
}
public static AcPower operator +(AcPower left, AcPower right) => FromActiveReactive
(
left.Active + right.Active,
left.Reactive + right.Reactive
);
public static AcPower operator -(AcPower left, AcPower right) => FromActiveReactive
(
left.Active - right.Active,
left.Reactive - right.Reactive
);
public static AcPower operator -(AcPower p) => FromActiveReactive
(
-p.Active,
-p.Reactive
);
public static implicit operator AcPower(Double p) => FromActiveReactive(p, 0);
public static implicit operator AcPower(Int32 p) => FromActiveReactive(p, 0);
public override String ToString() => Active.ToString(); // TODO: show all
public static implicit operator AcPower(Double p) => new AcPower { Active = p, Reactive = 0 };
public static implicit operator AcPower(Int32 p) => new AcPower { Active = p, Reactive = 0 };
}

View File

@ -2,20 +2,14 @@ using InnovEnergy.Lib.Units.Power;
namespace InnovEnergy.Lib.Units.Composite;
public sealed class DcBus
public record DcBus
{
public required Voltage Voltage { get; init; }
public required Current Current { get; init; }
public DcPower Power => Voltage * Current;
public static DcBus FromVoltageCurrent(Voltage voltage, Current current) => new()
{
Voltage = voltage,
Current = current,
};
public static DcBus Null => new()
public static DcBus Zero => new()
{
Voltage = 0,
Current = 0,

View File

@ -5,5 +5,4 @@ public abstract class Power : Unit
protected Power(Double value) : base(value)
{
}
}