483 lines
13 KiB
C#
483 lines
13 KiB
C#
using InnovEnergy.App.SaliMax.Ess;
|
|
using InnovEnergy.App.SaliMax.SaliMaxRelays;
|
|
using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc;
|
|
using InnovEnergy.Lib.Devices.Trumpf.TruConvertDc;
|
|
using static InnovEnergy.Lib.Devices.Trumpf.SystemControl.DataTypes.GridType;
|
|
|
|
namespace InnovEnergy.App.SaliMax.System;
|
|
|
|
public static class Controller
|
|
{
|
|
private static Int32 GetSystemState(this StatusRecord r)
|
|
{
|
|
var relays = r.Relays;
|
|
|
|
if (relays is null)
|
|
return 101; // Message = "Panic: relay device is not available!",
|
|
|
|
var acDcs = r.AcDc;
|
|
|
|
if (acDcs.NotAvailable())
|
|
return 102;
|
|
|
|
var k4 = acDcs.AllGridTied() ? 0
|
|
: acDcs.AllIsland() ? 1
|
|
: 4;
|
|
|
|
var k5 = acDcs.AllDisabled() ? 0
|
|
: acDcs.AllEnabled() ? 1
|
|
: 4;
|
|
|
|
if (k4 == 4 || k5 == 4)
|
|
return 103; //Message = "Panic: ACDCs have unequal grid types or power stage",
|
|
|
|
var nInverters = r.AcDc.Devices.Count;
|
|
|
|
var k1 = relays.K1GridBusIsConnectedToGrid ? 1 : 0;
|
|
var k2 = relays.K2IslandBusIsConnectedToGridBus ? 1 : 0;
|
|
var k3 = relays.K3InverterIsConnectedToIslandBus.Take(nInverters).Any(c => c) ? 1 : 0;
|
|
|
|
|
|
// states as defined in states excel sheet
|
|
return 1 * k1
|
|
+ 2 * k2
|
|
+ 4 * k3
|
|
+ 8 * k4
|
|
+ 16 * k5;
|
|
}
|
|
|
|
public static Boolean ControlSystemState(this StatusRecord s)
|
|
{
|
|
s.StateMachine.State = s.GetSystemState();
|
|
|
|
return s.StateMachine.State switch
|
|
{
|
|
0 => State0(s),
|
|
1 => State1(s),
|
|
3 => State3(s),
|
|
4 => State4(s),
|
|
6 => State6(s),
|
|
8 => State8(s),
|
|
9 => State9(s),
|
|
13 => State13(s),
|
|
19 => State19(s),
|
|
22 => State22(s),
|
|
23 => State23(s),
|
|
24 => State24(s),
|
|
28 => State28(s),
|
|
29 => State29(s),
|
|
|
|
|
|
101 => State101(s),
|
|
102 => State102(s),
|
|
103 => State103(s),
|
|
_ => UnknownState(s)
|
|
};
|
|
|
|
}
|
|
|
|
private static Boolean NotAvailable(this AcDcDevicesRecord acDcs)
|
|
{
|
|
return acDcs.SystemControl == null || acDcs.Devices.Count == 0;
|
|
}
|
|
|
|
private static Boolean State0(StatusRecord s)
|
|
{
|
|
s.StateMachine.Message = "Ac/Dc are off. Switching to Island Mode.";
|
|
|
|
s.DcDc.Disable();
|
|
s.AcDc.Disable();
|
|
s.AcDc.EnableIslandMode();
|
|
s.Relays.DisconnectIslandBusFromGrid();
|
|
|
|
return false;
|
|
|
|
// => 8
|
|
}
|
|
|
|
private static Boolean State9(StatusRecord s)
|
|
{
|
|
s.StateMachine.Message = "Ac/Dc are disconnected from Island Bus. Switching to GridTie Mode.";
|
|
|
|
s.DcDc.Disable();
|
|
s.AcDc.Disable();
|
|
s.AcDc.EnableGridTieMode();
|
|
s.Relays.DisconnectIslandBusFromGrid();
|
|
|
|
return false;
|
|
|
|
// => 1
|
|
}
|
|
|
|
private static Boolean State1(StatusRecord s)
|
|
{
|
|
s.StateMachine.Message = "Grid Tied mode active, closing k2";
|
|
|
|
s.DcDc.Disable();
|
|
s.AcDc.Disable();
|
|
s.AcDc.EnableGridTieMode();
|
|
s.Relays.ConnectIslandBusToGrid();
|
|
|
|
return false;
|
|
|
|
// => 3
|
|
}
|
|
|
|
private static Boolean State3(StatusRecord s)
|
|
{
|
|
s.StateMachine.Message = "K2 closed, Turning on Ac/Dc";
|
|
|
|
s.DcDc.Enable();
|
|
s.AcDc.Enable();
|
|
s.AcDc.EnableGridTieMode();
|
|
s.Relays.ConnectIslandBusToGrid();
|
|
|
|
return false;
|
|
|
|
// => 19
|
|
}
|
|
|
|
private static Boolean State13(StatusRecord s)
|
|
{
|
|
s.StateMachine.Message = "Ac/Dc are off. Waiting for them to disconnect from Island Bus.";
|
|
|
|
s.DcDc.Disable();
|
|
s.AcDc.Disable();
|
|
s.AcDc.EnableIslandMode();
|
|
s.Relays.DisconnectIslandBusFromGrid();
|
|
|
|
return true;
|
|
|
|
// => 9
|
|
}
|
|
|
|
|
|
|
|
private static Boolean State19(StatusRecord s)
|
|
{
|
|
s.StateMachine.Message = "Waiting for Ac/Dc to connect to Island Bus";
|
|
|
|
s.DcDc.Enable();
|
|
s.AcDc.Enable();
|
|
s.AcDc.EnableGridTieMode();
|
|
s.Relays.ConnectIslandBusToGrid();
|
|
|
|
return true;
|
|
|
|
// => 23
|
|
}
|
|
|
|
|
|
private static Boolean State23(StatusRecord s)
|
|
{
|
|
s.StateMachine.Message = "ESS";
|
|
|
|
s.DcDc.Enable();
|
|
s.AcDc.Enable();
|
|
s.AcDc.EnableGridTieMode();
|
|
s.EnableDcLinkGridTie();
|
|
s.Relays.ConnectIslandBusToGrid();
|
|
|
|
return true;
|
|
|
|
// => 22
|
|
}
|
|
|
|
private static Boolean State22(StatusRecord s)
|
|
{
|
|
s.StateMachine.Message = "K1 opened, switching inverters off";
|
|
|
|
s.DcDc.Disable();
|
|
s.AcDc.Disable();
|
|
s.AcDc.EnableGridTieMode();
|
|
s.Relays.ConnectIslandBusToGrid();
|
|
|
|
return true;
|
|
|
|
// => 6
|
|
}
|
|
|
|
|
|
private static Boolean State6(StatusRecord s)
|
|
{
|
|
s.StateMachine.Message = "Inverters are off, opening K2";
|
|
|
|
s.DcDc.Disable();
|
|
s.AcDc.Disable();
|
|
s.AcDc.EnableGridTieMode();
|
|
s.Relays.DisconnectIslandBusFromGrid();
|
|
|
|
return true;
|
|
|
|
// => 4
|
|
}
|
|
|
|
private static Boolean State4(StatusRecord s)
|
|
{
|
|
s.StateMachine.Message = "K2 is open, waiting K3 to open";
|
|
|
|
s.DcDc.Disable();
|
|
s.AcDc.Disable();
|
|
s.AcDc.EnableGridTieMode();
|
|
s.Relays.DisconnectIslandBusFromGrid();
|
|
|
|
return true;
|
|
|
|
// => 0
|
|
}
|
|
|
|
private static Boolean State8(StatusRecord s)
|
|
{
|
|
s.StateMachine.Message = "Ac/Dc are off and in Island Mode.";
|
|
|
|
s.DcDc.Enable();
|
|
s.AcDc.Enable();
|
|
s.AcDc.EnableIslandMode();
|
|
s.Relays.DisconnectIslandBusFromGrid();
|
|
|
|
return true;
|
|
// => 24
|
|
}
|
|
|
|
private static Boolean State28(StatusRecord s)
|
|
{
|
|
s.StateMachine.Message = "Island Mode";
|
|
|
|
s.DcDc.Enable();
|
|
s.AcDc.Enable();
|
|
s.AcDc.EnableIslandMode();
|
|
s.EnableDcLinkIslandMode();
|
|
s.Relays.DisconnectIslandBusFromGrid();
|
|
|
|
return false;
|
|
|
|
// => 29
|
|
}
|
|
|
|
private static Boolean State29(StatusRecord s)
|
|
{
|
|
s.StateMachine.Message = "K1 closed, Switching off Inverters and moving to grid tie";
|
|
|
|
s.DcDc.Disable();
|
|
s.AcDc.Disable();
|
|
s.AcDc.EnableIslandMode();
|
|
s.Relays.DisconnectIslandBusFromGrid();
|
|
|
|
return false;
|
|
|
|
// => 13
|
|
}
|
|
|
|
private static Boolean State24(StatusRecord s)
|
|
{
|
|
s.StateMachine.Message = "Inverter are on waiting for k3 to close";
|
|
|
|
s.DcDc.Enable();
|
|
s.AcDc.Enable();
|
|
s.AcDc.EnableIslandMode();
|
|
s.Relays.DisconnectIslandBusFromGrid();
|
|
|
|
return false;
|
|
|
|
// => 28
|
|
}
|
|
|
|
private static Boolean State101(StatusRecord s)
|
|
{
|
|
s.StateMachine.Message = "Relay device is not available";
|
|
return s.EnableSafeDefaults();
|
|
}
|
|
|
|
private static Boolean State102(StatusRecord s)
|
|
{
|
|
s.StateMachine.Message = "ACDCs not available";
|
|
return s.EnableSafeDefaults();
|
|
}
|
|
|
|
private static Boolean State103(StatusRecord s)
|
|
{
|
|
s.StateMachine.Message = "Panic: ACDCs have unequal grid types or PowerStage";
|
|
return s.EnableSafeDefaults();
|
|
}
|
|
|
|
// private static Boolean State104(StatusRecord s)
|
|
// {
|
|
// s.StateMachine.Message = "Panic: DCDCs not available";
|
|
// return s.EnableSafeDefaults();
|
|
// }
|
|
|
|
|
|
private static Boolean UnknownState(StatusRecord s)
|
|
{
|
|
// "Unknown System State"
|
|
return s.EnableSafeDefaults();
|
|
}
|
|
|
|
|
|
|
|
private static Boolean AllDisabled(this AcDcDevicesRecord acDcs)
|
|
{
|
|
return acDcs.Devices.All(d => !d.Control.PowerStageEnable);
|
|
}
|
|
|
|
private static Boolean AllEnabled(this AcDcDevicesRecord acDcs)
|
|
{
|
|
return acDcs.Devices.All(d => d.Control.PowerStageEnable);
|
|
}
|
|
|
|
|
|
private static Boolean AllTheSame(this AcDcDevicesRecord acDcs)
|
|
{
|
|
return acDcs.Devices
|
|
.Select(d => d.Control.PowerStageEnable)
|
|
.Distinct()
|
|
.Count() == 1;
|
|
}
|
|
|
|
private static Boolean AllGridTied(this AcDcDevicesRecord acDcs)
|
|
{
|
|
return acDcs.Devices.All(d => d.Status.ActiveGridType is GridTied380V60Hz)
|
|
|| acDcs.Devices.All(d => d.Status.ActiveGridType is GridTied400V50Hz)
|
|
|| acDcs.Devices.All(d => d.Status.ActiveGridType is GridTied480V60Hz);
|
|
}
|
|
|
|
private static Boolean AllIsland(this AcDcDevicesRecord acDcs)
|
|
{
|
|
return acDcs.Devices.All(d => d.Status.ActiveGridType is Island400V50Hz)
|
|
|| acDcs.Devices.All(d => d.Status.ActiveGridType is Island480V60Hz);
|
|
}
|
|
|
|
private static void ForAll<T>(this IEnumerable<T> ts, Action<T> action)
|
|
{
|
|
foreach (var t in ts)
|
|
action(t);
|
|
}
|
|
|
|
private static void Disable(this AcDcDevicesRecord acDc)
|
|
{
|
|
acDc.Devices
|
|
.Select(d => d.Control)
|
|
.ForAll(c => c.PowerStageEnable = false);
|
|
}
|
|
|
|
|
|
private static void Disable(this DcDcDevicesRecord dcDc)
|
|
{
|
|
// For Test purpose, The transition from island mode to grid tier and vis versa , may not need to disable Dc/Dc.
|
|
// This will keep the Dc link powered.
|
|
|
|
// dcDc.Devices
|
|
// .Select(d => d.Control)
|
|
// .ForAll(c => c.PowerStageEnable = false);
|
|
}
|
|
|
|
private static void Enable(this AcDcDevicesRecord acDc)
|
|
{
|
|
acDc.Devices
|
|
.Select(d => d.Control)
|
|
.ForAll(c => c.PowerStageEnable = true);
|
|
}
|
|
|
|
private static void Enable(this DcDcDevicesRecord dcDc)
|
|
{
|
|
dcDc.Devices
|
|
.Select(d => d.Control)
|
|
.ForAll(c => c.PowerStageEnable = true);
|
|
}
|
|
|
|
|
|
private static void EnableGridTieMode(this AcDcDevicesRecord acDc)
|
|
{
|
|
acDc.Devices
|
|
.Select(d => d.Control)
|
|
.ForAll(c => c.Ac.GridType = GridTied400V50Hz); // TODO: config grid type
|
|
}
|
|
|
|
|
|
private static void EnableIslandMode(this AcDcDevicesRecord acDc)
|
|
{
|
|
acDc.Devices
|
|
.Select(d => d.Control)
|
|
.ForAll(c => c.Ac.GridType = Island400V50Hz); // TODO: config grid type
|
|
}
|
|
|
|
// This is must be deleted , not needed anymore
|
|
private static void EnableDcLinkIslandMode(this StatusRecord s)
|
|
{
|
|
// // Dc Link Windows on AcDc +- 60
|
|
// s.Config.ReferenceDcLinkVoltageFromAcDc ;
|
|
// s.Config.MinDcLinkVoltageFromAcDc ;
|
|
// s.Config.MaxDcLinkVoltageFromAcDc ;
|
|
//
|
|
// // Dc Link Windows on DcDc +-55
|
|
// s.Config.ReferenceDcLinkVoltageFromDc = 750;
|
|
// s.Config.UpperDcLinkVoltageFromDc = 55;
|
|
// s.Config.LowerDcLinkVoltageFromDc = 55;
|
|
}
|
|
|
|
// This is must be deleted , not needed anymore
|
|
private static void EnableDcLinkGridTie(this StatusRecord s)
|
|
{
|
|
// Dc Link Windows on DcDc +-30
|
|
|
|
//s.Config.ReferenceDcLinkVoltageFromAcDc = 750;
|
|
//s.Config.MinDcLinkVoltageFromAcDc = 720;
|
|
//s.Config.MaxDcLinkVoltageFromAcDc = 780;
|
|
//
|
|
//// Dc Link Windows on DcDc +-20
|
|
//s.Config.ReferenceDcLinkVoltageFromDc = 750;
|
|
//s.Config.UpperDcLinkVoltageFromDc = 20;
|
|
//s.Config.LowerDcLinkVoltageFromDc = 20;
|
|
}
|
|
|
|
private static void DisconnectIslandBusFromGrid(this RelaysRecord? relays)
|
|
{
|
|
if (relays is not null)
|
|
relays.K2ConnectIslandBusToGridBus = false;
|
|
}
|
|
|
|
private static void ConnectIslandBusToGrid(this RelaysRecord? relays)
|
|
{
|
|
if (relays is not null)
|
|
relays.K2ConnectIslandBusToGridBus = true;
|
|
}
|
|
|
|
|
|
private static Boolean EnableSafeDefaults(this StatusRecord s)
|
|
{
|
|
// After some tests, the safe state is switch off inverter and keep the last state of K2 , Dc/Dc and Grid type to avoid conflict.
|
|
|
|
// s.DcDc.Disable();
|
|
s.AcDc.Disable();
|
|
// s.AcDc.EnableGridTieMode();
|
|
// s.Relays.DisconnectIslandBusFromGrid();
|
|
return false;
|
|
}
|
|
|
|
public static DcDcDevicesRecord ResetAlarms(this DcDcDevicesRecord dcDcStatus)
|
|
{
|
|
var sc = dcDcStatus.SystemControl;
|
|
|
|
if (sc is not null)
|
|
sc.ResetAlarmsAndWarnings = sc.Alarms.Any();
|
|
|
|
foreach (var d in dcDcStatus.Devices)
|
|
d.Control.ResetAlarmsAndWarnings = d.Status.Alarms.Any() || d.Status.Warnings.Any();
|
|
|
|
return dcDcStatus;
|
|
}
|
|
|
|
public static AcDcDevicesRecord ResetAlarms(this AcDcDevicesRecord acDcStatus)
|
|
{
|
|
var sc = acDcStatus.SystemControl;
|
|
|
|
if (sc is not null)
|
|
sc.ResetAlarmsAndWarnings = sc.Alarms.Any() || sc.Warnings.Any();
|
|
|
|
foreach (var d in acDcStatus.Devices)
|
|
d.Control.ResetAlarmsAndWarnings = d.Status.Alarms.Any() || d.Status.Warnings.Any();
|
|
|
|
return acDcStatus;
|
|
}
|
|
|
|
} |