Introduce VoltageRms and CurrentRms and use them where appropriate
This commit is contained in:
parent
006ea0e1ee
commit
7ecb6e4607
|
@ -1,7 +1,7 @@
|
|||
using InnovEnergy.Lib.Devices.Battery48TL;
|
||||
using InnovEnergy.Lib.Devices.Battery48TL.DataTypes;
|
||||
using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc;
|
||||
using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes;
|
||||
using InnovEnergy.Lib.Time.Unix;
|
||||
using InnovEnergy.Lib.Units;
|
||||
using InnovEnergy.Lib.Utils;
|
||||
|
||||
|
@ -9,7 +9,6 @@ namespace InnovEnergy.App.SaliMax.Ess;
|
|||
|
||||
public static class Controller
|
||||
{
|
||||
private static readonly UnixTimeSpan MaxTimeWithoutEoc = UnixTimeSpan.FromDays(7); // TODO: move to config
|
||||
private static readonly Double BatteryHeatingPower = 200.0; // TODO: move to config
|
||||
|
||||
public static EssMode SelectControlMode(this StatusRecord s)
|
||||
|
@ -105,12 +104,10 @@ public static class Controller
|
|||
|
||||
private static EssControl LimitDischargePower(this EssControl control, StatusRecord s)
|
||||
{
|
||||
//var maxInverterDischargeDelta = s.ControlInverterPower(-s.Config.MaxInverterPower);
|
||||
var maxBatteryDischargeDelta = s.Battery.Devices.Sum(b => b.MaxDischargePower);
|
||||
var maxBatteryDischargeDelta = s.Battery?.Devices.Sum(b => b.MaxDischargePower) ?? 0;
|
||||
var keepMinSocLimitDelta = s.ControlBatteryPower(s.HoldMinSocPower());
|
||||
|
||||
return control
|
||||
// .LimitDischargePower(maxInverterDischargeDelta, EssLimit.DischargeLimitedByInverterPower)
|
||||
.LimitDischargePower(maxBatteryDischargeDelta , EssLimit.DischargeLimitedByBatteryPower)
|
||||
.LimitDischargePower(keepMinSocLimitDelta , EssLimit.DischargeLimitedByMinSoc);
|
||||
}
|
||||
|
@ -133,15 +130,9 @@ public static class Controller
|
|||
};
|
||||
}
|
||||
|
||||
|
||||
private static Boolean HasPreChargeAlarm(this StatusRecord statusRecord)
|
||||
{
|
||||
return statusRecord.DcDc.Alarms.Contains(Lib.Devices.Trumpf.TruConvertDc.Status.AlarmMessage.DcDcPrecharge);
|
||||
}
|
||||
|
||||
private static Boolean MustHeatBatteries(this StatusRecord s)
|
||||
{
|
||||
var batteries = s.Battery.Devices;
|
||||
var batteries = s.GetBatteries();
|
||||
|
||||
if (batteries.Count <= 0)
|
||||
return true; // batteries might be there but BMS is without power
|
||||
|
@ -156,13 +147,12 @@ public static class Controller
|
|||
// This introduce a limit when we don't have communication with batteries
|
||||
// Otherwise the limit will be 0 and the batteries will be not heated
|
||||
|
||||
var maxChargePower = s.Config.Devices.BatteryNodes.Length * BatteryHeatingPower;
|
||||
var batteries = s.GetBatteries();
|
||||
|
||||
var maxChargePower = batteries.Count == 0
|
||||
? s.Config.Devices.BatteryNodes.Length * BatteryHeatingPower
|
||||
: batteries.Sum(b => b.MaxChargePower);
|
||||
|
||||
if (s.Battery.Devices.Count != 0)
|
||||
{
|
||||
maxChargePower = s.Battery.Devices.Sum(b => b.MaxChargePower);
|
||||
}
|
||||
|
||||
maxChargePower.W().ToDisplayString().WriteLine(" Max Charge Power");
|
||||
|
||||
return maxChargePower;
|
||||
|
@ -186,12 +176,17 @@ public static class Controller
|
|||
|
||||
private static Boolean MustReachMinSoc(this StatusRecord s)
|
||||
{
|
||||
var batteries = s.Battery.Devices;
|
||||
var batteries = s.GetBatteries();
|
||||
|
||||
return batteries.Count > 0
|
||||
&& batteries.Any(b => b.Soc < s.Config.MinSoc);
|
||||
}
|
||||
|
||||
private static IReadOnlyList<Battery48TlRecord> GetBatteries(this StatusRecord s)
|
||||
{
|
||||
return s.Battery?.Devices ?? Array.Empty<Battery48TlRecord>();
|
||||
}
|
||||
|
||||
|
||||
private static Boolean MustDoCalibrationCharge(this StatusRecord statusRecord)
|
||||
{
|
||||
|
@ -209,7 +204,7 @@ public static class Controller
|
|||
// no need to return false in case of EOC reached
|
||||
// because the BMS will set the Time Since TOC to 0 as soon a battery reach EOC
|
||||
// then Calibration Charge flag will be set false by the software
|
||||
return statusRecord.Battery.CalibrationChargeRequested;
|
||||
return statusRecord.Battery?.CalibrationChargeRequested ?? false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -237,7 +232,7 @@ public static class Controller
|
|||
{
|
||||
return ControlPower
|
||||
(
|
||||
measurement: status.Battery.Devices.Sum(b => b.Dc.Power),
|
||||
measurement: status.GetBatteries().Sum(b => b.Dc.Power),
|
||||
target: targetBatteryPower,
|
||||
pConstant: status.Config.PConstant
|
||||
);
|
||||
|
@ -247,7 +242,7 @@ public static class Controller
|
|||
{
|
||||
// TODO: explain LowSOC curve
|
||||
|
||||
var batteries = s.Battery.Devices;
|
||||
var batteries = s.GetBatteries();
|
||||
|
||||
if (batteries.Count == 0)
|
||||
return Double.NegativeInfinity;
|
||||
|
@ -264,6 +259,7 @@ public static class Controller
|
|||
return error * pConstant;
|
||||
}
|
||||
|
||||
// ReSharper disable once UnusedMember.Local, TODO
|
||||
private static Double ControlPowerWithIntegral(Double measurement, Double target, Double p, Double i)
|
||||
{
|
||||
var errorSum = 0; // this is must be sum of error
|
||||
|
@ -273,11 +269,4 @@ public static class Controller
|
|||
return ki + kp;
|
||||
}
|
||||
|
||||
private static IEnumerable<InverterState> InverterStates(this AcDcDevicesRecord acDcStatus)
|
||||
{
|
||||
return acDcStatus
|
||||
.Devices
|
||||
.Select(d => d.Status.InverterState.Current);
|
||||
}
|
||||
|
||||
}
|
|
@ -388,8 +388,11 @@ public static class Topology
|
|||
);
|
||||
}
|
||||
|
||||
private static TextBlock CreateAveragedBatteryBox(Battery48TlRecords bat)
|
||||
private static TextBlock CreateAveragedBatteryBox(Battery48TlRecords? bat)
|
||||
{
|
||||
if (bat is null)
|
||||
return TextBlock.AlignLeft("no battery").Box();
|
||||
|
||||
var voltage = bat.Dc.Voltage.ToDisplayString();
|
||||
var soc = bat.Devices.Any() ? bat.Devices.Average(b => b.Soc).Percent().ToDisplayString() : "0";
|
||||
var current = bat.Dc.Current.ToDisplayString();
|
||||
|
|
|
@ -2,7 +2,6 @@ using System.Diagnostics.CodeAnalysis;
|
|||
using InnovEnergy.Lib.Devices.Battery48TL.DataTypes;
|
||||
using InnovEnergy.Lib.Units;
|
||||
using InnovEnergy.Lib.Units.Power;
|
||||
using InnovEnergy.Lib.Utils;
|
||||
using static InnovEnergy.Lib.Devices.Battery48TL.DataTypes.LedState;
|
||||
|
||||
namespace InnovEnergy.Lib.Devices.Battery48TL;
|
||||
|
@ -18,7 +17,7 @@ public partial class Battery48TlRecord
|
|||
public Leds_ Leds => new Leds_(this);
|
||||
public Temperatures_ Temperatures => new Temperatures_(this);
|
||||
|
||||
public Boolean ConnectedToDcBus => (_IoStates & 1) == 0;
|
||||
public Boolean ConnectedToDcBus => (_IoStates & 1) == 0;
|
||||
public Boolean Eoc => Leds is { Green: On, Amber: Off, Blue : Off };
|
||||
|
||||
public Strings Warnings => ParseWarnings().OrderBy(w => w).ToList();
|
||||
|
@ -28,13 +27,10 @@ public partial class Battery48TlRecord
|
|||
|
||||
// Time since TOC is a counter from the last moment when the battery reached EOC
|
||||
// When The battery is full charged (reached EOC) the Time Since TOC is set to 0
|
||||
public UInt16 TimeSinceTOC => _TimeSinceToc;
|
||||
|
||||
public Current BusCurrent => _BusCurrent;
|
||||
|
||||
public UInt16 TimeSinceTOC => _TimeSinceToc;
|
||||
public Current BusCurrent => _BusCurrent;
|
||||
public Current HeatingCurrent => _BusCurrent - _CellsCurrent;
|
||||
|
||||
public DcPower HeatingPower => HeatingCurrent * Dc.Voltage;
|
||||
public DcPower HeatingPower => HeatingCurrent * Dc.Voltage;
|
||||
|
||||
public Boolean CalibrationChargeRequested => TimeSinceTOC > OneWeekInMinutes;
|
||||
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
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 AlarmMessage = InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes.AlarmMessage;
|
||||
using WarningMessage = InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes.WarningMessage;
|
||||
using static System.Math;
|
||||
|
||||
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Status;
|
||||
|
||||
|
@ -77,30 +77,26 @@ public class AcDcStatus
|
|||
|
||||
private AcPhase L1 => new()
|
||||
{
|
||||
Current = _Self.GridCurrentL1,
|
||||
Voltage = _Self.GridVoltageL1,
|
||||
Current = Abs(_Self.GridCurrentL1),
|
||||
Voltage = Abs(_Self.GridVoltageL1),
|
||||
Phi = Atan2(_Self.ReactivePowerL1, _Self.ActivePowerL1)
|
||||
};
|
||||
|
||||
private AcPhase L2 => new()
|
||||
{
|
||||
Current = _Self.GridCurrentL2,
|
||||
Voltage = _Self.GridVoltageL2,
|
||||
Current = Abs(_Self.GridCurrentL2),
|
||||
Voltage = Abs(_Self.GridVoltageL2),
|
||||
Phi = Atan2(_Self.ReactivePowerL2, _Self.ActivePowerL2)
|
||||
};
|
||||
|
||||
private AcPhase L3 => new()
|
||||
{
|
||||
Current = _Self.GridCurrentL3,
|
||||
Voltage = _Self.GridVoltageL3,
|
||||
Current = Abs(_Self.GridCurrentL3),
|
||||
Voltage = Abs(_Self.GridVoltageL3),
|
||||
Phi = Atan2(_Self.ReactivePowerL3, _Self.ActivePowerL3)
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
internal AcDcStatus(AcDcRecord self) => _Self = self;
|
||||
private readonly AcDcRecord _Self;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -4,9 +4,9 @@ namespace InnovEnergy.Lib.Units.Composite;
|
|||
|
||||
public record AcPhase
|
||||
{
|
||||
public required Voltage Voltage { get; init; }
|
||||
public required Current Current { get; init; }
|
||||
public required Angle Phi { get; init; }
|
||||
public required VoltageRms Voltage { get; init; }
|
||||
public required CurrentRms Current { get; init; }
|
||||
public required Angle Phi { get; init; }
|
||||
|
||||
public AcPower Power => new()
|
||||
{
|
||||
|
|
|
@ -9,5 +9,4 @@ public sealed class Current : Unit
|
|||
|
||||
public static implicit operator Current(Double d) => new Current(d);
|
||||
public static implicit operator Double(Current d) => d.Value;
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
namespace InnovEnergy.Lib.Units;
|
||||
|
||||
public sealed class CurrentRms : Unit
|
||||
{
|
||||
public override String Symbol => "A~";
|
||||
|
||||
public CurrentRms(Double value) : base(value)
|
||||
{
|
||||
if (value < 0)
|
||||
throw new ArgumentException("RMS value cannot be negative", nameof(value));
|
||||
}
|
||||
|
||||
public static implicit operator CurrentRms(Double d) => new CurrentRms(d);
|
||||
public static implicit operator Double(CurrentRms d) => d.Value;
|
||||
}
|
|
@ -6,6 +6,8 @@ public sealed class ApparentPower : Power
|
|||
|
||||
public ApparentPower(Double value) : base(value)
|
||||
{
|
||||
if (value < 0)
|
||||
throw new ArgumentException($"{nameof(ApparentPower)} cannot be negative by definition.", nameof(value));
|
||||
}
|
||||
|
||||
public static implicit operator ApparentPower(Double d) => new ApparentPower(d);
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
|
||||
namespace InnovEnergy.Lib.Units;
|
||||
|
||||
public sealed class Voltage : Unit
|
||||
{
|
||||
public override String Symbol => "V";
|
||||
|
||||
public Voltage(Double value) : base(value)
|
||||
{}
|
||||
public Voltage(Double value) : base(value) {}
|
||||
|
||||
public static implicit operator Voltage(Double d) => new Voltage(d);
|
||||
public static implicit operator Double(Voltage d) => d.Value;
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
namespace InnovEnergy.Lib.Units;
|
||||
|
||||
public sealed class VoltageRms : Unit
|
||||
{
|
||||
public override String Symbol => "V~";
|
||||
|
||||
public VoltageRms(Double value) : base(value)
|
||||
{
|
||||
if (value < 0)
|
||||
throw new ArgumentException("RMS value cannot be negative", nameof(value));
|
||||
}
|
||||
|
||||
public static implicit operator VoltageRms(Double d) => new VoltageRms(d);
|
||||
public static implicit operator Double(VoltageRms d) => d.Value;
|
||||
}
|
Loading…
Reference in New Issue