Add curtailing algorithm and all what needed for execution
This commit is contained in:
parent
8d00d7ede9
commit
ac52c098e6
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue