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
|
||||
|
||||
using System.Diagnostics;
|
||||
|
@ -54,6 +54,7 @@ internal static class Program
|
|||
private static readonly Channel RelaysChannel;
|
||||
private static readonly Channel BatteriesChannel;
|
||||
|
||||
private static Boolean _curtailFlag = false;
|
||||
private const String VpnServerIp = "10.2.0.11";
|
||||
private static Boolean _subscribedToQueue = false;
|
||||
private static Boolean _subscribeToQueueForTheFirstTime = false;
|
||||
|
@ -232,7 +233,7 @@ internal static class Program
|
|||
record.ControlConstants();
|
||||
record.ControlSystemState();
|
||||
|
||||
record.ControlPvPower(record.Config.CurtailP);
|
||||
record.ControlPvPower(record.Config.CurtailP, record.Config.PvInstalledPower);
|
||||
|
||||
var essControl = record.ControlEss().WriteLine();
|
||||
|
||||
|
@ -332,6 +333,8 @@ internal static class Program
|
|||
else if (IsPowerOfTwo(battery.LimpBitMap))
|
||||
{
|
||||
"1 String is disabled".WriteLine();
|
||||
Console.WriteLine(" ****************** ");
|
||||
|
||||
warningList.Add(new AlarmOrWarning
|
||||
{
|
||||
Date = DateTime.Now.ToString("yyyy-MM-dd"),
|
||||
|
@ -345,7 +348,8 @@ internal static class Program
|
|||
else
|
||||
{
|
||||
"2 or more string are disabled".WriteLine();
|
||||
|
||||
Console.WriteLine(" ****************** ");
|
||||
|
||||
alarmList.Add(new AlarmOrWarning
|
||||
{
|
||||
Date = DateTime.Now.ToString("yyyy-MM-dd"),
|
||||
|
@ -532,69 +536,87 @@ internal static class Program
|
|||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
const UInt16 stableFactor = 500;
|
||||
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)
|
||||
private static void ControlPvPower(this StatusRecord r, UInt16 exportLimit = 0, UInt16 pvInstalledPower = 20)
|
||||
{
|
||||
if (r.GridMeter?.Ac.Power.Active == null)
|
||||
{
|
||||
exportLimit.WriteLine(" exportLimit");
|
||||
systemProduction.WriteLine(" systemProduction");
|
||||
limitSystemProduction.WriteLine(" limit System export");
|
||||
targetReferenceVoltage.WriteLine("targetReferenceVoltage");
|
||||
Console.WriteLine(" No reading from Grid meter");
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
//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)
|
||||
if (upperVoltage <= configFile.GridTie.AcDc.MaxDcLinkVoltage)
|
||||
{
|
||||
var maxDcLinkVoltage = (UInt16)(r.Config.GridTie.AcDc.MaxDcLinkVoltage - 10);
|
||||
r.Config.GridTie.AcDc.MaxDcLinkVoltage = maxDcLinkVoltage;
|
||||
maxDcLinkVoltage.WriteLine("maxDcLinkVoltage");
|
||||
_curtailFlag = false;
|
||||
upperVoltage = configFile.GridTie.AcDc.MaxDcLinkVoltage;
|
||||
upperVoltage.WriteLine(" New Upper limit");
|
||||
Console.WriteLine("Upper Voltage decreased: Smaller than the default value, value clamped");
|
||||
}
|
||||
else
|
||||
{
|
||||
"do nothing".WriteLine();
|
||||
Console.WriteLine("Upper Voltage decreased: New Upper limit");
|
||||
upperVoltage.WriteLine(" New Upper limit");
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
r.Config.GridTie.AcDc.MaxDcLinkVoltage.WriteLine("maxDcLinkVoltage");
|
||||
r.Config.GridTie.DcDc.UpperDcLinkVoltage.WriteLine("maxDcDcLinkVoltage");
|
||||
{
|
||||
deadBand.WriteLine("W :We are in Dead band area");
|
||||
upperVoltage.WriteLine(" same Upper limit from last cycle");
|
||||
}
|
||||
}
|
||||
|
||||
//if (exportLimit == 100)
|
||||
//{
|
||||
// r.Config.GridSetPoint = 0;
|
||||
//}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Curtail Flag is false , no need to curtail");
|
||||
upperVoltage.WriteLine(" same Upper limit from last cycle");
|
||||
}
|
||||
}
|
||||
inverters.ForEach(d => d.Control.Dc.MaxVoltage = upperVoltage);
|
||||
Console.WriteLine(" ****************** ");
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
if (sc is null)
|
||||
|
@ -797,8 +839,6 @@ internal static class Program
|
|||
else if (config.CalibrationChargeState == CalibrationChargeType.AdditionallyOnce)
|
||||
{
|
||||
status.Config.DayAndTimeForAdditionalCalibration = config.CalibrationChargeDate;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue