Add curtailing algorithm and all what needed for execution

This commit is contained in:
atef 2024-08-02 13:39:51 +02:00
parent 8d00d7ede9
commit ac52c098e6
1 changed files with 94 additions and 54 deletions

View File

@ -1,4 +1,4 @@
#define Amax #undef Amax
#undef GridLimit #undef GridLimit
using System.Diagnostics; using System.Diagnostics;
@ -54,6 +54,7 @@ internal static class Program
private static readonly Channel RelaysChannel; private static readonly Channel RelaysChannel;
private static readonly Channel BatteriesChannel; private static readonly Channel BatteriesChannel;
private static Boolean _curtailFlag = false;
private const String VpnServerIp = "10.2.0.11"; private const String VpnServerIp = "10.2.0.11";
private static Boolean _subscribedToQueue = false; private static Boolean _subscribedToQueue = false;
private static Boolean _subscribeToQueueForTheFirstTime = false; private static Boolean _subscribeToQueueForTheFirstTime = false;
@ -232,7 +233,7 @@ internal static class Program
record.ControlConstants(); record.ControlConstants();
record.ControlSystemState(); record.ControlSystemState();
record.ControlPvPower(record.Config.CurtailP); record.ControlPvPower(record.Config.CurtailP, record.Config.PvInstalledPower);
var essControl = record.ControlEss().WriteLine(); var essControl = record.ControlEss().WriteLine();
@ -332,6 +333,8 @@ internal static class Program
else if (IsPowerOfTwo(battery.LimpBitMap)) else if (IsPowerOfTwo(battery.LimpBitMap))
{ {
"1 String is disabled".WriteLine(); "1 String is disabled".WriteLine();
Console.WriteLine(" ****************** ");
warningList.Add(new AlarmOrWarning warningList.Add(new AlarmOrWarning
{ {
Date = DateTime.Now.ToString("yyyy-MM-dd"), Date = DateTime.Now.ToString("yyyy-MM-dd"),
@ -345,6 +348,7 @@ internal static class Program
else else
{ {
"2 or more string are disabled".WriteLine(); "2 or more string are disabled".WriteLine();
Console.WriteLine(" ****************** ");
alarmList.Add(new AlarmOrWarning alarmList.Add(new AlarmOrWarning
{ {
@ -532,69 +536,87 @@ internal static class Program
} }
// This will be used for provider throttling, this example is only for either 100% or 0 % // This will be used for provider throttling, this example is only for either 100% or 0 %
private static void ControlPvPower(this StatusRecord r, UInt16 exportLimit = 100) private static void ControlPvPower(this StatusRecord r, UInt16 exportLimit = 0, UInt16 pvInstalledPower = 20)
{ {
const UInt16 stableFactor = 500; if (r.GridMeter?.Ac.Power.Active == null)
var inverters = r.AcDc.Devices;
var configFile = r.Config;
var systemProduction = inverters.Count * 25000; // this should be from to the PV
var limitSystemProduction = systemProduction * exportLimit / 100;
var devicesConfig = r.AcDc.Devices.All(d => d.Control.Ac.GridType == GridType.GridTied400V50Hz) ? configFile.GridTie : configFile.IslandMode; // TODO if any of the grid tie mode
var targetReferenceVoltage = devicesConfig.AcDc.ReferenceDcLinkVoltage;
if (r.PvOnDc.Dc.Power != null && r.PvOnDc.Dc.Power > limitSystemProduction)
{ {
exportLimit.WriteLine(" exportLimit"); Console.WriteLine(" No reading from Grid meter");
systemProduction.WriteLine(" systemProduction"); return;
limitSystemProduction.WriteLine(" limit System export"); }
targetReferenceVoltage.WriteLine("targetReferenceVoltage");
if (r.GridMeter?.Ac.Power.Active != null) if (pvInstalledPower == 0)
{
Console.WriteLine(" No curtailing, because Pv installed is equal to 0");
return;
}
const Int32 constantDeadBand = 5000; // magic number
const Double voltageRange = 100; // 100 Voltage configured rang for PV slope, if the configured slope change this must change also
var configFile = r.Config;
var inverters = r.AcDc.Devices;
var systemExportLimit = -exportLimit * 1000 ; // Conversion from Kw in W
var stepSize = ClampStepSize((UInt16)Math.Floor(voltageRange/ pvInstalledPower)); // in Voltage per 1 Kw
var deadBand = constantDeadBand/stepSize;
// LINQ query to select distinct ActiveUpperVoltage
var result = r.AcDc.Devices
.Select(device => device?.Status?.DcVoltages?.Active?.ActiveUpperVoltage)
.Select(voltage => voltage.Value) // Extract the value since we've confirmed it's non-null
.Distinct()
.ToList();
var upperVoltage = result.Count == 1 ? result[0] : 0;
/************* For debugging purposes ********************/
systemExportLimit.WriteLine(" Export Limit in W");
upperVoltage.WriteLine(" Upper Voltage");
r.GridMeter.Ac.Power.Active.WriteLine(" Active Export");
Console.WriteLine(" ****************** ");
/*********************************************************/
if (r.GridMeter.Ac.Power.Active < systemExportLimit)
{
_curtailFlag = true;
upperVoltage = IncreaseInverterUpperLimit(upperVoltage, stepSize);
upperVoltage.WriteLine("Upper Voltage Increased: New Upper limit");
}
else
{
if (_curtailFlag)
{ {
if (r.GridMeter.Ac.Power.Active < -limitSystemProduction) if (r.GridMeter.Ac.Power.Active > (systemExportLimit + deadBand))
{ {
"We are openning the window".WriteLine(); upperVoltage = DecreaseInverterUpperLimit(upperVoltage, stepSize);
//r.Config.GridSetPoint = -limitSystemProduction + stableFactor; if (upperVoltage <= configFile.GridTie.AcDc.MaxDcLinkVoltage)
//r.Config.GridSetPoint.WriteLine(" Grid set point");
var maxDcLinkVoltage = (UInt16)(r.Config.GridTie.AcDc.MaxDcLinkVoltage + 10);
r.Config.GridTie.AcDc.MaxDcLinkVoltage = maxDcLinkVoltage;
maxDcLinkVoltage.WriteLine("maxDcLinkVoltage");
}
else if (r.GridMeter.Ac.Power.Active > -limitSystemProduction + stableFactor * 4)
{
"We are closing the window".WriteLine();
//r.Config.GridSetPoint = -limitSystemProduction + stableFactor;
//r.Config.GridSetPoint.WriteLine(" Grid set point");
if ((r.Config.GridTie.AcDc.MaxDcLinkVoltage - r.Config.GridTie.AcDc.MinDcLinkVoltage) > 60)
{ {
var maxDcLinkVoltage = (UInt16)(r.Config.GridTie.AcDc.MaxDcLinkVoltage - 10); _curtailFlag = false;
r.Config.GridTie.AcDc.MaxDcLinkVoltage = maxDcLinkVoltage; upperVoltage = configFile.GridTie.AcDc.MaxDcLinkVoltage;
maxDcLinkVoltage.WriteLine("maxDcLinkVoltage"); upperVoltage.WriteLine(" New Upper limit");
Console.WriteLine("Upper Voltage decreased: Smaller than the default value, value clamped");
} }
else else
{ {
"do nothing".WriteLine(); Console.WriteLine("Upper Voltage decreased: New Upper limit");
upperVoltage.WriteLine(" New Upper limit");
} }
} }
else else
{ {
r.Config.GridTie.AcDc.MaxDcLinkVoltage.WriteLine("maxDcLinkVoltage"); deadBand.WriteLine("W :We are in Dead band area");
r.Config.GridTie.DcDc.UpperDcLinkVoltage.WriteLine("maxDcDcLinkVoltage"); upperVoltage.WriteLine(" same Upper limit from last cycle");
} }
} }
else
//if (exportLimit == 100) {
//{ Console.WriteLine("Curtail Flag is false , no need to curtail");
// r.Config.GridSetPoint = 0; upperVoltage.WriteLine(" same Upper limit from last cycle");
//} }
} }
inverters.ForEach(d => d.Control.Dc.MaxVoltage = upperVoltage);
Console.WriteLine(" ****************** ");
} }
// why this is not in Controller? // why this is not in Controller?
@ -615,6 +637,26 @@ internal static class Program
}); });
} }
private static Double IncreaseInverterUpperLimit(Double upperLimit, Double stepSize)
{
return upperLimit + stepSize;
}
private static Double DecreaseInverterUpperLimit(Double upperLimit, Double stepSize)
{
return upperLimit - stepSize;
}
private static UInt16 ClampStepSize(UInt16 stepSize)
{
return stepSize switch
{
> 5 => 5,
<= 1 => 1,
_ => stepSize
};
}
private static void ApplyAcDcDefaultSettings(this SystemControlRegisters? sc) private static void ApplyAcDcDefaultSettings(this SystemControlRegisters? sc)
{ {
if (sc is null) if (sc is null)
@ -798,7 +840,5 @@ internal static class Program
{ {
status.Config.DayAndTimeForAdditionalCalibration = config.CalibrationChargeDate; status.Config.DayAndTimeForAdditionalCalibration = config.CalibrationChargeDate;
} }
} }
} }