No discharge throught inverter xErrorShutdown : BOOL; // Start in balancing mode xStartBalancing : BOOL; // String in safety check mode xInSafetyCheckMode : BOOL; // Operating mode of string eOperationMode : E_STRING_OPERATING_MODE; // Requested inverter power rPowerInverter : REAL; // String HMI interface stHMIInterface : REFERENCE TO ST_STRING_HMI_INTERFACE; // Emergency stop ok xEmergencyStopOk : BOOL; // Reset Safety xResetSafety : BOOL; // Release alarms xReleaseErrors : BOOL; // Release analog io limit errors xReleaseLimitErrors : BOOL; // Release manual mode xReleaseManualMode : BOOL; // Input to confirm all errors xConfirmAlarms : BOOL; // Switch all components to manual mode xAllToManualMode : BOOL; // String inverter ip sInverterIP : STRING; timInverterStartupTimeout : TIME; xECWcState AT %I* : BOOL; xIsolationOKL1 AT %I* : BOOL; xIsolationOKL2 AT %I* : BOOL; refuStringErrorsModbus : REFERENCE TO U_STRING_ERROR_REGISTER; END_VAR VAR_OUTPUT // Repair switch closed xRepairSwitchOk AT %I* : BOOL; // Safety communication error {attribute 'analysis' := '-33'} xSafetyComError AT %I* : BOOL; // All safetyinterlocks from safety plc are ok xSafetyIntlksOk AT %I* : BOOL; // All component safety interlocks are ok xSafetyIntlksComponentsOk : BOOL; // Current string voltage rCurrentVoltage : REAL; // Module in shutdown segment discharge mode xInShutdownDischargeMode : BOOL; // Module can be discharged during shutdown sequence xShutdownDischargeAllowed : BOOL; // String ready xReady : BOOL; // String completely off xOff : BOOL; // Signal to close dc circuit breaker xCloseDCCB AT %Q* : BOOL; // Signal that dc circuit breakers are closed xDCCBOpen AT %I* : BOOL; // Reset signal for safety dc circuit breaker xResetSafetyDCCB AT %Q* : BOOL; // All modules in automatic mode xAllModulesInAutoMode : BOOL; xError : BOOL; xWarning : BOOL; // Temperature control cabinet module 1 above 40 °C xTempCabinetModule1Warning : BOOL; // Temperature control cabinet module 2 above 40 °C xTempCabinetModule2Warning : BOOL; // Temperature control cabinet module 3 above 40 °C xTempCabinetModule3Warning : BOOL; eStatus : E_COMPONENT_STATUS; // Inverter status data stInverterData : ST_SUNSPEC_CURRENT_VALUES; // Smallest segment voltage rSmallestSegmentVoltage : REAL; // Highest segment voltage rHighestSegmentVoltage : REAL; // Balancing done xBalancingDone : BOOL; // Inverter infos for EMS display stInverterInfos : ST_KACO_INFOS; END_VAR VAR _fbModule1 : FB_Module(CONCAT(Name,' - Module 1')); _fbModule2 : FB_Module(CONCAT(Name,' - Module 2')); _fbModule3 : FB_Module(CONCAT(Name,' - Module 3')); // All modules are ready _xAllModulesReady : BOOL; // All modules in shutdown discharge mode _xAllModulesInShutdownDischargeMode : BOOL; // Flag for module balance checking _xBalanceOk : BOOL; // Modules out of balance alarm message _fbModulesOutOfBalanceAlarm : Fb_TcAlarm; // Safetyinterlocks pending alarm _fbSafetyInterlocksNotOkAlarm : FB_TcAlarm; // Inverter startup error _fbInverterStartupTimeoutAlarm : FB_TcAlarm; // DC Main switch not closed _fbDCMainSwitchNotClosed : FB_TcAlarm; // Connection to SCS lost _fbSCSConnLost : FB_TcAlarm; // Isolatio alarm _fbIsolationAlarm : FB_TcAlarm; // Safety interlock reset timeout _fbSafetyIntlkTimeoutAlarm : FB_TcAlarm; // Shutdown discharge stopped messages _fbSDDCLevel : FB_TcMessage; _fbSDUnitThreshold : FB_TcMessage; // State for start and stop _iState : INT := 0; // Error timer for not closing dc relais _tonErrorDCCBNotClosed : TON := (PT := T#5S); // Delayed balance check signal _fbBalanceNotOkSignal : FB_ReleaseSignal; // String name _sName : STRING; // String inverter //_fbInverter : FB_PowerSupplySunspec(Name); _fbInverter : FB_PowerSupplyKaco(Name); // Internal inverter power command _rPowerInverterInternal : REAL; // Enable inverter flag _xEnableInverter : BOOL; // Fault timer for inverter startup _tonInverterStartupTimeout : TON; // Fault timer for inverter shutdown _tonInverterShutdownError : TON := (PT := T#10S); // Debug delay timer for inverter shutdown _tonInverterShutdownDelay : TON := (PT := T#10S); // Timer for Safety ok timeout _tonSafetyOkTimeout : TON := (PT := T#2M); // Analog input for string current measurement _fbStringCurrent : FB_AnalogInput(CONCAT(Name,' - Current')); _xErrorInverter : BOOL; _xReleaseLimitErrorsInternal : BOOL; _xReleaseSafetyIntlkErrors : BOOL; // Balancing done _xBalancingDone : BOOL; // Enable modules internal signal _xEnable : BOOL; // Start balancing internal signal _xStartBalancing : BOOL; _xIsoErrorActive : BOOL; _xIsoError : BOOL; // Iso error timeout _fbTONIsoError : TON; // Internal SOC _rSOC : REAL; _fbTONDCSettlingTime : TON := (PT := T#10S); _xErrorInternal : BOOL; _fbSafetyResetImpulseGen : FB_Blinker := (rFrequency := 2.0); END_VAR VAR PERSISTENT rCapacityWH : REAL; rCapacityAH : REAL; END_VAR ]]> , xWarning=> , rScaledValue=> , xErrorLow=> , xWarningLow=> , xWarningHigh=> , xErrorHigh=> , stHMIInterface=> ); // Copy scaled current value to HMI stHMIInterface.rCurrent := _fbStringCurrent.stHMIInterface.rValue; // =============================== // Module 1 // =============================== _fbModule1( xEnable := _xEnable, uiFirstUnitIndex := uiStringNumber * 12, rCurrent := stHMIInterface.rCurrent, xStartBalancing := _xStartBalancing, eStringOperatingMode := eOperationMode, xInverterEnabled := _fbInverter.xActive, xInSafetyCheckMode := xInSafetyCheckMode, xEmergencyStopOk:= xEmergencyStopOk, refstHMIInterface:= stHMIInterface.stHMIInterfaceModule1, xReleaseErrors:= xReleaseErrors, xReleaseLimitErrors:= xReleaseLimitErrors AND _xReleaseLimitErrorsInternal, xReleaseManualMode := xReleaseManualMode, xConfirmAlarms:= xConfirmAlarms, xAllToManualMode := xAllToManualMode, rBalancingTargetVoltage := rSmallestSegmentVoltage, xTempCabinetWarning => xTempCabinetModule1Warning); // =============================== // Module 2 // =============================== _fbModule2( xEnable := _xEnable, uiFirstUnitIndex := uiStringNumber * 12 + 4, rCurrent := stHMIInterface.rCurrent, xStartBalancing := _xStartBalancing, eStringOperatingMode := eOperationMode, xInverterEnabled := _fbInverter.xActive, xInSafetyCheckMode := xInSafetyCheckMode, xEmergencyStopOk:= xEmergencyStopOk, refstHMIInterface:= stHMIInterface.stHMIInterfaceModule2, xReleaseErrors:= xReleaseErrors, xReleaseLimitErrors:= xReleaseLimitErrors AND _xReleaseLimitErrorsInternal, xReleaseManualMode := xReleaseManualMode, xConfirmAlarms:= xConfirmAlarms, xAllToManualMode := xAllToManualMode, rBalancingTargetVoltage := rSmallestSegmentVoltage, xTempCabinetWarning => xTempCabinetModule2Warning); // =============================== // Module 3 // =============================== _fbModule3( xEnable := _xEnable, uiFirstUnitIndex := uiStringNumber * 12 + 8, rCurrent := stHMIInterface.rCurrent, xStartBalancing := _xStartBalancing, eStringOperatingMode := eOperationMode, xInverterEnabled := _fbInverter.xActive, xInSafetyCheckMode := xInSafetyCheckMode, xEmergencyStopOk:= xEmergencyStopOk, refstHMIInterface:= stHMIInterface.stHMIInterfaceModule3, xReleaseErrors:= xReleaseErrors, xReleaseLimitErrors:= xReleaseLimitErrors AND _xReleaseLimitErrorsInternal, xReleaseManualMode := xReleaseManualMode, xConfirmAlarms:= xConfirmAlarms, xAllToManualMode := xAllToManualMode, rBalancingTargetVoltage := rSmallestSegmentVoltage, xTempCabinetWarning => xTempCabinetModule3Warning); // =============================== // Handle modules warning state // =============================== xWarning := _fbModule1.xWarning OR _fbModule2.xWarning OR _fbModule3.xWarning; // =============================== // Handle modules in auto mode // =============================== xAllModulesInAutoMode := _fbModule1.xAllUnitsInAutomatic AND _fbModule2.xAllUnitsInAutomatic AND _fbModule3.xAllUnitsInAutomatic; // =============================== // Handle shutdown discharge mode // =============================== _xAllModulesInShutdownDischargeMode := _fbModule1.xInShutdownDischargeMode AND _fbModule2.xInShutdownDischargeMode AND _fbModule3.xInShutdownDischargeMode; // =============================== // Modules ready check // =============================== _xAllModulesReady := _fbModule1.xReady AND _fbModule2.xReady AND _fbModule3.xReady; // =============================== // Balancing done check // =============================== _xBalancingDone := _fbModule1.xBalancingDone AND _fbModule2.xBalancingDone AND _fbModule3.xBalancingDone; // =============================== // Modules in shutdown discharge mode // =============================== xInShutdownDischargeMode := _fbModule1.xInShutdownDischargeMode OR _fbModule2.xInShutdownDischargeMode OR _fbModule3.xInShutdownDischargeMode; // =============================== // Units shutdown discharge allowed // =============================== xShutdownDischargeAllowed := _fbModule1.xShutdownDischargeAllowed AND _fbModule2.xShutdownDischargeAllowed AND _fbModule3.xShutdownDischargeAllowed; // =============================== // All modules off // =============================== xOff := _fbModule1.xOff AND _fbModule2.xOff AND _fbModule3.xOff; // =============================== // Call inverter // =============================== _fbInverter( sInverterIPAddr:= sInverterIP, xEnable:= _xEnableInverter AND xEmergencyStopOk, xReleasePower := xReleaseInverterPower, rPower:= _rPowerInverterInternal, xReset:= xConfirmAlarms, rMaxBattPower:= DINT_TO_REAL(GVL_CONFIG.diMaxStringDischargePower), stCurrentValues => stInverterData, stInverterInfos => stInverterInfos); refuStringErrorsModbus.stBitmap.bInverterError := _fbInverter.xError; IF (_iState >= 30) AND (_iState < 40) THEN rCapacityAH := rCapacityAH + ((stInverterData.rActDCCurrent * 0.01) / 3600); rCapacityWH := rCapacityWH + ((stInverterData.rActACPower * 0.01) / 3600); END_IF // =============================== // String ready validation check // =============================== _tonErrorDCCBNotClosed(); _tonSafetyOkTimeout(); // =============================== // Get smalles segment voltage // of all units // =============================== rSmallestSegmentVoltage := MIN(_fbModule1.rSmallestSegmentVoltage, _fbModule2.rSmallestSegmentVoltage, _fbModule3.rSmallestSegmentVoltage); rHighestSegmentVoltage := MAX(_fbModule1.rHighestSegmentVoltage, _fbModule2.rHighestSegmentVoltage, _fbModule3.rHighestSegmentVoltage); // Only recalculate SOC if all modules are ready IF _xAllModulesReady THEN _rSOC := ((100.0 * rSmallestSegmentVoltage ) / 24.0) - 229.17; END_IF HandleErrors(); CASE _iState OF 0: // Idle // Start in normal mode IF (xEnable OR xStartBalancing) AND xAllModulesInAutoMode AND xRepairSwitchOk AND (NOT _xErrorInternal) THEN _xEnable := TRUE; CASE eOperationMode OF // Automatic mode (local or remote) E_STRING_OPERATING_MODE.AUTOMATIC: _iState := 5; // Balancing mode E_STRING_OPERATING_MODE.BALANCING: _xStartBalancing := TRUE; _xReleaseLimitErrorsInternal := FALSE; _xEnable := FALSE; _iState := 7; // Safety check mode E_STRING_OPERATING_MODE.SAFETY_CHECK: _iState := 1; // Precharge mode E_STRING_OPERATING_MODE.PRECHARGE: _iState := 1; END_CASE END_IF IF _xErrorInternal THEN _iState := 1000; END_IF 1: // Wait for ready in safety check mode IF _xAllModulesReady THEN _xReleaseLimitErrorsInternal := TRUE; _iState := 10; END_IF IF (NOT xEnable) THEN _xEnable := FALSE; _iState := 0; END_IF IF _xErrorInternal THEN _iState := 1000; END_IF 5: // Wait for all modules to be ready in normal mode IF _xAllModulesReady AND _xBalanceOk THEN _xReleaseLimitErrorsInternal := TRUE; _iState := 10; END_IF IF (NOT xEnable) THEN _xEnable := FALSE; _xReleaseLimitErrorsInternal := FALSE; _iState := 0; END_IF IF _xErrorInternal THEN _iState := 1000; END_IF 7: // Wait for all modules to be ready in balancing mode IF _xAllModulesReady THEN _iState := 50; END_IF IF (NOT xStartBalancing) THEN _xStartBalancing := FALSE; //eStatus := E_COMPONENT_STATUS.OFF; _iState := 0; END_IF IF _xErrorInternal THEN _iState := 1000; END_IF 10: // Reset safety from sensors xResetSafety := FALSE; _tonSafetyOkTimeout.IN := TRUE; _iState := 15; 15: // Wait for Safety to be ok xResetSafety := _fbSafetyResetImpulseGen.xOut; IF xSafetyIntlksOk THEN xResetSafety := FALSE; _tonSafetyOkTimeout.IN := FALSE; xCloseDCCB := TRUE; _tonErrorDCCBNotClosed.IN := TRUE; _iState := 20; END_IF IF (NOT xEnable) THEN _tonSafetyOkTimeout.IN := FALSE; xResetSafety := FALSE; _xEnable := FALSE; _xReleaseLimitErrorsInternal := FALSE; _iState := 40; END_IF IF _tonSafetyOkTimeout.Q THEN _tonSafetyOkTimeout.IN := FALSE; xResetSafety := FALSE; xCloseDCCB := TRUE; xError := TRUE; xReady := FALSE; IF (NOT _fbSafetyIntlkTimeoutAlarm.bRaised) THEN _fbSafetyIntlkTimeoutAlarm.Raise(0); END_IF _iState := 1000; END_IF IF _xErrorInternal THEN _iState := 1000; END_IF 20: // Check if DC relais closed and safety is ok IF (NOT xDCCBOpen) THEN _xReleaseSafetyIntlkErrors := TRUE; _tonErrorDCCBNotClosed.IN := FALSE; CASE eOperationMode OF E_STRING_OPERATING_MODE.AUTOMATIC: _rPowerInverterInternal := rPowerInverter; _xEnableInverter := TRUE; _iState := 21; E_STRING_OPERATING_MODE.SAFETY_CHECK: _rPowerInverterInternal := 0.0; _xEnableInverter := TRUE; _iState := 21; E_STRING_OPERATING_MODE.PRECHARGE: _rPowerInverterInternal := 0.0; _xEnableInverter := FALSE; _iState := 29; // Balancing mode should never reach this point! // Its just here for testing E_STRING_OPERATING_MODE.BALANCING: _rPowerInverterInternal := 0.0; _xEnableInverter := FALSE; _iState := 50; END_CASE END_IF IF _tonErrorDCCBNotClosed.Q THEN _xEnable := FALSE; xCloseDCCB := FALSE; _tonErrorDCCBNotClosed.IN := FALSE; xError := TRUE; xReady := FALSE; IF (NOT _fbDCMainSwitchNotClosed.bRaised) THEN _fbDCMainSwitchNotClosed.Raise(0); END_IF _iState := 1000; END_IF IF (NOT xEnable) THEN _tonSafetyOkTimeout.IN := FALSE; _xEnable := FALSE; _xReleaseLimitErrorsInternal := FALSE; //eStatus := E_COMPONENT_STATUS.SHUTDOWN; _iState := 40; END_IF IF _xErrorInternal THEN _iState := 1000; END_IF 21: // Wait some time for inverter dc bus voltage settling _fbTONDCSettlingTime(IN := TRUE); IF _fbTONDCSettlingTime.Q THEN _fbTONDCSettlingTime(IN := FALSE); _xEnableInverter := TRUE; _iState := 22; END_IF 22: // Wait for inverter to be ready _tonInverterStartupTimeout(IN := TRUE, PT := timInverterStartupTimeout); IF _fbInverter.xActive AND (NOT _fbInverter.xError) THEN CASE eOperationMode OF E_STRING_OPERATING_MODE.SAFETY_CHECK: _iState := 29; ELSE _iState := 30; END_CASE xReady := TRUE; _tonInverterStartupTimeout(IN := FALSE); END_IF IF (NOT xEnable) OR (NOT _xAllModulesReady) THEN _xEnableInverter := FALSE; _rPowerInverterInternal := 0.0; _xEnable := FALSE; _xReleaseLimitErrorsInternal := FALSE; _iState := 31; _tonInverterStartupTimeout(IN := FALSE); END_IF // Inverter error or timeout for startup IF _fbInverter.xError OR (NOT xRepairSwitchOk) OR _tonInverterStartupTimeout.Q THEN // _tonInverterStartupTimeout.Q // Shutdown beacause of inverter startup timeout IF _tonInverterStartupTimeout.Q AND (NOT _fbInverterStartupTimeoutAlarm.bRaised) THEN _fbInverterStartupTimeoutAlarm.Raise(0); END_IF _iState := 1000; _xEnableInverter := FALSE; xError := TRUE; _xErrorInverter := TRUE; _xEnable := FALSE; _tonInverterStartupTimeout(IN := FALSE); END_IF 29: // Ready in safety check mode IF (NOT xEnable) THEN _xEnable := FALSE; _xReleaseLimitErrorsInternal := FALSE; _iState := 31; END_IF IF _xErrorInternal THEN _iState := 1000; END_IF 30: // All modules ready // !!! ATTENTION !!! // BMS HAS TO SHUT DOWN THE INVERTER BEFORE DISSABLING THE STRING // OTHERWISE THE DC CIRCUIT BREAKERS WILL OPEN WHILE THE INVERTER IS STILL ACTIVE // THIS CAN DAMAGE THE INVERTER IF rPowerInverter > DINT_TO_REAL(GVL_CONFIG.diMaxStringDischargePower) THEN // Limit discharge power (> because discharging is a positive number) _rPowerInverterInternal := DINT_TO_REAL(GVL_CONFIG.diMaxStringDischargePower); ELSIF rPowerInverter < DINT_TO_REAL(GVL_CONFIG.diMaxStringChargingPower) THEN // Limit charging power (< because charging is a negative number) _rPowerInverterInternal := DINT_TO_REAL(GVL_CONFIG.diMaxStringChargingPower); ELSE // Power command within range _rPowerInverterInternal := rPowerInverter; END_IF // Shutdown IF (NOT xEnable) THEN _xEnable := FALSE; IF GVL_CONFIG.xShutdownDischargeWithInverter THEN _rPowerInverterInternal := GVL_CONFIG.rAbsShutdownDischargePower; _iState := 31; ELSE _xReleaseLimitErrorsInternal := FALSE; _rPowerInverterInternal := 0.0; _xEnableInverter := FALSE; _iState := 40; END_IF ELSIF (NOT _xAllModulesReady) OR (_fbBalanceNotOkSignal.xReleaseSignal) OR (NOT xSafetyIntlksOk) OR (NOT xRepairSwitchOk) OR (_xErrorInternal) THEN xError := TRUE; _xEnable := FALSE; _rPowerInverterInternal := 0.0; _xEnableInverter := FALSE; _iState := 1000; END_IF 31: // Wait for String to be in in shutdown discharge mode IF _xAllModulesInShutdownDischargeMode THEN _iState := 32; END_IF IF _xErrorInternal THEN _rPowerInverterInternal := 0.0; _xEnableInverter := FALSE; _iState := 40; END_IF 32: // Shutdown discharge mode IF xShutdownDischargeAllowed AND (NOT xErrorShutdown) AND GVL_CONFIG.xShutdownDischargeWithInverter AND xSafetyIntlksOk AND (stInverterData.rActDCVoltage > 620.0) THEN _rPowerInverterInternal := GVL_CONFIG.rAbsShutdownDischargePower; ELSE // Send shutdown message IF NOT xShutdownDischargeAllowed THEN _fbSDUnitThreshold.Send(0); END_IF IF (stInverterData.rActDCVoltage < 620.0) THEN _fbSDDCLevel.Send(0); END_IF _rPowerInverterInternal := 0.0; _xEnableInverter := FALSE; _iState := 40; END_IF // Restart on Enable or StartBalancing IF xEnable OR xStartBalancing THEN _rPowerInverterInternal := 0.0; //_xEnableInverter := FALSE; _iState := 0; END_IF IF _xErrorInternal THEN _iState := 1000; END_IF 40: // Wait for inverter to shut down IF (NOT _fbInverter.xActive) THEN _iState := 41; END_IF IF _xErrorInternal THEN _iState := 1000; END_IF 41: // Debug delay time for inverter shutdown _tonInverterShutdownDelay(IN := TRUE); IF _tonInverterShutdownDelay.Q THEN _tonInverterShutdownDelay(IN := FALSE); xCloseDCCB := FALSE; _xReleaseSafetyIntlkErrors := FALSE; //eStatus := E_COMPONENT_STATUS.OFF; _iState := 0; END_IF 50: // Wait for balancing of all units to be done IF _xBalancingDone THEN _xStartBalancing := FALSE; _iState := 51; END_IF IF _xErrorInternal THEN _iState := 1000; END_IF 51: // Check if start balancing has been releases to avoid a restart IF (NOT xStartBalancing) THEN //eStatus := E_COMPONENT_STATUS.OFF; _iState := 0; END_IF IF _xErrorInternal THEN _iState := 1000; END_IF 1000: // Error state _xEnable := FALSE; _xEnableInverter := FALSE; _rPowerInverterInternal := 0.0; xError := TRUE; _xReleaseLimitErrorsInternal := FALSE; _xReleaseSafetyIntlkErrors := FALSE; // Reset timer _tonErrorDCCBNotClosed(IN := FALSE); //eStatus := E_COMPONENT_STATUS.ERROR; _iState := 1005; 1005: // Wait for inverter to be off _tonInverterShutdownError(IN := TRUE); // If inverter is not shutting down, hard disconnect it IF (NOT _fbInverter.xActive) OR _tonInverterShutdownError.Q THEN _tonInverterShutdownError(IN := FALSE); xCloseDCCB := FALSE; _iState := 1010; END_IF 1010: // Error idle state // Leave error state only if modules are deactivated IF (NOT xEnable) AND (NOT _xErrorInternal) THEN xError := FALSE; _xReleaseSafetyIntlkErrors := FALSE; ClearAlarms(); //eStatus := E_COMPONENT_STATUS.OFF; _iState := 0; END_IF END_CASE // =============================== // Handle status // =============================== // String off IF xOff AND (NOT xError) THEN eStatus := E_COMPONENT_STATUS.OFF; END_IF // String starting IF _xEnable AND (NOT _xAllModulesReady) AND (NOT xError) THEN eStatus := E_COMPONENT_STATUS.STARTING; END_IF // String on IF _xAllModulesReady AND _fbInverter.xActive AND (NOT xError) THEN IF _rPowerInverterInternal < 0.0 THEN eStatus := E_COMPONENT_STATUS.CHARGING; ELSIF _rPowerInverterInternal > 0.0 THEN eStatus := E_COMPONENT_STATUS.DISCHARGING; ELSE eStatus := E_COMPONENT_STATUS.ON; END_IF END_IF // String in shutdown IF xInShutdownDischargeMode AND (NOT xError) THEN eStatus := E_COMPONENT_STATUS.SHUTDOWN; END_IF // String in error state IF xError THEN eStatus := E_COMPONENT_STATUS.ERROR; END_IF // =============================== // Calculate string voltage // =============================== rCurrentVoltage := _fbModule1.rCurrentVoltage + _fbModule2.rCurrentVoltage + _fbModule3.rCurrentVoltage; stHMIInterface.rVoltage := stHMIInterface.rVoltage* 0.95 + rCurrentVoltage * 0.05; // =============================== // Copy inverter data to SCADA interface // =============================== stHMIInterface.stInverterData := stInverterData; IF _xAllModulesReady AND _xBalanceOk AND ((_iState = 30) OR (_iState = 29)) THEN xReady := TRUE; ELSE xReady := FALSE; END_IF // Reset inverter startup timeout alarm IF _fbInverterStartupTimeoutAlarm.bRaised AND xConfirmAlarms THEN _fbInverterStartupTimeoutAlarm.Clear(0, TRUE); END_IF // Reset safetyinterlock timeout alarm IF _fbSafetyIntlkTimeoutAlarm.bRaised AND xConfirmAlarms THEN _fbSafetyIntlkTimeoutAlarm.Clear(0, TRUE); END_IF // Copy status to hmi interface stHMIInterface.eStatus := eStatus; // Reset Safety xResetSafetyDCCB := xResetSafety; xCloseDCCB := TRUE;]]> 0) AND (NOT _fbSCSConnLost.bRaised) AND xReleaseErrors THEN _fbSCSConnLost.Raise(0); END_IF IF (xECWcState = 0) AND _fbSCSConnLost.bRaised THEN _fbSCSConnLost.Clear(0, FALSE); END_IF IF _fbSCSConnLost.eConfirmationState = TcEventConfirmationState.WaitForConfirmation AND xConfirmAlarms THEN _fbSCSConnLost.Confirm(0); END_IF IF (xECWcState <> 0) THEN _xErrorInternal := TRUE; END_IF // =============================== // DC Main switch error handling // =============================== IF (NOT xRepairSwitchOk) AND (NOT _fbDCMainSwitchNotClosed.bRaised) AND xReleaseErrors THEN _fbDCMainSwitchNotClosed.Raise(0); END_IF IF xRepairSwitchOk AND _fbDCMainSwitchNotClosed.bRaised THEN _fbDCMainSwitchNotClosed.Clear(0, FALSE); END_IF IF (NOT xRepairSwitchOk) THEN _xErrorInternal := TRUE; END_IF // =============================== // ISO Error handling // =============================== // Mute iso error when inverter is enabled _xIsoErrorActive := ((NOT xIsolationOKL1) OR (NOT xIsolationOKL2)) AND (NOT _fbInverter.xActive) AND (xDCCBOpen); _fbTONIsoError(IN := _xIsoErrorActive, PT := GVL_CONFIG.timIsoErrorTimeout); IF _fbTONIsoError.Q AND (NOT _fbIsolationAlarm.bRaised) AND xReleaseErrors THEN _fbIsolationAlarm.Raise(0); END_IF IF (NOT _fbTONIsoError.Q) AND _fbIsolationAlarm.bRaised THEN _fbIsolationAlarm.Clear(0, FALSE); END_IF IF _fbIsolationAlarm.eConfirmationState = TcEventConfirmationState.WaitForConfirmation AND xConfirmAlarms THEN _fbIsolationAlarm.Confirm(0); END_IF IF _fbTONIsoError.Q THEN _xIsoError := TRUE; END_IF IF xConfirmAlarms AND (NOT _fbTONIsoError.Q) THEN _xIsoError := FALSE; END_IF IF _xIsoError THEN _xErrorInternal := TRUE; refuStringErrorsModbus.stBitmap.bIsolationError := 1; END_IF // =============================== // Handle modules error state // =============================== IF _fbModule1.xError OR _fbModule2.xError OR _fbModule3.xError THEN _xErrorInternal := TRUE; END_IF // =============================== // Handle component safety interlocks ok // =============================== xSafetyIntlksComponentsOk := _fbModule1.xSafetyIntlksOk AND _fbModule2.xSafetyIntlksOk AND _fbModule3.xSafetyIntlksOk; IF (NOT xSafetyIntlksComponentsOk) THEN _xErrorInternal := TRUE; END_IF // =============================== // Handle safety interlock alarm // =============================== IF (NOT xSafetyIntlksOk) AND (NOT _fbSafetyInterlocksNotOkAlarm.bRaised) AND xReleaseErrors AND _xReleaseSafetyIntlkErrors THEN _fbSafetyInterlocksNotOkAlarm.Raise(0); END_IF IF (xSafetyIntlksOk OR (NOT xReleaseErrors) OR (NOT _xReleaseSafetyIntlkErrors)) AND _fbSafetyInterlocksNotOkAlarm.bRaised THEN _fbSafetyInterlocksNotOkAlarm.Clear(0, TRUE); END_IF IF (NOT xSafetyIntlksOk) AND _xReleaseSafetyIntlkErrors THEN _xErrorInternal := TRUE; END_IF // =============================== // String balance check // =============================== // Reset balance ok flag _xBalanceOk := TRUE; // Test module 1 with module 2 IF ABS(_fbModule1.rCurrentVoltage - _fbModule2.rCurrentVoltage) > GVL_CONFIG.rMaxAbsDiffVoltageModulesInString THEN _xBalanceOk := FALSE; END_IF // Test module 1 with module 3 IF ABS(_fbModule1.rCurrentVoltage - _fbModule3.rCurrentVoltage) > GVL_CONFIG.rMaxAbsDiffVoltageModulesInString THEN _xBalanceOk := FALSE; END_IF // Test module 2 with module 3 IF ABS(_fbModule2.rCurrentVoltage - _fbModule3.rCurrentVoltage) > GVL_CONFIG.rMaxAbsDiffVoltageModulesInString THEN _xBalanceOk := FALSE; END_IF // Release signal for balance not ok _fbBalanceNotOkSignal( xSignal:= NOT _xBalanceOk, xRelease:= xEnable AND _xAllModulesReady, timOnDelay:= T#5S, timOffDelay:= T#5S, xReleaseSignal=> ); // Signal an error if all units are ready and module is out of balance IF _fbBalanceNotOkSignal.xReleaseSignal THEN _xErrorInternal := TRUE; END_IF // Raise error IF _fbBalanceNotOkSignal.xReleaseSignal AND (NOT _fbModulesOutOfBalanceAlarm.bRaised) AND xReleaseErrors THEN _fbModulesOutOfBalanceAlarm.Raise(0); END_IF // Clear error IF (NOT _fbBalanceNotOkSignal.xReleaseSignal) AND _fbModulesOutOfBalanceAlarm.bRaised AND xConfirmAlarms THEN _fbModulesOutOfBalanceAlarm.Clear(0, FALSE); END_IF // Confirm error IF _fbModulesOutOfBalanceAlarm.eConfirmationState = TcEventConfirmationState.WaitForConfirmation AND xConfirmAlarms THEN _fbModulesOutOfBalanceAlarm.Confirm(0); END_IF // =============================== // Handle inverter error // =============================== IF _fbInverter.xError THEN _xErrorInternal := TRUE; END_IF]]>