Merge branch 'main' of https://git.innov.energy/Innovenergy/git_trunk
This commit is contained in:
commit
531c296a15
|
@ -7,9 +7,6 @@ namespace InnovEnergy.App.Backend;
|
||||||
|
|
||||||
public static class Program
|
public static class Program
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static void Main(String[] args)
|
public static void Main(String[] args)
|
||||||
{
|
{
|
||||||
//Db.CreateFakeRelations();
|
//Db.CreateFakeRelations();
|
||||||
|
|
|
@ -11,6 +11,7 @@ echo -e "\n============================ Build ============================\n"
|
||||||
|
|
||||||
dotnet publish \
|
dotnet publish \
|
||||||
./SaliMax.csproj \
|
./SaliMax.csproj \
|
||||||
|
-p:PublishTrimmed=false \
|
||||||
-c Release \
|
-c Release \
|
||||||
-r linux-x64
|
-r linux-x64
|
||||||
|
|
||||||
|
|
|
@ -30,11 +30,17 @@ public static class Controller
|
||||||
mode.WriteLine();
|
mode.WriteLine();
|
||||||
|
|
||||||
if (mode is EssMode.Off or EssMode.NoGridMeter)
|
if (mode is EssMode.Off or EssMode.NoGridMeter)
|
||||||
return new EssControl(mode, EssLimit.NoLimit, PowerCorrection: 0, PowerSetpoint: 0);
|
return EssControl.Default;
|
||||||
|
|
||||||
var essDelta = s.ComputePowerDelta(mode);
|
var essDelta = s.ComputePowerDelta(mode);
|
||||||
|
|
||||||
var unlimitedControl = new EssControl(mode, EssLimit.NoLimit, essDelta, 0);
|
var unlimitedControl = new EssControl
|
||||||
|
{
|
||||||
|
Mode = mode,
|
||||||
|
LimitedBy = EssLimit.NoLimit,
|
||||||
|
PowerCorrection = essDelta,
|
||||||
|
PowerSetpoint = 0
|
||||||
|
};
|
||||||
|
|
||||||
var limitedControl = unlimitedControl
|
var limitedControl = unlimitedControl
|
||||||
.LimitChargePower(s)
|
.LimitChargePower(s)
|
||||||
|
|
|
@ -3,13 +3,21 @@ using InnovEnergy.Lib.Units.Power;
|
||||||
namespace InnovEnergy.App.SaliMax.Ess;
|
namespace InnovEnergy.App.SaliMax.Ess;
|
||||||
|
|
||||||
public record EssControl
|
public record EssControl
|
||||||
(
|
|
||||||
EssMode Mode,
|
|
||||||
EssLimit LimitedBy,
|
|
||||||
ActivePower PowerCorrection,
|
|
||||||
ActivePower PowerSetpoint
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
|
public required EssMode Mode { get; init; }
|
||||||
|
public required EssLimit LimitedBy { get; init; }
|
||||||
|
public required ActivePower PowerCorrection { get; init; }
|
||||||
|
public required ActivePower PowerSetpoint { get; init; }
|
||||||
|
|
||||||
|
public static EssControl Default { get; } = new()
|
||||||
|
{
|
||||||
|
Mode = EssMode.Off,
|
||||||
|
LimitedBy = EssLimit.NoLimit,
|
||||||
|
PowerCorrection = 0,
|
||||||
|
PowerSetpoint = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
public EssControl LimitChargePower(Double controlDelta, EssLimit reason)
|
public EssControl LimitChargePower(Double controlDelta, EssLimit reason)
|
||||||
{
|
{
|
||||||
var overload = PowerCorrection - controlDelta;
|
var overload = PowerCorrection - controlDelta;
|
||||||
|
|
|
@ -12,20 +12,20 @@ namespace InnovEnergy.App.SaliMax.Ess;
|
||||||
|
|
||||||
public record StatusRecord
|
public record StatusRecord
|
||||||
{
|
{
|
||||||
public AcDcDevicesRecord AcDc { get; init; } = null!;
|
public required AcDcDevicesRecord AcDc { get; init; }
|
||||||
public DcDcDevicesRecord DcDc { get; init; } = null!;
|
public required DcDcDevicesRecord DcDc { get; init; }
|
||||||
public Battery48TlRecords Battery { get; init; } = null!;
|
public required Battery48TlRecords Battery { get; init; }
|
||||||
public EmuMeterRegisters? GridMeter { get; init; }
|
public required EmuMeterRegisters? GridMeter { get; init; }
|
||||||
public EmuMeterRegisters? LoadOnAcIsland { get; init; }
|
public required EmuMeterRegisters? LoadOnAcIsland { get; init; }
|
||||||
public AcPowerDevice? LoadOnAcGrid { get; init; } = null!;
|
public required AcPowerDevice? LoadOnAcGrid { get; init; }
|
||||||
public AcPowerDevice? PvOnAcGrid { get; init; } = null!;
|
public required AcPowerDevice? PvOnAcGrid { get; init; }
|
||||||
public AcPowerDevice? PvOnAcIsland { get; init; } = null!;
|
public required AcPowerDevice? PvOnAcIsland { get; init; }
|
||||||
public AcPowerDevice? AcGridToAcIsland { get; init; } = null!;
|
public required AcPowerDevice? AcGridToAcIsland { get; init; }
|
||||||
public DcPowerDevice? LoadOnDc { get; init; } = null!;
|
public required DcPowerDevice? LoadOnDc { get; init; }
|
||||||
public RelaysRecord? Relays { get; init; }
|
public required RelaysRecord? Relays { get; init; }
|
||||||
public AmptStatus PvOnDc { get; init; } = null!;
|
public required AmptStatus PvOnDc { get; init; }
|
||||||
public Config Config { get; init; } = null!;
|
public required Config Config { get; init; }
|
||||||
public EssControl EssControl { get; set; } = null!;
|
public required EssControl EssControl { get; set; } // TODO: init only
|
||||||
public StateMachine StateMachine { get; } = new StateMachine();
|
public required StateMachine StateMachine { get; init; }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ public static class Flow
|
||||||
|
|
||||||
public static TextBlock Horizontal(Unit amount, Int32 width = 10)
|
public static TextBlock Horizontal(Unit amount, Int32 width = 10)
|
||||||
{
|
{
|
||||||
var label = amount.ToStringRounded();
|
var label = amount.ToDisplayString();
|
||||||
var arrowChar = amount.Value < 0 ? LeftArrowChar : RightArrowChar;
|
var arrowChar = amount.Value < 0 ? LeftArrowChar : RightArrowChar;
|
||||||
var arrow = Enumerable.Repeat(arrowChar, width).Join();
|
var arrow = Enumerable.Repeat(arrowChar, width).Join();
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ public static class Flow
|
||||||
[SuppressMessage("ReSharper", "CoVariantArrayConversion")]
|
[SuppressMessage("ReSharper", "CoVariantArrayConversion")]
|
||||||
public static TextBlock Vertical(Unit amount, Int32 height = 4)
|
public static TextBlock Vertical(Unit amount, Int32 height = 4)
|
||||||
{
|
{
|
||||||
var label = amount.ToStringRounded();
|
var label = amount.ToDisplayString();
|
||||||
var arrowChar = amount.Value < 0 ? UpArrowChar : DownArrowChar;
|
var arrowChar = amount.Value < 0 ? UpArrowChar : DownArrowChar;
|
||||||
var halfArrow = Enumerable.Repeat(arrowChar, height/2);
|
var halfArrow = Enumerable.Repeat(arrowChar, height/2);
|
||||||
|
|
||||||
|
|
|
@ -148,6 +148,8 @@ internal static class Program
|
||||||
LoadOnAcIsland = loadOnAcIsland,
|
LoadOnAcIsland = loadOnAcIsland,
|
||||||
LoadOnDc = loadOnDc,
|
LoadOnDc = loadOnDc,
|
||||||
|
|
||||||
|
StateMachine = StateMachine.Default,
|
||||||
|
EssControl = EssControl.Default,
|
||||||
Config = Config.Load() // load from disk every iteration, so config can be changed while running
|
Config = Config.Load() // load from disk every iteration, so config can be changed while running
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -228,17 +230,17 @@ internal static class Program
|
||||||
var islandToGridBusPower = inverterPower + islandLoadPower;
|
var islandToGridBusPower = inverterPower + islandLoadPower;
|
||||||
var gridLoadPower = s.LoadOnAcGrid is null ? 0: s.LoadOnAcGrid.Power.Active;
|
var gridLoadPower = s.LoadOnAcGrid is null ? 0: s.LoadOnAcGrid.Power.Active;
|
||||||
|
|
||||||
var gridPowerByPhase = TextBlock.AlignLeft(s.GridMeter.Ac.L1.Power.Active.ToStringRounded(),
|
var gridPowerByPhase = TextBlock.AlignLeft(s.GridMeter.Ac.L1.Power.Active.ToDisplayString(),
|
||||||
s.GridMeter.Ac.L2.Power.Active.ToStringRounded(),
|
s.GridMeter.Ac.L2.Power.Active.ToDisplayString(),
|
||||||
s.GridMeter.Ac.L3.Power.Active.ToStringRounded());
|
s.GridMeter.Ac.L3.Power.Active.ToDisplayString());
|
||||||
|
|
||||||
var gridVoltageByPhase = TextBlock.AlignLeft(s.GridMeter.Ac.L1.Voltage.ToStringRounded(),
|
var gridVoltageByPhase = TextBlock.AlignLeft(s.GridMeter.Ac.L1.Voltage.ToDisplayString(),
|
||||||
s.GridMeter.Ac.L2.Voltage.ToStringRounded(),
|
s.GridMeter.Ac.L2.Voltage.ToDisplayString(),
|
||||||
s.GridMeter.Ac.L3.Voltage.ToStringRounded());
|
s.GridMeter.Ac.L3.Voltage.ToDisplayString());
|
||||||
|
|
||||||
var inverterPowerByPhase = TextBlock.AlignLeft(s.AcDc.Ac.L1.Power.Active.ToStringRounded(),
|
var inverterPowerByPhase = TextBlock.AlignLeft(s.AcDc.Ac.L1.Power.Active.ToDisplayString(),
|
||||||
s.AcDc.Ac.L2.Power.Active.ToStringRounded(),
|
s.AcDc.Ac.L2.Power.Active.ToDisplayString(),
|
||||||
s.AcDc.Ac.L3.Power.Active.ToStringRounded());
|
s.AcDc.Ac.L3.Power.Active.ToDisplayString());
|
||||||
|
|
||||||
// ReSharper disable once CoVariantArrayConversion
|
// ReSharper disable once CoVariantArrayConversion
|
||||||
var inverterPowerByAcDc = TextBlock.AlignLeft(s.AcDc.Devices
|
var inverterPowerByAcDc = TextBlock.AlignLeft(s.AcDc.Devices
|
||||||
|
@ -246,7 +248,7 @@ internal static class Program
|
||||||
.ToArray());
|
.ToArray());
|
||||||
|
|
||||||
var dcLinkVoltage = TextBlock.CenterHorizontal("",
|
var dcLinkVoltage = TextBlock.CenterHorizontal("",
|
||||||
s.DcDc.Dc.Link.Voltage.ToStringRounded(),
|
s.DcDc.Dc.Link.Voltage.ToDisplayString(),
|
||||||
"");
|
"");
|
||||||
|
|
||||||
//var inverterPowerByPhase = new ActivePower[(Int32)s.AcDc.Ac.L1.Power.Active, (Int32)s.AcDc.Ac.L2.Power.Active, (Int32)s.AcDc.Ac.L3.Power.Active];
|
//var inverterPowerByPhase = new ActivePower[(Int32)s.AcDc.Ac.L1.Power.Active, (Int32)s.AcDc.Ac.L2.Power.Active, (Int32)s.AcDc.Ac.L3.Power.Active];
|
||||||
|
@ -273,7 +275,7 @@ internal static class Program
|
||||||
var gridBox = TextBlock.AlignLeft(gridPowerByPhase).TitleBox("Grid");
|
var gridBox = TextBlock.AlignLeft(gridPowerByPhase).TitleBox("Grid");
|
||||||
var inverterBox = TextBlock.AlignLeft(inverterPowerByAcDc).TitleBox("Inverter");
|
var inverterBox = TextBlock.AlignLeft(inverterPowerByAcDc).TitleBox("Inverter");
|
||||||
var dcDcBox = TextBlock.AlignLeft(dc48Voltage).TitleBox("DC/DC");
|
var dcDcBox = TextBlock.AlignLeft(dc48Voltage).TitleBox("DC/DC");
|
||||||
var batteryBox = TextBlock.AlignLeft(batteryVoltage.ToStringRounded(), batterySoc.ToStringRounded(), batteryCurrent.ToStringRounded(), batteryTemp.ToStringRounded()).TitleBox("Battery");
|
var batteryBox = TextBlock.AlignLeft(batteryVoltage.ToDisplayString(), batterySoc.ToDisplayString(), batteryCurrent.ToDisplayString(), batteryTemp.ToDisplayString()).TitleBox("Battery");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -9,12 +9,12 @@ namespace InnovEnergy.App.SaliMax;
|
||||||
|
|
||||||
public record S3Config
|
public record S3Config
|
||||||
{
|
{
|
||||||
public String Bucket { get; init; } = "";
|
public required String Bucket { get; init; }
|
||||||
public String Region { get; init; } = "";
|
public required String Region { get; init; }
|
||||||
public String Provider { get; init; } = "";
|
public required String Provider { get; init; }
|
||||||
public String Key { get; init; } = "";
|
public required String Key { get; init; }
|
||||||
public String Secret { get; init; } = "";
|
public required String Secret { get; init; }
|
||||||
public String ContentType { get; init; } = "";
|
public required String ContentType { get; init; }
|
||||||
|
|
||||||
public String Host => $"{Bucket}.{Region}.{Provider}";
|
public String Host => $"{Bucket}.{Region}.{Provider}";
|
||||||
public String Url => $"https://{Host}";
|
public String Url => $"https://{Host}";
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
namespace InnovEnergy.App.SaliMax.System;
|
namespace InnovEnergy.App.SaliMax.System;
|
||||||
|
|
||||||
public class StateMachine
|
public record StateMachine
|
||||||
{
|
{
|
||||||
public String Message { get; set; } = "Panic: Unknown State!";
|
public required String Message { get; set; } // TODO: init only
|
||||||
public Int32 State { get; set; } = 100;
|
public required Int32 State { get; set; } // TODO: init only
|
||||||
|
|
||||||
|
public static StateMachine Default { get; } = new StateMachine { State = 100, Message = "Unknown State" };
|
||||||
}
|
}
|
|
@ -6,7 +6,7 @@
|
||||||
<LangVersion>preview</LangVersion>
|
<LangVersion>preview</LangVersion>
|
||||||
<IsTrimmable>true</IsTrimmable>
|
<IsTrimmable>true</IsTrimmable>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<InvariantGlobalization>true</InvariantGlobalization>
|
<InvariantGlobalization>true</InvariantGlobalization>
|
||||||
<SuppressTrimAnalysisWarnings>false</SuppressTrimAnalysisWarnings>
|
<SuppressTrimAnalysisWarnings>false</SuppressTrimAnalysisWarnings>
|
||||||
<RootNamespace>Please.reload.the.project.Rider.is.stupid</RootNamespace>
|
<RootNamespace>Please.reload.the.project.Rider.is.stupid</RootNamespace>
|
||||||
|
|
|
@ -4,8 +4,8 @@ namespace InnovEnergy.Lib.Channels.Stages;
|
||||||
|
|
||||||
public class Channel<Tx, Rx>
|
public class Channel<Tx, Rx>
|
||||||
{
|
{
|
||||||
public AsyncAction<Tx> Write { get; init; } = _ => throw new NotImplementedException(nameof(Write));
|
public required AsyncAction<Tx> Write { get; init; }
|
||||||
public Async<Rx> Read { get; init; } = () => throw new NotImplementedException(nameof(Read));
|
public required Async<Rx> Read { get; init; }
|
||||||
|
|
||||||
public Channel<T, R> Map<T, R>(Stage<T, Tx, Rx, R> stage)
|
public Channel<T, R> Map<T, R>(Stage<T, Tx, Rx, R> stage)
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,9 +4,9 @@ namespace InnovEnergy.Lib.Channels.Stages;
|
||||||
|
|
||||||
public class ConnectedChannel<Tx, Rx> : Channel<Tx,Rx>, IAsyncDisposable
|
public class ConnectedChannel<Tx, Rx> : Channel<Tx,Rx>, IAsyncDisposable
|
||||||
{
|
{
|
||||||
public Func<Boolean> IsOpen { get; init; } = () => throw new NotImplementedException(nameof(IsOpen));
|
public required Func<Boolean> IsOpen { get; init; }
|
||||||
public AsyncAction Open { get; init; } = () => throw new NotImplementedException(nameof(Open));
|
public required AsyncAction Open { get; init; }
|
||||||
public AsyncAction Close { get; init; } = () => throw new NotImplementedException(nameof(Close));
|
public required AsyncAction Close { get; init; }
|
||||||
|
|
||||||
public async ValueTask DisposeAsync() => await Close();
|
public async ValueTask DisposeAsync() => await Close();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
namespace InnovEnergy.Lib.Devices.AMPT;
|
namespace InnovEnergy.Lib.Devices.AMPT;
|
||||||
|
|
||||||
|
|
||||||
|
// not used ATM
|
||||||
public class AmptCommunicationUnitStatus
|
public class AmptCommunicationUnitStatus
|
||||||
{
|
{
|
||||||
public UInt32 Sid { get; init; } // A well-known value 0x53756e53, uniquely identifies this as a SunSpec Modbus Map
|
public required UInt32 Sid { get; init; } // A well-known value 0x53756e53, uniquely identifies this as a SunSpec Modbus Map
|
||||||
public UInt16 IdSunSpec { get; init; } // A well-known value 1, uniquely identifies this as a SunSpec Common Model
|
public required UInt16 IdSunSpec { get; init; } // A well-known value 1, uniquely identifies this as a SunSpec Common Model
|
||||||
|
|
||||||
public String Manufacturer { get; init; } = "undefined"; // A well-known value registered with SunSpec for compliance: "Ampt"
|
public required String Manufacturer { get; init; } // A well-known value registered with SunSpec for compliance: "Ampt"
|
||||||
public String Model { get; init; } = "undefined"; // Manufacturer specific value "Communication Unit"
|
public required String Model { get; init; } // Manufacturer specific value "Communication Unit"
|
||||||
public String Version { get; init; } = "undefined"; // Software Version
|
public required String Version { get; init; } // Software Version
|
||||||
public String SerialNumber { get; init; } = "undefined"; // Manufacturer specific value
|
public required String SerialNumber { get; init; } // Manufacturer specific value
|
||||||
public Int16 DeviceAddress { get; init; } // Modbus Device ID
|
public required Int16 DeviceAddress { get; init; } // Modbus Device ID
|
||||||
public UInt16 IdVendor { get; init; } // Ampt SunSpec Vendor Code 64050
|
public required UInt16 IdVendor { get; init; } // Ampt SunSpec Vendor Code 64050
|
||||||
|
|
||||||
public IReadOnlyList<AmptStatus> Devices { get; init; } = Array.Empty<AmptStatus>();
|
public required IReadOnlyList<AmptStatus> Devices { get; init; }
|
||||||
}
|
}
|
|
@ -21,13 +21,13 @@ public interface IMatchRule
|
||||||
|
|
||||||
public record MatchRule : IMatchRule
|
public record MatchRule : IMatchRule
|
||||||
{
|
{
|
||||||
public MessageType? Type { get; init; } = default;
|
public MessageType? Type { get; init; }
|
||||||
public String? Interface { get; init; } = default;
|
public String? Interface { get; init; }
|
||||||
public String? Member { get; init; } = default;
|
public String? Member { get; init; }
|
||||||
public ObjectPath? Path { get; init; } = default;
|
public ObjectPath? Path { get; init; }
|
||||||
public ObjectPath? PathNamespace { get; init; } = default;
|
public ObjectPath? PathNamespace { get; init; }
|
||||||
public String? Sender { get; init; } = default;
|
public String? Sender { get; init; }
|
||||||
public String? Destination { get; init; } = default;
|
public String? Destination { get; init; }
|
||||||
public Boolean Eavesdrop { get; init; } = false;
|
public Boolean Eavesdrop { get; init; } = false;
|
||||||
|
|
||||||
public override String ToString() => this.Rule();
|
public override String ToString() => this.Rule();
|
||||||
|
|
|
@ -5,10 +5,10 @@ public sealed class Ac1Bus
|
||||||
private Ac1Bus()
|
private Ac1Bus()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
public Voltage Voltage { get; private init; } = null!;
|
public required Voltage Voltage { get; init; }
|
||||||
public Current Current { get; private init; } = null!;
|
public required Current Current { get; init; }
|
||||||
public AcPower Power { get; private init; } = null!;
|
public required AcPower Power { get; init; }
|
||||||
public Frequency Frequency { get; private init; } = null!;
|
public required Frequency Frequency { get; init; }
|
||||||
|
|
||||||
public static Ac1Bus FromVoltageCurrentFrequencyPhi(Double voltageRms,
|
public static Ac1Bus FromVoltageCurrentFrequencyPhi(Double voltageRms,
|
||||||
Double currentRms,
|
Double currentRms,
|
||||||
|
|
|
@ -6,11 +6,11 @@ public sealed class Ac3Bus
|
||||||
{
|
{
|
||||||
private Ac3Bus() {}
|
private Ac3Bus() {}
|
||||||
|
|
||||||
public AcPhase L1 { get; private init; } = null!;
|
public required AcPhase L1 { get; init; }
|
||||||
public AcPhase L2 { get; private init; } = null!;
|
public required AcPhase L2 { get; init; }
|
||||||
public AcPhase L3 { get; private init; } = null!;
|
public required AcPhase L3 { get; init; }
|
||||||
public AcPower Power { get; private init; } = null!;
|
public required AcPower Power { get; init; }
|
||||||
public Frequency Frequency { get; private init; } = null!;
|
public required Frequency Frequency { get; init; }
|
||||||
|
|
||||||
public static Ac3Bus FromPhasesAndFrequency(AcPhase l1,
|
public static Ac3Bus FromPhasesAndFrequency(AcPhase l1,
|
||||||
AcPhase l2,
|
AcPhase l2,
|
||||||
|
|
|
@ -7,9 +7,9 @@ public sealed class AcPhase
|
||||||
{
|
{
|
||||||
private AcPhase(){}
|
private AcPhase(){}
|
||||||
|
|
||||||
public Voltage Voltage { get; private init; } = null!;
|
public required Voltage Voltage { get; init; }
|
||||||
public Current Current { get; private init; } = null!;
|
public required Current Current { get; init; }
|
||||||
public AcPower Power { get; private init; } = null!;
|
public required AcPower Power { get; init; }
|
||||||
|
|
||||||
public static AcPhase FromVoltageCurrentPhi(Voltage voltageRms,
|
public static AcPhase FromVoltageCurrentPhi(Voltage voltageRms,
|
||||||
Current currentRms,
|
Current currentRms,
|
||||||
|
|
|
@ -8,11 +8,11 @@ public sealed class AcPower
|
||||||
{
|
{
|
||||||
private AcPower(){}
|
private AcPower(){}
|
||||||
|
|
||||||
public ApparentPower Apparent { get; private init; } = null!;
|
public required ApparentPower Apparent { get; init; }
|
||||||
public ActivePower Active { get; private init; } = null!;
|
public required ActivePower Active { get; init; }
|
||||||
public ReactivePower Reactive { get; private init; } = null!;
|
public required ReactivePower Reactive { get; init; }
|
||||||
public Angle Phi { get; private init; } = null!;
|
public required Angle Phi { get; init; }
|
||||||
public Double CosPhi { get; private init; }
|
public required Double CosPhi { get; init; }
|
||||||
|
|
||||||
public static AcPower FromActiveReactiveApparent(ActivePower activePower, ReactivePower reactivePower, ApparentPower apparentPower)
|
public static AcPower FromActiveReactiveApparent(ActivePower activePower, ReactivePower reactivePower, ApparentPower apparentPower)
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,9 +6,9 @@ public sealed class DcBus
|
||||||
{
|
{
|
||||||
private DcBus() {}
|
private DcBus() {}
|
||||||
|
|
||||||
public Voltage Voltage { get; private init; } = null!;
|
public required Voltage Voltage { get; init; }
|
||||||
public Current Current { get; private init; } = null!;
|
public required Current Current { get; init; }
|
||||||
public ActivePower Power { get; private init; } = null!;
|
public required ActivePower Power { get; init; }
|
||||||
|
|
||||||
public static DcBus FromVoltageCurrent(Voltage voltage, Current current) => new()
|
public static DcBus FromVoltageCurrent(Voltage voltage, Current current) => new()
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,7 +2,7 @@ namespace InnovEnergy.Lib.Units;
|
||||||
|
|
||||||
public sealed class Energy : Unit
|
public sealed class Energy : Unit
|
||||||
{
|
{
|
||||||
public override String Symbol => "kWh";
|
public override String Symbol => "Wh";
|
||||||
|
|
||||||
public Energy(Double value) : base(value)
|
public Energy(Double value) : base(value)
|
||||||
{
|
{
|
||||||
|
|
|
@ -12,7 +12,6 @@ public sealed class ActivePower : AcPower
|
||||||
public static implicit operator ActivePower(Double d) => new ActivePower(d);
|
public static implicit operator ActivePower(Double d) => new ActivePower(d);
|
||||||
public static implicit operator Double(ActivePower d) => d.Value;
|
public static implicit operator Double(ActivePower d) => d.Value;
|
||||||
|
|
||||||
|
|
||||||
public static ActivePower operator -(ActivePower d) => -d.Value;
|
public static ActivePower operator -(ActivePower d) => -d.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,5 +8,35 @@ public abstract class Unit
|
||||||
public Double Value { get; }
|
public Double Value { get; }
|
||||||
|
|
||||||
public override String ToString() => $"{Value} {Symbol}";
|
public override String ToString() => $"{Value} {Symbol}";
|
||||||
public String ToStringRounded() => $"{Math.Round(Value,3)} {Symbol}";
|
|
||||||
|
public String ToDisplayString()
|
||||||
|
{
|
||||||
|
if (Value == 0)
|
||||||
|
return $"0 {Symbol}";
|
||||||
|
|
||||||
|
var a = Math.Abs(Value);
|
||||||
|
var s = Math.Sign(Value);
|
||||||
|
|
||||||
|
var i = 8;
|
||||||
|
|
||||||
|
while (a >= 10000)
|
||||||
|
{
|
||||||
|
a /= 1000;
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
|
while (a < 10)
|
||||||
|
{
|
||||||
|
a *= 1000;
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
|
||||||
|
var r = a < 100
|
||||||
|
? Math.Floor(a * 10) / 10
|
||||||
|
: Math.Floor(a);
|
||||||
|
|
||||||
|
return $"{r * s} {Prefix[i]}{Symbol}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly IReadOnlyList<String> Prefix = new[] { "y", "z", "a", "f", "p", "n", "µ", "m", "", "k", "M", "G", "T", "P", "E", "Y" };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Reflection;
|
|
||||||
using InnovEnergy.Lib.Units.Power;
|
using InnovEnergy.Lib.Units.Power;
|
||||||
using InnovEnergy.Lib.Utils;
|
using InnovEnergy.Lib.Utils;
|
||||||
using static System.Reflection.BindingFlags;
|
using static System.Reflection.BindingFlags;
|
||||||
|
@ -20,7 +19,8 @@ public static class Units
|
||||||
public static Frequency Hz (this Double value) => value;
|
public static Frequency Hz (this Double value) => value;
|
||||||
public static Angle Rad (this Double value) => value;
|
public static Angle Rad (this Double value) => value;
|
||||||
public static Temperature Celsius(this Double value) => value;
|
public static Temperature Celsius(this Double value) => value;
|
||||||
public static Energy KWh (this Double value) => value;
|
public static Energy KWh (this Double value) => value * 1000;
|
||||||
|
public static Energy Wh (this Double value) => value;
|
||||||
|
|
||||||
public static String ToCsv(this Object thing)
|
public static String ToCsv(this Object thing)
|
||||||
{
|
{
|
||||||
|
@ -88,87 +88,3 @@ public static class Units
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Prefixes
|
|
||||||
{
|
|
||||||
private static readonly IReadOnlyList<String> Big = new[]
|
|
||||||
{
|
|
||||||
"",
|
|
||||||
"k",
|
|
||||||
"M",
|
|
||||||
"G",
|
|
||||||
"T",
|
|
||||||
"P",
|
|
||||||
"E",
|
|
||||||
"Y",
|
|
||||||
};
|
|
||||||
|
|
||||||
private static readonly IReadOnlyList<String> Small = new[]
|
|
||||||
{
|
|
||||||
"",
|
|
||||||
"m",
|
|
||||||
"µ",
|
|
||||||
"n",
|
|
||||||
"p",
|
|
||||||
"f",
|
|
||||||
"a",
|
|
||||||
"z",
|
|
||||||
"y",
|
|
||||||
};
|
|
||||||
|
|
||||||
public static String TestGetPrefix(Double v, String unit)
|
|
||||||
{
|
|
||||||
if (v == 0)
|
|
||||||
return "";
|
|
||||||
|
|
||||||
var log10 = Math.Log10(v / 10);
|
|
||||||
var l = (Int32)Math.Floor(log10 / 3);
|
|
||||||
var lookUp = l > 0 ? Big : Small;
|
|
||||||
var i = Math.Abs(l);
|
|
||||||
|
|
||||||
return $"{v / Math.Pow(10.0, l * 3.0)} {lookUp[i]}{unit}";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static String TestGetPrefix(Decimal v, String unit)
|
|
||||||
{
|
|
||||||
if (v == 0m)
|
|
||||||
return "";
|
|
||||||
|
|
||||||
var d = (Double)v;
|
|
||||||
var log10 = Math.Log10(d / 10);
|
|
||||||
var l = (Int32)Math.Floor(log10 / 3);
|
|
||||||
var lookUp = l > 0 ? Big : Small;
|
|
||||||
var i = Math.Abs(l);
|
|
||||||
|
|
||||||
return $"{d / Math.Pow(10.0, l * 3.0)} {lookUp[i]}{unit}";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String TestGetPrefix2(Decimal v, String unit)
|
|
||||||
{
|
|
||||||
if (v == 0m)
|
|
||||||
return "";
|
|
||||||
|
|
||||||
var a = Math.Abs(v);
|
|
||||||
var s = Math.Sign(v);
|
|
||||||
|
|
||||||
var i = 0;
|
|
||||||
|
|
||||||
while (a >= 10000m)
|
|
||||||
{
|
|
||||||
a /= 1000;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
while (a < 10m)
|
|
||||||
{
|
|
||||||
a *= 1000;
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
|
|
||||||
var lookUp = i >= 0 ? Big : Small;
|
|
||||||
|
|
||||||
var r = Decimal.Floor(a * 10m) / 10m;
|
|
||||||
|
|
||||||
return $"{r*s} {lookUp[Math.Abs(i)]}{unit}";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue