diff --git a/.gitignore b/.gitignore index dc57b71..9702eb7 100755 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,9 @@ app/*.cmake controller/CMakeFiles/* controller/*.cmake + +tests/CMakeFiles/* + *.*swp .cmake/** .cmake/* diff --git a/app/app b/app/app index c83352f..0a052cd 100755 Binary files a/app/app and b/app/app differ diff --git a/app/libapp_lib.a b/app/libapp_lib.a index 48a480d..e72628b 100644 Binary files a/app/libapp_lib.a and b/app/libapp_lib.a differ diff --git a/app/main.cpp b/app/main.cpp index 24ec338..6cdb4bb 100755 --- a/app/main.cpp +++ b/app/main.cpp @@ -31,7 +31,7 @@ int kbhit() { } return 0; } -#include "Controller.hpp" +#include "Controller.h" // entry point for controller app diff --git a/controller/Controller.cpp b/controller/Controller.cpp index 7dad55e..1f57f75 100755 --- a/controller/Controller.cpp +++ b/controller/Controller.cpp @@ -1,4 +1,4 @@ -#include "Controller.hpp" +#include "Controller.h" #ifdef BUILD_TARGET_SOM diff --git a/controller/Controller.h b/controller/Controller.h index e69de29..611b0fd 100755 --- a/controller/Controller.h +++ b/controller/Controller.h @@ -0,0 +1,2531 @@ +#pragma once + +#ifdef BUILD_TARGET_SOM + +#if defined(_WIN32) +#define BINDER_SIMULINK_API_EXPORT __declspec(dllexport) +#else +#define BINDER_SIMULINK_API_EXPORT __attribute__((visibility("default"))) +#endif +#include "algorithm/ControllerBase.hpp" +#include "asio/SignalConnection.hpp" + +#endif + +#include +#include +#include +#include +#include +#include +#include + +const double PI_CONST = 3.14159265358979323846; + +#define MAX std::max +#define MIN std::min + +namespace UTILITY_FUNCTIONS { + +inline double limit(double x, double lo, double hi) { + return (x < lo) ? lo : (x > hi) ? hi : x; +} + +inline double max3(double a, double b, double c) { + return std::max(a, std::max(b, c)); +} +inline double min3(double a, double b, double c) { + return std::min(a, std::min(b, c)); +} + +inline bool is_valid(double x) { return std::isfinite(x); } + +// ST: REAL_TO_INT(x) i.d.R. trunc Richtung 0. Bei Siemens oft ROUND? Du nutzt +// häufig +0.5. +inline int real_to_int(double x) { return static_cast(x); } + +// Platzhalter für GET_VALUE_* (kommt vermutlich aus Parameter-/Recipe-System) +inline std::int32_t GET_VALUE_DINT(int /*a*/, int /*b*/, int /*c*/, int /*d*/) { + // TODO: an dein Parameter-System anbinden + return 0; +} +inline double GET_VALUE_REAL(int /*a*/, int /*b*/, int /*c*/, int /*d*/) { + // TODO: an dein Parameter-System anbinden + return 0.0; +} + +} // namespace UTILITY_FUNCTIONS + +// ------------------------- +// Regelkern (ST -> C++) +// ------------------------- + +class PWM { +public: + PWM(double zyklus_min, double zyklus_max, double initial_zykluszeit = -1.0) { + Zykluszeit = 0.0; + Ausgabe = 0.0; + Zyklus_MAX = zyklus_max; + Zyklus_MIN = zyklus_min; + } + /*(* Puls Pause Generierung Kühlung *) + Zyklus_Kuehlventil := Zyklus_Kuehlventil + sampling_time; + + IF Ausgabe_Kuehlventil > 0.0 THEN + Kuehlventil := NOT Status_Untertemperatur; + Ausgabe_Kuehlventil := Ausgabe_Kuehlventil - sampling_time; + IF Ausgabe_Kuehlventil < 0.0 THEN + Zykluszeit_Kuehlventil := Zykluszeit_Kuehlventil - + Ausgabe_Kuehlventil * 100.0 / MAX(Stellgrad_Kuehlventil, sampling_time / + Zykluszeit_Kuehlventil_MAX * 100.0); Ausgabe_Kuehlventil := 0.0; END_IF; ELSE + Kuehlventil := FALSE; + END_IF; + + IF Stellgrad_Kuehlventil > sampling_time / Zykluszeit_Kuehlventil_MAX * 100.0 + THEN IF Zyklus_Kuehlventil >= Zykluszeit_Kuehlventil OR Zyklus_Kuehlventil >= + MAX(2.0 * Zykluszeit_Kuehlventil_MIN, sampling_time * 100.0 / + Stellgrad_Kuehlventil) THEN Ausgabe_Kuehlventil := MIN(Ausgabe_Kuehlventil + + Stellgrad_Kuehlventil / 100.0 * Zykluszeit_Kuehlventil_MIN, + Zykluszeit_Kuehlventil); Zykluszeit_Kuehlventil := Zykluszeit_Kuehlventil_MIN; + Zyklus_Kuehlventil := 0.0; + END_IF; + END_IF;*/ + + bool step(double Stellgrad, double samplingTime) { + Zyklus += samplingTime; + bool output_bool; + if (Ausgabe > 0.0) { + output_bool = true; + Ausgabe -= samplingTime; + if (Ausgabe < 0.0) { + Zykluszeit -= + Ausgabe * 100 / MAX(Stellgrad, samplingTime / Zyklus_MAX * 100.0); + Ausgabe = 0.0; + } + + } else { + output_bool = false; + } + if (Stellgrad > samplingTime / Zyklus_MAX * 100.0) { + if (Zyklus >= Zykluszeit || + Zyklus >= MAX(2.0 * Zyklus_MIN, samplingTime * 100.0 / Stellgrad)) { + Ausgabe = MIN(Ausgabe + Stellgrad / 100.0 * Zyklus_MIN, Zyklus); + Zykluszeit = Zyklus_MIN; + Zyklus = 0.0; + } + } + return output_bool; + } + +private: + double Zyklus = 0.0; + double Ausgabe = 0.0; + double Zykluszeit = 0.0; + double Zyklus_MAX = 0.0; + double Zyklus_MIN = 0.0; +}; + +class ClimateAlgorithm { +public: + struct BinInputs { + // Eingangswerte aus bool_inXX / real_inXX / reset_flag + bool reset_flag{}; + bool Sammelalarm_quittiert{}; + bool Tuer_offen{}; + bool Sollwert_Feuchte_aktiv{}; + bool Steuerkontakt_Standby{}; + bool Steuerkontakt_Befeuchtung_aus{}; + bool Steuerkontakt_Entfeuchtung_aus{}; + bool Entleerbehaelter_Oben{}; + bool Wasserkanister_leer{}; + bool Entleerbehaelter_Unten{}; + bool Sammelalarm{}; + } binInput; + + struct AnalogInputs { + double Istwert_Temperatur{}; + double Sollwert_Temperatur{}; + double Temperaturband{}; + double Istwert_Ueberwachungsregler{}; + double Klasse_Ueberwachungsregler{}; + double Grenzwert_Untertemperatur{}; + double Istwert_Feuchte{}; + double Sollwert_Feuchte{}; + double Feuchteband{}; + double Sollwert_Luefter{}; + double Istwert_Temperatur_Tuer{}; + double Istwert_Temperatur_Verdampferausgang{}; + double Temperatur_Feuchtemodul{}; + double Bandalarm_nach{}; + double Betauungsschutz{}; + double real_in11{}; // du nutzt real_in11 später direkt in alarm_15 + } analogInput; + + struct BinOutputs { + // bool_outXX + bool bool_out01{}; + bool bool_out02{}; + bool bool_out03{}; + bool bool_out07{}; + bool bool_out09{}; + bool bool_out11{}; + bool bool_out12{}; + bool bool_out13{}; + bool bool_out14{}; + bool bool_out16{}; + bool bool_out17{}; + bool bool_out18{}; + bool bool_out19{}; + bool bool_out20{}; + bool bool_out21{}; + bool bool_out23{}; + } binOut; + + struct AnalogOutputs { + // real_outXX (nur die, die du im ST setzt) + double real_out01{}; + double real_out02{}; + double real_out04{}; + double real_out05{}; + double real_out06{}; + double real_out07{}; + double real_out08{}; + double real_out09{}; + double real_out10{}; + double real_out11{}; + double real_out12{}; + double real_out13{}; + double real_out14{}; + double real_out16{}; + double Stellgrad_Feuchtemodul{}; // ...out17 + double real_out18{}; + double real_out19{}; + double real_out20{}; + double real_out21{}; + double real_out25{}; + double real_out26{}; + double Stellgrad_Heizung{}; + double Stellgrad_Kuehlung{}; + double Stellgrad_Befeuchtung{}; + double Stellgrad_Entfeuchtung{}; + double Counter_Tuer{}; + } analogOut; + + struct Alarm { + // alarm_01..alarm_15 + bool Startup{}; + bool alarm_01{}; + bool alarm_02{}; + bool alarm_03{}; + bool alarm_04{}; + bool alarm_05{}; + bool alarm_06{}; + bool alarm_07{}; + bool alarm_08{}; + bool alarm_09{}; + bool alarm_10{}; + bool alarm_11{}; + bool alarm_12{}; + bool alarm_13{}; + bool alarm_14{}; + bool alarm_15{}; + } alarmOut; + + ClimateAlgorithm() = default; + + void Step(void) { + using UTILITY_FUNCTIONS::is_valid; + using UTILITY_FUNCTIONS::limit; + + // --------------------------- + // Eingangswerte (ST Zuweisungen) + // --------------------------- + Sammelalarm_quittiert = binInput.Sammelalarm_quittiert; + Tuer_offen = binInput.Tuer_offen; + Sollwert_Feuchte_aktiv = true; + Steuerkontakt_Standby = false; + Steuerkontakt_Befeuchtung_aus = false; + Steuerkontakt_Entfeuchtung_aus = false; + Entleerbehaelter_Oben = binInput.Entleerbehaelter_Oben; + bool Wasserkanister_leer = false; + Entleerbehaelter_Unten = binInput.Entleerbehaelter_Unten; + Sammelalarm = false; + Istwert_Temperatur = analogInput.Istwert_Temperatur; + Istwert_Ueberwachungsregler = Istwert_Temperatur; + Sollwert_Temperatur = analogInput.Sollwert_Temperatur; + Istwert_Feuchte = analogInput.Istwert_Feuchte; + Sollwert_Feuchte = analogInput.Sollwert_Feuchte; + // uj - not needed double Sollwert_Luefter = analogInput.Sollwert_Luefter; + Istwert_Temperatur_Tuer = analogInput.Istwert_Temperatur_Tuer; + double Istwert_Temperatur_Verdampferausgang = analogInput.Istwert_Temperatur_Verdampferausgang; + Temperatur_Feuchtemodul = analogInput.Temperatur_Feuchtemodul; + double Betauungsschutz = 50.0; + double Feuchteband = 10; + double Temperaturband = 5; + bool reset_flag = binInput.reset_flag; + + // Zähler reset_flag + // ----------------- + if (reset_flag) { + Counter_reset_flag = 0; + } else { + Counter_reset_flag += 1; + } + Startup_finished = + (Counter_reset_flag > static_cast(10 * 4)); + + // ------------------------------------------ + // Verzögerte Abschaltung Regelung bei Türöffnung + // ------------------------------------------ + // f_PostDoorOpeningCutOffDelaed(...) + if (Tuer_offen || Steuerkontakt_Standby) { + Counter_Regelung_AUS += sampling_time; + } else { + Counter_Regelung_AUS = 0.0; + } + Regelung_AUS = (Counter_Regelung_AUS > 60.0); + + // ------------------- + // Nachlauf Türöffnung + // ------------------- + // f_PostDoorOpening(..) + if (!Startup_finished) { + Counter_Tuer_offen = 0.0; + Counter_Tuer_geschlossen = 600.0; + } else if (Tuer_offen) { + Counter_Tuer_offen += sampling_time; + Counter_Tuer_geschlossen = 0.0; + } else { + Counter_Tuer_offen = 0.0; + Counter_Tuer_geschlossen += sampling_time; + } + + Sollwert_Temperatur_MIN = -5.0; + Sollwert_Temperatur_MAX = 100.0; + + // ------------------------------------------ + // Sollwert Feuchte (Limit-Kennfeld) + // ------------------------------------------ + // f_HumiditySetValueByVector(...) + Index_Sollwert_Feuchte_Limit = 1; + while (Kennfeld_Sollwert_Feuchte_Limit[0][Index_Sollwert_Feuchte_Limit] < + Sollwert_Temperatur && + Index_Sollwert_Feuchte_Limit < 10) { + Index_Sollwert_Feuchte_Limit++; + } + + Interpolation_Sollwert_Feuchte_Limit = limit( + (Kennfeld_Sollwert_Feuchte_Limit[0][Index_Sollwert_Feuchte_Limit - 1] - + Sollwert_Temperatur) / + (Kennfeld_Sollwert_Feuchte_Limit[0] + [Index_Sollwert_Feuchte_Limit - 1] - + Kennfeld_Sollwert_Feuchte_Limit[0][Index_Sollwert_Feuchte_Limit]), + 0.0, 1.0); + + Sollwert_Feuchte_Max = + Kennfeld_Sollwert_Feuchte_Limit[1][Index_Sollwert_Feuchte_Limit] * + Interpolation_Sollwert_Feuchte_Limit + + Kennfeld_Sollwert_Feuchte_Limit[1][Index_Sollwert_Feuchte_Limit - 1] * + (1.0 - Interpolation_Sollwert_Feuchte_Limit); + + Sollwert_Feuchte_Min = + Kennfeld_Sollwert_Feuchte_Limit[2][Index_Sollwert_Feuchte_Limit] * + Interpolation_Sollwert_Feuchte_Limit + + Kennfeld_Sollwert_Feuchte_Limit[2][Index_Sollwert_Feuchte_Limit - 1] * + (1.0 - Interpolation_Sollwert_Feuchte_Limit); + + Sollwert_Feuchte = + limit(Sollwert_Feuchte, Sollwert_Feuchte_Min, Sollwert_Feuchte_Max); + + + + // Abschaltung Feuchteregelung + // f_CutOffHumidityControl(...) + Befeuchtung_aus = + (!Sollwert_Feuchte_aktiv) || Steuerkontakt_Befeuchtung_aus || + (Sollwert_Temperatur > 95.0) || (Sollwert_Temperatur < 5.0); + Entfeuchtung_aus = + (!Sollwert_Feuchte_aktiv) || Steuerkontakt_Entfeuchtung_aus || + (Sollwert_Temperatur > 95.0) || (Sollwert_Temperatur < 5.0); + + // (p_H2Omax, Taupunkt etc.) + p_H2Omax_Sollwert = 6.112 * std::exp(17.62 * Sollwert_Temperatur / + (243.12 + Sollwert_Temperatur)); + p_H2Omax_Istwert = 6.112 * std::exp(17.62 * Istwert_Temperatur / + (243.12 + Istwert_Temperatur)); + + Taupunkt_Istwert = + (241.2 * std::log(std::max(Istwert_Feuchte, 0.001) / 100.0) + + (4222.03716 * Istwert_Temperatur) / (241.2 + Istwert_Temperatur)) / + (17.5043 - std::log(std::max(Istwert_Feuchte, 0.001) / 100.0) - + (17.5043 * Istwert_Temperatur) / (241.2 + Istwert_Temperatur)); + + if (Temperatursprung) { + Sollwert_Feuchte_Absolut = + limit(Sollwert_Feuchte * p_H2Omax_Sollwert / p_H2Omax_Istwert, 0.0, + Sollwert_Feuchte); + } else { + Sollwert_Feuchte_Absolut = Sollwert_Feuchte; + } + if (!is_valid(Sollwert_Feuchte_Absolut)) { + Sollwert_Feuchte_Absolut = Sollwert_Feuchte; + } + + // ------------------ + // Überwachungsregler + // ------------------ + // f_SuperVisor + + /* + Modus_Ueberwachungsregler = + static_cast(UTILITY_FUNCTIONS::GET_VALUE_DINT(71,0,3,0)); + Grenzwert_Uebertemperatur = UTILITY_FUNCTIONS::GET_VALUE_REAL(71,0,4,0); + Offset_Ueberwachungsregler = UTILITY_FUNCTIONS::GET_VALUE_REAL(71,0,5,0); + + if (Modus_Ueberwachungsregler > 0) { + Schaltwert_Uebertemperatur = limit(Sollwert_Temperatur + + Offset_Ueberwachungsregler, -30.0, 110.0); Schaltwert_Untertemperatur = + limit(Sollwert_Temperatur - Offset_Ueberwachungsregler, -30.0, 110.0); } + else { Schaltwert_Uebertemperatur = Grenzwert_Uebertemperatur; + Schaltwert_Untertemperatur = Grenzwert_Untertemperatur; + } + + const double maxUeberw = std::max(Istwert_Ueberwachungsregler, + Istwert_Temperatur); const double minUeberw = + std::min(Istwert_Ueberwachungsregler, Istwert_Temperatur); + + if ( (maxUeberw > Schaltwert_Uebertemperatur) || + (Status_Uebertemperatur && (maxUeberw > Schaltwert_Uebertemperatur + - 1.0)) || (StatusQuittierung_Uebertemperatur && (Klasse_Ueberwachungsregler + < 3.0)) ) { Counter_Status_Uebertemperatur += 1; } else { + Counter_Status_Uebertemperatur = 0; + } + + Status_Uebertemperatur = (Counter_Status_Uebertemperatur >= + static_cast(10 * 4)); StatusQuittierung_Uebertemperatur = + (Status_Uebertemperatur && Counter_Status_Uebertemperatur < + static_cast(11 * 4)) || (StatusQuittierung_Uebertemperatur && + Sammelalarm_quittiert); + + if ( ((minUeberw < Schaltwert_Untertemperatur) || + (Status_Untertemperatur && (minUeberw < Schaltwert_Untertemperatur + + 1.0))) && (Klasse_Ueberwachungsregler >= 3.0) ) { + Counter_Status_Untertemperatur += 1; + } else { + Counter_Status_Untertemperatur = 0; + } + + Status_Untertemperatur = (Counter_Status_Untertemperatur >= + static_cast(10 * 4)); StatusQuittierung_Untertemperatur = + (Status_Untertemperatur && Counter_Status_Untertemperatur < + static_cast(11 * 4)) || (StatusQuittierung_Untertemperatur && + Sammelalarm_quittiert); + + if (Status_Untertemperatur || StatusQuittierung_Untertemperatur) { + Sollwert_Temperatur = std::max(Sollwert_Temperatur, + Schaltwert_Untertemperatur); + } + if (Status_Uebertemperatur || StatusQuittierung_Uebertemperatur) { + Sollwert_Temperatur = std::min(Sollwert_Temperatur, + Schaltwert_Uebertemperatur); + }*/ + + // ------------------------ + // Parametersatzumschaltung + // ------------------------ + // f_SwitchParameterSet(...) + Index_Feuchte = static_cast( + 8 - + UTILITY_FUNCTIONS::real_to_int( + limit((Sollwert_Feuchte - 10.0) / (90.0 - 10.0) * 8.0, 0.0, 8.0) + + 0.5)); + Index_Temperatur = + static_cast(UTILITY_FUNCTIONS::real_to_int( + limit((Sollwert_Temperatur - 10.0) / (90.0 - 10.0) * 8.0, 0.0, + 8.0) + + 0.5)); + Index_Temperatur_ohne_Feuchte = + static_cast(UTILITY_FUNCTIONS::real_to_int( + limit((Sollwert_Temperatur - (-20.0)) / (100.0 - (-20.0)) * 12.0, + 0.0, 12.0) + + 0.5)); + + Regler_Heizung_Xp = F_Xp_Heizung * Kennfeld_Regler_Heizung_Xp[Index_Temperatur_ohne_Feuchte]; + Regler_Kuehlung_Xp = F_Xp_Kuehlung * + Kennfeld_Regler_Kuehlung_Xp[Index_Temperatur_ohne_Feuchte]; + Regler_Befeuchtung_Xp = + F_Xp_Befeuchtung_BINDER * + Kennfeld_Regler_Befeuchtung_Xp[Index_Feuchte][Index_Temperatur]; + Regler_Entfeuchtung_Xp = + F_Xp_Entfeuchtung * + Kennfeld_Regler_Entfeuchtung_Xp[Index_Feuchte][Index_Temperatur]; + Regler_Tuer_Xp = F_Xp_Tuer; + + // --------------------- + // PID Regler Temperatur + // --------------------- + // F_PID PID_Temperature(...) + Regelabweichung_Temperatur = Sollwert_Temperatur - Istwert_Temperatur; + + // Zykluszeit Regelabweichung Temperatur + if (!Startup_finished || !is_valid(Standardregelabweichung_Temperatur) || + !is_valid(Standardgradient_Regelabweichung_Temperatur) || + Standardgradient_Regelabweichung_Temperatur <= 0.0) { + Zykluszeit_Regelabweichung_Temperatur = 600.0; + } else { + Zykluszeit_Regelabweichung_Temperatur = + limit(2.0 * 3.1415 * Standardregelabweichung_Temperatur / + Standardgradient_Regelabweichung_Temperatur * 60.0, + 120.0, 1200.0); + } + Zykluszeit_Regelabweichung_Heizung = + std::min(Zykluszeit_Regelabweichung_Temperatur, 300.0); + Zykluszeit_Regelabweichung_Kuehlung = + std::max(Zykluszeit_Regelabweichung_Temperatur, 600.0); + + Amplitude_Regelabweichung_Temperatur = + 1.4142 * Standardregelabweichung_Temperatur; + + // Mittelwert Regelabweichung Temperatur + if (!Startup_finished || !is_valid(Regelabweichung_Temperatur_Mittelwert) || + Temperatursprung) { + Regelabweichung_Temperatur_Mittelwert = 0.0; + } else if (is_valid(Regelabweichung_Temperatur)) { + const double alpha = + (Zykluszeit_Regelabweichung_Temperatur / sampling_time); + Regelabweichung_Temperatur_Mittelwert = limit( + Regelabweichung_Temperatur_Mittelwert + + (Regelabweichung_Temperatur - + Regelabweichung_Temperatur_Mittelwert) / + alpha, + Regelabweichung_Temperatur - 1.0, Regelabweichung_Temperatur + 1.0); + } + + // Standardregelabweichung Temperatur + if (!Startup_finished || !is_valid(Standardregelabweichung_Temperatur) || + Temperatursprung) { + Standardregelabweichung_Temperatur = 0.0; + } else if (is_valid(Regelabweichung_Temperatur)) { + const double n = (Zykluszeit_Regelabweichung_Temperatur / sampling_time); + Standardregelabweichung_Temperatur = std::min( + std::sqrt(((Regelabweichung_Temperatur - + Regelabweichung_Temperatur_Mittelwert) * + (Regelabweichung_Temperatur - + Regelabweichung_Temperatur_Mittelwert) + + Standardregelabweichung_Temperatur * + Standardregelabweichung_Temperatur * (n - 1.0)) / + n), + 1.0); + } + + // Gradient Regelabweichung Temperatur + // f_PID_Temperaure.GradientDifference(...) + if (!Startup_finished || !is_valid(Regelabweichung_Temperatur_Gradient)) { + Regelabweichung_Temperatur_Gradient = 0.0; + } else if (is_valid(Regelabweichung_Temperatur) && + is_valid(Regelabweichung_Temperatur_alt)) { + Regelabweichung_Temperatur_Gradient = limit( + Regelabweichung_Temperatur_Gradient + + ((Regelabweichung_Temperatur - Regelabweichung_Temperatur_alt) * + (60.0 / sampling_time) - + Regelabweichung_Temperatur_Gradient) / + (10.0 / sampling_time), + -4.0, 2.0); + } + + // Standardgradient Temperatur + // f_PID_Temperaure.StandardGradient(...) + if (!Startup_finished || + !is_valid(Standardgradient_Regelabweichung_Temperatur) || + Temperatursprung) { + Standardgradient_Regelabweichung_Temperatur = 0.0; + } else if (is_valid(Regelabweichung_Temperatur)) { + const double n = (Zykluszeit_Regelabweichung_Temperatur / sampling_time); + Standardgradient_Regelabweichung_Temperatur = + limit(std::sqrt((Regelabweichung_Temperatur_Gradient * + Regelabweichung_Temperatur_Gradient + + Standardgradient_Regelabweichung_Temperatur * + Standardgradient_Regelabweichung_Temperatur * + (n - 1.0)) / + n), + 0.01, 1.0); + } + + // Temperatursprung + // f_TemperatureJumpHandler(...) + if (!Startup_finished) { + Counter_Temperatursprung = 0.0; + } else if (((Sollwert_Temperatur != Sollwert_Temperatur_alt) && + (std::abs(Regelabweichung_Temperatur) > 1.0)) || + Tuer_offen) { + Counter_Temperatursprung = + std::max(Counter_Temperatursprung + sampling_time, 0.0); + } else if (Regelabweichung_Temperatur < + std::max(0.2, Amplitude_Regelabweichung_Temperatur) && + Regelabweichung_Temperatur > + -std::max(0.2, Amplitude_Regelabweichung_Temperatur)) { + Counter_Temperatursprung = + std::min(Counter_Temperatursprung - sampling_time, 0.0); + } else if (Regelabweichung_Temperatur > + std::max(0.5, 2.0 * Amplitude_Regelabweichung_Temperatur) || + Regelabweichung_Temperatur < + -std::max(0.5, 2.0 * Amplitude_Regelabweichung_Temperatur)) { + Counter_Temperatursprung = + std::max(Counter_Temperatursprung + sampling_time, -120.0); + } + Temperatursprung = (Counter_Temperatursprung > 0.0) || + (Temperatursprung && Counter_Temperatursprung > -60.0); + + // Anti-wind-up Heizung (dynamisches Clamping) + // ------ F_PID_Temperatuer.AntiWindUpHeater(...) + if ((Counter_Tuer_geschlossen < 180.0) || (Counter_Tuer_offen > 0.0)) { + Regler_Heizung_MIN = 0.0; + Regler_Heizung_I_Anteil_MIN = 0.0; + Regler_Heizung_MAX = 100.0; + Regler_Heizung_I_Anteil_MAX = + limit(100.0 - P_Anteil_Heizung, Regler_Heizung_I_Anteil_MIN, + Stellgrad_Heizung_Mittelwert); + } else { + Regler_Heizung_MIN = 0.0; + Regler_Heizung_I_Anteil_MIN = 0.0; + Regler_Heizung_MAX = 100.0; + if (Temperatursprung) { + Regler_Heizung_I_Anteil_MAX = + limit(100.0 - P_Anteil_Heizung, Regler_Heizung_I_Anteil_MIN, + Regler_Heizung_MAX); + } else { + Regler_Heizung_I_Anteil_MAX = 100.0; + } + } + //---------------------- + + // Anpassung Xp Heizung + // // ------------F_PID_Temperatuer.AdaptXp(...) + if (Regelabweichung_Temperatur > Amplitude_Regelabweichung_Temperatur && + Regelabweichung_Temperatur_Mittelwert > 0.05 && !Temperatursprung) { + Regler_Heizung_Xp /= 2.0; + } + // Achtung: du referenzierst hier Zykluszeit_Regelabweichung_Feuchte später + // – steht unten. Wir setzen default, falls noch uninitialisiert: + if (!is_valid(Zykluszeit_Regelabweichung_Feuchte) || + Zykluszeit_Regelabweichung_Feuchte <= 0.0) { + Zykluszeit_Regelabweichung_Feuchte = 600.0; + } + + Regler_Heizung_Xp = + Regler_Heizung_Xp * + limit(Zykluszeit_Regelabweichung_Feuchte / 300.0, 1.0, 2.0) * + limit(1.0 + Amplitude_Regelabweichung_Temperatur / 0.5 + + Stellgrad_Kuehlung_Mittelwert / -100.0, + 1.0, 2.0); + //-----------// ------------F_PID_Temperatuer.AdaptXp(...)--------------------------------------------------- + + // P/I/D Heizung + //----------------- F_PID_Temperature.step(...) + if (!Startup_finished || !is_valid(Regelabweichung_Temperatur)) { + P_Anteil_Heizung = 0.0; + } else { + P_Anteil_Heizung = 100.0 / Regler_Heizung_Xp * Regelabweichung_Temperatur; + } + + if (!Startup_finished || !is_valid(I_Anteil_Heizung)) { + I_Anteil_Heizung = 0.0; + } else if (!Regelung_AUS && is_valid(Regelabweichung_Temperatur) && + Counter_Tuer_geschlossen > 60.0) { + I_Anteil_Heizung = limit( + I_Anteil_Heizung + 100.0 / Regler_Heizung_Xp / + (1.0 * Zykluszeit_Regelabweichung_Heizung) * + sampling_time * Regelabweichung_Temperatur, + Regler_Heizung_I_Anteil_MIN, Regler_Heizung_I_Anteil_MAX); + } + + if (!Startup_finished || !is_valid(D_Anteil_Heizung)) { + D_Anteil_Heizung = 0.0; + } else if (is_valid(Regelabweichung_Temperatur) && + is_valid(Regelabweichung_Temperatur_alt) && + Counter_Tuer_geschlossen > 0.0) { + D_Anteil_Heizung = + D_Anteil_Heizung + + (100.0 / Regler_Heizung_Xp * + (0.1 * Zykluszeit_Regelabweichung_Heizung) * + (Regelabweichung_Temperatur - Regelabweichung_Temperatur_alt) / + sampling_time - + D_Anteil_Heizung) / + (Tau_Heizung_Tv / sampling_time); + } + + if (Counter_Tuer_offen > 60.0 || Regelung_AUS || !Startup_finished) { + Stellgrad_Heizung = 0.0; + } else { + Stellgrad_Heizung = + limit(P_Anteil_Heizung + I_Anteil_Heizung + D_Anteil_Heizung, + Regler_Heizung_MIN, Regler_Heizung_MAX); + } + + if (!Startup_finished || !is_valid(Stellgrad_Heizung_Mittelwert)) { + Stellgrad_Heizung_Mittelwert = 0.0; + } else if (Temperatursprung) { + Stellgrad_Heizung_Mittelwert = Stellgrad_Heizung; + } else if (is_valid(Stellgrad_Heizung)) { + Stellgrad_Heizung_Mittelwert = + Stellgrad_Heizung_Mittelwert + + (Stellgrad_Heizung - Stellgrad_Heizung_Mittelwert) / + (Zykluszeit_Regelabweichung_Temperatur / sampling_time); + } + + + // ------------ F_PID_Temperature.step(...) !!!!! todo uj umbenennen in Heizung !!!!!!!!!!!!!!!!!!! + + + // ---------------------------------------------------- + // Ab hier: Kühlung + Feuchte-PIDs + Tür-PID + Aktorlogik + // ---------------------------------------------------- + // => in gleicher Art übersetzen (Muster ist identisch). + // + // Für dieses Snippet: wir übernehmen für die Outputs zumindest die Werte, + // die schon berechnet sind, und lassen Stellgrade der restlichen Aktoren, + // falls nicht berechnet, auf gültigen Default stehen. + + // Regelabweichung Kühlung + // F_ PID PID_Cooling() + double Regelabweichung_Kuehlung = Regelabweichung_Temperatur; + + // Gradient Regelabweichgun Kuehlung + + if (!Startup_finished) { + Regelabweichung_Kuehlung_Gradient = 0.0; + + } else { + Regelabweichung_Kuehlung_Gradient = + limit((Regelabweichung_Kuehlung - Regelabweichung_Kuehlung_alt) * + 60.0 / sampling_time - + Regelabweichung_Kuehlung_Gradient, + -4.0, 2.0); + } + + // Faktor Kuehlung + + if (!Startup_finished || Temperatursprung) { + Faktor_Kuehlung = 5.0; + } else if (Regelabweichung_Kuehlung < -0.1) { + Faktor_Kuehlung = std::min(Faktor_Kuehlung + sampling_time, 5.0); + } else { + Faktor_Kuehlung = std::max(Faktor_Kuehlung - sampling_time / 60.0, 0.2); + } + + // --------------------------- Gegenheizen Band !!! Überwacher !!!!! + double Regelabweichung_Entfeuchtung = Regelabweichung_Feuchte; + if (!Startup_finished || Temperatursprung || + (Counter_Temperatursprung > -600.0 && + Faktor_Gegenheizen_Band == 10.0)) { + Faktor_Gegenheizen_Band = 10.0; + + } else if (Stellgrad_Heizung_Mittelwert - Sollwert_Gegenheizen < -1.0) { + if (Regelabweichung_Entfeuchtung > 0.5) { + Faktor_Gegenheizen_Band = + std::max(Faktor_Gegenheizen_Band - sampling_time / 10.0, 0.0); + } else { + Faktor_Gegenheizen_Band = + std::min(Faktor_Gegenheizen_Band + sampling_time / 60.0, 10.0); + } + + } else if (Stellgrad_Heizung_Mittelwert - Sollwert_Gegenheizen > 1.0 && + Stellgrad_Kuehlung_Mittelwert < -5.0) { + if (Regelabweichung_Entfeuchtung < -0.5) { + Faktor_Gegenheizen_Band = + std::max(Faktor_Gegenheizen_Band - sampling_time / 10.0, 0.0); + } else { + Faktor_Gegenheizen_Band = + std::min(Faktor_Gegenheizen_Band + sampling_time / 600.0, 5.0); + } + } + else { + Faktor_Gegenheizen_Band = + std::max(Faktor_Gegenheizen_Band - sampling_time / 60.0, 0.1); + } + // --------------------------- Gegenheizen Band + + // -----------------------Sollwert Gegenheizen für I-Anteilverschiebung + + double Faktor_Entfeuchtung_Kuehlung = 0.0; + double Offset_Kuehlung = Faktor_Entfeuchtung_Kuehlung; + Offset_Kuehlung = + Faktor_Entfeuchtung_Kuehlung * Stellgrad_Entfeuchtung_Mittelwert * + std::max((50.0 - Stellgrad_Heizung_Mittelwert) / (50 - 0.0), 0.0) * + (8.0 - Stellgrad_Befeuchtung_Standby) / (8.0 - 2.0); + //------------------------------------------------------------ + + + // P-Anteil Kühlung + // f_PID_Cooling.SetP + double P_Anteil_Kuehlung = 0.0; + if (!Startup_finished) { + P_Anteil_Kuehlung = 0.0; + } else { + P_Anteil_Kuehlung = 100.0 / Regler_Kuehlung_Xp * Faktor_Kuehlung * + Regelabweichung_Kuehlung; + } + + // Begrenzung I-Anteil Kühlung bei Türöffnung + // f_PID_Cooling.Limit_I_PostDoorOpening(...) + double Regler_Kuehlung_MAX = 0; + double Regler_Kuehlung_MIN = 0; + double Regler_Kuehlung_I_Anteil_MAX = 0; + double Regler_Kuehlung_I_Anteil_MIN = 0; + + if ((Counter_Tuer_geschlossen < 180.0) || (Counter_Tuer_offen > 0.0)) { + Regler_Kuehlung_MAX = I_Anteil_Kuehlung; + Regler_Kuehlung_MIN = -100.0; + Regler_Kuehlung_I_Anteil_MAX = I_Anteil_Kuehlung; + Regler_Kuehlung_I_Anteil_MIN = limit( -100.0 - P_Anteil_Kuehlung, Regler_Kuehlung_MIN, Regler_Kuehlung_MAX); + } else { + Regler_Kuehlung_MAX = 0.0; + Regler_Kuehlung_MIN = -100.0; + Regler_Kuehlung_I_Anteil_MAX = 0.1 / Regler_Kuehlung_Xp * 100.0; + Regler_Kuehlung_I_Anteil_MIN = limit( -100.0 - P_Anteil_Kuehlung + Regelabweichung_Kuehlung_Gradient / 0.5 * 100.0, + Regler_Kuehlung_MIN, + Regler_Kuehlung_MAX); + } + + // f_PID_Cooling.Step(...) + // I Anteil Kühlung + if (!Startup_finished) { + I_Anteil_Kuehlung = 0.0; + } else if (Counter_Tuer_geschlossen > 60.0) { + I_Anteil_Kuehlung = + limit(I_Anteil_Kuehlung + + 100.0 / Regler_Kuehlung_Tn * sampling_time * + (Regelabweichung_Kuehlung + + (Stellgrad_Heizung - Sollwert_Gegenheizen) / 100.0 * + Regler_Heizung_Xp * Theta_I_Kuehlung * + Faktor_Gegenheizen_Band), + Regler_Kuehlung_I_Anteil_MIN, Regler_Kuehlung_I_Anteil_MAX); + } + + // D-Anteil Kühlung + + if (!Startup_finished) { + D_Anteil_Kuehlung = 0.0; + } else if (Counter_Tuer_geschlossen > 0.0) { + D_Anteil_Kuehlung += + (100.0 / Regler_Kuehlung_Xp * Regler_Kuehlung_Tv * + (Regelabweichung_Kuehlung - Regelabweichung_Kuehlung_alt) / + sampling_time - + D_Anteil_Kuehlung) / + (Tau_Kuehlung_Tv / sampling_time); + } + + // Berechnung Stellgrad Kühlung + // f_ + if (Counter_Tuer_offen > 60.0 || !Startup_finished) { + Stellgrad_Kuehlung = 0.0; + } else { + Stellgrad_Kuehlung = limit(P_Anteil_Kuehlung + I_Anteil_Kuehlung + + D_Anteil_Kuehlung + Offset_Kuehlung, + Regler_Kuehlung_MIN, Regler_Kuehlung_MAX); + } + + // Berechnung Stellgrad Mittelwert + + if (!Startup_finished) { + Stellgrad_Kuehlung_Mittelwert = 0.0; + } else { + Stellgrad_Kuehlung_Mittelwert = + limit(Stellgrad_Kuehlung_Mittelwert + + (Stellgrad_Kuehlung - Stellgrad_Kuehlung_Mittelwert) / + (600.0 / sampling_time), + Stellgrad_Kuehlung - 0.5 * 100.0 * Regler_Kuehlung_Xp, + Stellgrad_Kuehlung + 0.5 * 100.0 / Regler_Kuehlung_Xp); + } + // ------------------- F_ PID PID_Cooling() + + + // PID Regler Feuchte + // f_PID_Humidiy + Regelabweichung_Feuchte = Sollwert_Feuchte_Absolut - Istwert_Feuchte; + + // Berechnung Regelabweichung Feuchte Mittelwert + if (!Startup_finished) { + Regelabweichung_Feuchte_Mittelwert = 0.0; + } else { + Regelabweichung_Feuchte_Mittelwert = limit( + Regelabweichung_Feuchte_Mittelwert + + (Regelabweichung_Feuchte - Regelabweichung_Feuchte_Mittelwert) / + (60.0 / sampling_time), + Regelabweichung_Feuchte - 10.0, Regelabweichung_Feuchte + 10.0); + } + + // Feuchtesprung + // f_PID_Hunidity.HandleJump(...) + if (!Startup_finished) { + Counter_Feuchtesprung = 0.0; + } else if (Sollwert_Feuchte != Sollwert_Feuchte_alt && + std::abs(Regelabweichung_Feuchte) > 2.0) { + Counter_Feuchtesprung = + std::max(Counter_Feuchtesprung + sampling_time, 0.0); + } else if (std::abs(Regelabweichung_Feuchte) < 2.0 || + std::abs(Regelabweichung_Feuchte_Mittelwert) < 2.0) { + Counter_Feuchtesprung = + std::min(Counter_Feuchtesprung - sampling_time, 0.0); + } else if (std::abs(Regelabweichung_Feuchte_Mittelwert) > 5.0) { + Counter_Feuchtesprung = + std::max(Counter_Feuchtesprung + sampling_time, -120.0); + } + + Feuchtesprung = (Counter_Feuchtesprung > 0.0 || + (Feuchtesprung && Counter_Feuchtesprung > -120.0)); + + // Regelabweichung Befeuchtung + + double Regelabweichung_Befeuchtung = Regelabweichung_Feuchte; + + // Gradient regelabweichung Feuchte + + if (!Startup_finished) { + Regelabweichung_Befeuchtung_Gradient = 0.0; + } else { + Regelabweichung_Befeuchtung_Gradient = limit( + Regelabweichung_Befeuchtung_Gradient + + ((Regelabweichung_Befeuchtung - Regelabweichung_Befeuchtung_alt) * + 60.0 / sampling_time - + Regelabweichung_Befeuchtung_Gradient) / + 60.0 * sampling_time, + -20.0, 5.0); + } + + // Begrenzung I-Anteil bei Türöffnung + double Regler_Befeuchtung_MIN = 0.0; + double Regler_Befeuchtung_MAX = 0.0; + double Regler_Befeuchtung_I_Anteil_MIN = 0.0; + double Regler_Befeuchtung_I_Anteil_MAX = 0.0; + + if ((Counter_Tuer_geschlossen < 180.0) || (Counter_Tuer_offen > 0.0)) { + Regler_Befeuchtung_MIN = + std::max(Stellgrad_Befeuchtung_Standby - 2.0, Standby_Feuchtemodul); + Regler_Befeuchtung_MAX = std::min(100.0, Stellgrad_Feuchtemodul_MAX); + Regler_Befeuchtung_I_Anteil_MIN = 0.0; + Regler_Befeuchtung_I_Anteil_MAX = + limit(100.0 - P_Anteil_Befeuchtung, Regler_Befeuchtung_I_Anteil_MIN, + Stellgrad_Befeuchtung_Mittelwert); + } else { + if (Feuchtesprung) { + Regler_Befeuchtung_MIN = + std::max(Stellgrad_Befeuchtung_Standby - 2.0, Standby_Feuchtemodul); + } else { + Regler_Befeuchtung_MIN = + std::max(std::min(Stellgrad_Befeuchtung_Standby + + 0.25 * P_Anteil_Befeuchtung + + D_Anteil_Befeuchtung + Z_Anteil_Befeuchtung, + Stellgrad_Befeuchtung_Standby + 2.0), + std::max(Stellgrad_Befeuchtung_Standby - 1.0, + Standby_Feuchtemodul)); + } + Regler_Befeuchtung_MAX = std::min(100.0, Stellgrad_Feuchtemodul_MAX); + Regler_Befeuchtung_I_Anteil_MIN = 0.0; + Regler_Befeuchtung_I_Anteil_MAX = + limit(100.0, Regler_Befeuchtung_I_Anteil_MIN, + Stellgrad_Befeuchtung_Mittelwert); + } + + // Anteil P-Anteil Befeuchtung bei Feuchtesprung und Türöffnung + + if (Counter_Tuer_geschlossen < 180.0 && Feuchtesprung) { + Regler_Befeuchtung_Xp = Regler_Befeuchtung_Xp * 2.0; + } else if (Counter_Tuer_geschlossen > 300.0 && Feuchtesprung) { + Regler_Befeuchtung_Xp = Regler_Befeuchtung_Xp / 2.0; + } else { + Regler_Befeuchtung_Xp = + Regler_Befeuchtung_Xp * + (1.0 + Stellgrad_Entfeuchtung_Mittelwert / -100.0); + } + + // P-Anteil Befeuchtung + + if (!Startup_finished) { + P_Anteil_Befeuchtung = 0.0; + } + + else { + P_Anteil_Befeuchtung = + 100.0 / Regler_Befeuchtung_Xp * Regelabweichung_Befeuchtung; + } + + // I-Anteil Befeuchtung + + if (!Startup_finished) { + I_Anteil_Befeuchtung = 0.0; + } else if (Counter_Tuer_geschlossen > 60.0) { + I_Anteil_Befeuchtung = limit( + I_Anteil_Befeuchtung + 100.0 / Regler_Befeuchtung_Xp / + Regler_Befeuchtung_Tn * sampling_time * + Regelabweichung_Befeuchtung, + Regler_Befeuchtung_I_Anteil_MIN, Regler_Befeuchtung_I_Anteil_MAX); + } + + // D-Anteil Befeuchtung + if (!Startup_finished) { + D_Anteil_Befeuchtung = 0.0; + } else if (Counter_Tuer_geschlossen) { + D_Anteil_Befeuchtung += + (100.0 / Regler_Befeuchtung_Xp * Regler_Befeuchtung_Tv * + (Regelabweichung_Befeuchtung - Regelabweichung_Befeuchtung_alt) / + sampling_time - + D_Anteil_Befeuchtung) / + (Tau_Befeuchtung_Tv / sampling_time); + } + + // Z-Anteil Befeuchtung + + if (!Startup_finished || Feuchtesprung) { + Z_Anteil_Befeuchtung = 0.0; + } else if (Counter_Tuer_geschlossen > 0.0) { + Z_Anteil_Befeuchtung += + (100.0 / Regler_Befeuchtung_Xp * Regler_Befeuchtung_Tz * + ((Regelabweichung_Befeuchtung - + Regelabweichung_Befeuchtung_alt) - + (Regelabweichung_Befeuchtung_alt - + Regelabweichung_Befeuchtung_alt_alt)) / + sampling_time - + Z_Anteil_Befeuchtung) / + (Tau_Befeuchtung_Tz / sampling_time); + } + // Regler_Befeuchtung_MAX = 10.0; + // Berechnung Stellgrad Befeuchtung + if (Counter_Tuer_offen > 60.0 || !Startup_finished) { + Stellgrad_Befeuchtung = 0.0; + } else { + Stellgrad_Befeuchtung = + limit(P_Anteil_Befeuchtung + I_Anteil_Befeuchtung + + D_Anteil_Befeuchtung + Z_Anteil_Befeuchtung, + Regler_Befeuchtung_MIN, Regler_Befeuchtung_MAX); + } + + // Berechnung Stellgrad befeuchtung Mittelwert + + if (!Startup_finished) { + Stellgrad_Befeuchtung_Mittelwert = 0.0; + } else { + Stellgrad_Befeuchtung_Mittelwert = + limit(Stellgrad_Befeuchtung_Mittelwert + + (Stellgrad_Befeuchtung - Stellgrad_Befeuchtung_Mittelwert) / + (600.0 / sampling_time), + Stellgrad_Befeuchtung - 5.0 * 100.0 / Regler_Befeuchtung_Xp, + Stellgrad_Befeuchtung + 5.0 * 100.0 / Regler_Befeuchtung_Xp); + } + + if (!Startup_finished) { + Stellgrad_Befeuchtung_Standby = 4.0; + } else if (!(Feuchtesprung && Counter_Feuchtesprung < 300.0)) { + Stellgrad_Befeuchtung_Standby = + limit(Stellgrad_Befeuchtung_Standby + + (Stellgrad_Befeuchtung - Stellgrad_Befeuchtung_Standby) / + (600.0 / sampling_time), + 2.0, 8.0); + } + + // Regelabweichung Entfeuchtung + + Regelabweichung_Entfeuchtung = Regelabweichung_Feuchte; + + // Gradient Regelabweichung Entfeuchtung + + if (!Startup_finished) { + Regelabweichung_Entfeuchtung_Gradient = 0.0; + } + + else { + Regelabweichung_Entfeuchtung_Gradient = + limit(Regelabweichung_Entfeuchtung_Gradient + + ((Regelabweichung_Entfeuchtung - + Regelabweichung_Entfeuchtung_alt) * + 60.0 / sampling_time - + Regelabweichung_Entfeuchtung_Gradient) / + 60.0 * sampling_time, + -20.0, 5.0); + } + + // Faktor Entfeuchtung + + if (!Startup_finished) { + Faktor_Entfeuchtung = 5.0; + } else if (Regelabweichung_Entfeuchtung < -0.5) { + Faktor_Entfeuchtung = + std::min(Faktor_Entfeuchtung + sampling_time / 60.0, 5.0); + } else { + Faktor_Entfeuchtung = std::max(Faktor_Entfeuchtung - sampling_time, 0.2); + } + + // Gegenbefeuchten Band + + if (!Startup_finished || Feuchtesprung || + (Counter_Feuchtesprung > -600.0 && + Faktor_Gegenbefeuchten_Band == 5.0)) { + Faktor_Gegenbefeuchten_Band = 5.0; + } else if (Stellgrad_Befeuchtung_Mittelwert - Sollwert_Gegenbefeuchten < + -1.0) { + if (Regelabweichung_Kuehlung > 0.05) { + Faktor_Gegenbefeuchten_Band = + std::max(Faktor_Gegenbefeuchten_Band - sampling_time / 10.0, 0.0); + } else { + Faktor_Gegenbefeuchten_Band = + std::min(Faktor_Gegenbefeuchten_Band + sampling_time / 60.0, 5.0); + } + + } else if (Stellgrad_Befeuchtung_Mittelwert - Sollwert_Gegenbefeuchten > + 1.0 && + Stellgrad_Entfeuchtung_Mittelwert < -10.0) { + if (Regelabweichung_Kuehlung < -0.05) { + Faktor_Gegenbefeuchten_Band = + std::max(Faktor_Gegenbefeuchten_Band - sampling_time / 10.0, 0.0); + } else { + Faktor_Gegenbefeuchten_Band = + std::min(Faktor_Gegenbefeuchten_Band + sampling_time / 600.0, 2.0); + } + } else { + Faktor_Gegenbefeuchten_Band = + std::max(Faktor_Gegenbefeuchten_Band - sampling_time / 60.0, 0.2); + } + + // Sollwert Gegenbefeuchten für I-Anteilverschiebung + + Sollwert_Gegenbefeuchten = + 6.0 - 4.0 * (-Stellgrad_Entfeuchtung_Mittelwert / 100.0); + double Offset_Entfeuchtung = 0.0 * Stellgrad_Kuehlung_Mittelwert; + + //(* P-Anteil Entfeuchtung *) + + double P_Anteil_Entfeuchtung = 0.0; + if (!Startup_finished) { + P_Anteil_Entfeuchtung = 0.0; + } else { + P_Anteil_Entfeuchtung = 100.0 / Regler_Entfeuchtung_Xp * + Faktor_Entfeuchtung * + Regelabweichung_Entfeuchtung; + } + // I-Anteil Entfeuchtung + if (!Startup_finished) { + I_Anteil_Entfeuchtung = 0.0; + } else if (Counter_Tuer_geschlossen > 60.0) { + I_Anteil_Entfeuchtung = limit( + I_Anteil_Entfeuchtung + + 100.0 / Regler_Entfeuchtung_Xp / Regler_Entfeuchtung_Tn * + sampling_time * + (Regelabweichung_Entfeuchtung + + (Stellgrad_Befeuchtung - Sollwert_Gegenbefeuchten) / 100.0 * + Regler_Befeuchtung_Xp * Theta_I_Entfeuchtung * + Faktor_Gegenbefeuchten_Band), + Regler_Entfeuchtung_I_Anteil_MIN, Regler_Entfeuchtung_I_Anteil_MAX); + } + // D-Anteil Entfeuchtung + if (!Startup_finished) { + D_Anteil_Entfeuchtung = 0.0; + } else if (Counter_Tuer_geschlossen > 0.0) { + D_Anteil_Entfeuchtung = + D_Anteil_Entfeuchtung + + (100.0 / Regler_Entfeuchtung_Xp * Regler_Entfeuchtung_Tv * + (Regelabweichung_Entfeuchtung - + Regelabweichung_Entfeuchtung_alt) / + sampling_time - + D_Anteil_Entfeuchtung) / + (Tau_Entfeuchtung_Tv / sampling_time); + } + + // Begrenzung Stellgrad und I-Anteil + + if ((Counter_Tuer_geschlossen < 180.0) || (Counter_Tuer_offen > 0.0)) { + Regler_Entfeuchtung_MAX = I_Anteil_Entfeuchtung; + Regler_Entfeuchtung_MIN = -100.0; + Regler_Entfeuchtung_I_Anteil_MAX = I_Anteil_Entfeuchtung; + Regler_Entfeuchtung_I_Anteil_MIN = + limit(-100.0 - P_Anteil_Entfeuchtung, Regler_Entfeuchtung_MIN, + Regler_Entfeuchtung_I_Anteil_MAX); + } else { + Regler_Entfeuchtung_MAX = 0.0; + Regler_Entfeuchtung_MIN = -100.0; + Regler_Entfeuchtung_I_Anteil_MAX = 1.5 / Regler_Entfeuchtung_Xp * 100.0; + Regler_Entfeuchtung_I_Anteil_MIN = + limit(-100.0 - P_Anteil_Entfeuchtung + + Regelabweichung_Entfeuchtung_Gradient / 20.0 * 100.0, + Regler_Entfeuchtung_MIN, Regler_Entfeuchtung_I_Anteil_MAX); + } + + // Berechnung Stellgrad Entfeuchtung + + if (Counter_Tuer_offen > 60.0 || !Startup_finished) { + Stellgrad_Entfeuchtung = 0.0; + } else { + Stellgrad_Entfeuchtung = + limit(P_Anteil_Entfeuchtung + I_Anteil_Entfeuchtung + + Offset_Entfeuchtung + D_Anteil_Entfeuchtung, + Regler_Entfeuchtung_MIN, Regler_Entfeuchtung_MAX); + } + + // Berechnung Stellgrad entfeuchtung Mittelwert + + if (!Startup_finished) { + Stellgrad_Entfeuchtung_Mittelwert = 0.0; + } else { + Stellgrad_Entfeuchtung_Mittelwert = limit( + Stellgrad_Entfeuchtung_Mittelwert + + (Stellgrad_Entfeuchtung - Stellgrad_Entfeuchtung_Mittelwert) / + (600.0 / sampling_time), + Stellgrad_Entfeuchtung - 5.0 * 100.0 / Regler_Entfeuchtung_Xp, + Stellgrad_Entfeuchtung + 5.0 * 100.0 / Regler_Entfeuchtung_Xp); + } + + // PID Regler Tür + // f_PID_Door(...) + double Offset_Temperatur_Tuer; + if (Feuchtesprung) { + Offset_Temperatur_Tuer = 0.0; + } else { + Offset_Temperatur_Tuer = + 2.0 * Betauungsschutz / 100.0 * + limit((90.0 + Stellgrad_Kuehlung_Mittelwert) / (90.0 - 80.0), 0.0, + 1.0); + } + + // Regelabweichung + if (!Tuer_offen || + std::abs(Regelabweichung_Tuer) > + std::abs(Sollwert_Temperatur + Offset_Temperatur_Tuer - + Istwert_Temperatur_Tuer)) { + Regelabweichung_Tuer = Sollwert_Temperatur + Offset_Temperatur_Tuer - + Istwert_Temperatur_Tuer; + } + + // P-Anteil + + // Anti-Windup über dynamisches Integrator Clamping + + double Regler_Tuer_MAX = limit( + (100.0 + Stellgrad_Kuehlung) / (100.0 - 80.0) * 100.0, 0.0, 100.0); + double Regler_Tuer_MIN = 0.0; + double Regler_Tuer_I_Anteil_MAX = + limit(100.0 - P_Anteil_Tuer, 0.0, Regler_Tuer_MAX); + double Regler_Tuer_I_Anteil_MIN = 0.0; + + if (!Startup_finished) { + P_Anteil_Tuer = 0.0; + } else { + P_Anteil_Tuer = 100.0 / Regler_Tuer_Xp * Regelabweichung_Tuer; + } + + // I-Anteil + if (!Startup_finished) { + I_Anteil_Tuer = 0.0; + } else if (Temperatursprung && Regelabweichung_Tuer > 0.0) { + I_Anteil_Tuer = limit(I_Anteil_Tuer, Regler_Tuer_I_Anteil_MIN, + Regler_Tuer_I_Anteil_MAX); + } else if (!Tuer_offen) { + I_Anteil_Tuer = + limit(I_Anteil_Tuer + 100.0 / Regler_Tuer_Xp / Regler_Tuer_Tn * + sampling_time * Regelabweichung_Tuer, + Regler_Tuer_I_Anteil_MIN, Regler_Tuer_I_Anteil_MAX); + } + // D-Anteil + + if (!Startup_finished) { + D_Anteil_Tuer = 0.0; + } else { + D_Anteil_Tuer = D_Anteil_Tuer + + (100.0 / Regler_Tuer_Xp * Regler_Tuer_Tv * + (Regelabweichung_Tuer - Regelabweichung_Tuer_alt) / + sampling_time - + D_Anteil_Tuer) / + (Tau_Tuer_Tv / sampling_time); + } + + double Stellgrad_Tuer; + // Berechnung Stellgrad Tür + if (Tuer_offen || !Startup_finished) { + Stellgrad_Tuer = limit(P_Anteil_Tuer + I_Anteil_Tuer + D_Anteil_Tuer, + Regler_Tuer_MIN, Regler_Tuer_MAX); + } + + // Kennfelder Kühlung/Entfeuchtung + + int Index_Ueberhitzung = 1; + while (Kennfeld_Ueberhitzung[0][Index_Ueberhitzung] < Istwert_Temperatur && + Index_Ueberhitzung < 12) { + Index_Ueberhitzung++; + } + double Interpolation_Ueberhitzung = limit((Kennfeld_Ueberhitzung[0][Index_Ueberhitzung - 1] - Istwert_Temperatur) / + (Kennfeld_Ueberhitzung[0][Index_Ueberhitzung - 1] - Kennfeld_Ueberhitzung[0][Index_Ueberhitzung]), + 0.0, 1.0); + double Skalierung_Ueberhitzung_Kennfeld_Min = Kennfeld_Ueberhitzung[1][Index_Ueberhitzung] * + (Interpolation_Ueberhitzung + Kennfeld_Ueberhitzung[1][Index_Ueberhitzung - 1]) * + (1.0 - Interpolation_Ueberhitzung); + double Skalierung_Ueberhitzung_Kennfeld_Max = Kennfeld_Ueberhitzung[2][Index_Ueberhitzung] * + (Interpolation_Ueberhitzung + Kennfeld_Ueberhitzung[2][Index_Ueberhitzung - 1]) * + (1.0 - Interpolation_Ueberhitzung); + double Sollwert_Ueberhitzung = Kennfeld_Ueberhitzung[3][Index_Ueberhitzung] * + (Interpolation_Ueberhitzung + Kennfeld_Ueberhitzung[3][Index_Ueberhitzung - 1]) * + (1.0 - Interpolation_Ueberhitzung); + + //(* Entfeuchtung und Abtauung aus Kennfeld *) + int Index_Entfeuchtung = 1; // todo uj - warum nicht mit 0 starten? + while ((Kennfeld_Entfeuchtung[0][Index_Entfeuchtung] < Istwert_Temperatur) && (Index_Ueberhitzung < 12)) { + Index_Entfeuchtung++; + } + double Interpolation_Entfeuchtung = limit((Kennfeld_Entfeuchtung[0][Index_Entfeuchtung - 1] - + (Istwert_Temperatur) / (Kennfeld_Entfeuchtung[0][Index_Entfeuchtung - 1] ) - + Kennfeld_Entfeuchtung[0][Index_Entfeuchtung]), + 0.0, 1.0); + double Skalierung_Entfeuchtungsventil = Kennfeld_Entfeuchtung[1][Index_Entfeuchtung] * + Interpolation_Entfeuchtung + + Kennfeld_Entfeuchtung[1][Index_Entfeuchtung - 1] * + (1.0 - Interpolation_Entfeuchtung); + double Abtauzyklus_Pause = + Kennfeld_Entfeuchtung[2][Index_Entfeuchtung] * + Interpolation_Entfeuchtung + + Kennfeld_Entfeuchtung[2][Index_Entfeuchtung - 1] * + (1.0 - Interpolation_Entfeuchtung); + double Abtauzyklus_Dauer = + Kennfeld_Entfeuchtung[3][Index_Entfeuchtung] * + Interpolation_Entfeuchtung + + Kennfeld_Entfeuchtung[3][Index_Entfeuchtung - 1] * + (1.0 - Interpolation_Entfeuchtung); + + // Ende - f_PID_Door(...) + + // Überhitzungsregelung + + // Temperatur Verdampferausgang PT1 + // f_PT1.Vapourize(...) + if (!Startup_finished) { + Istwert_Temperatur_Verdampferausgang_PT1 = + Istwert_Temperatur_Verdampferausgang; + } else { + Istwert_Temperatur_Verdampferausgang_PT1 += + (Istwert_Temperatur_Verdampferausgang - + Istwert_Temperatur_Verdampferausgang_PT1) / + (60.0 * 4.0); + } + + // Skalierung Überhitzung + if (Istwert_Temperatur_Verdampferausgang < + (Istwert_Temperatur + Sollwert_Ueberhitzung)) { + Counter_Durchzug = MIN(Counter_Durchzug + sampling_time, 10.0); + } else { + // uj-todo; template for MAX + // Counter_Durchzug = MAX(MAX(Counter_Durchzug-sampling_time,-10),0); + } + if (Counter_Durchzug >= 10.0) { + Durchzug = true; + } else if (Counter_Durchzug <= -10.0) { + Durchzug = false; + } + + double Skalierung_Ueberhitzung_PT1 = Skalierung_Ueberhitzung_Kennfeld_Max; + + // Magnetventil Kühlung + + // Stellgrad Kühlung + + if (Counter_Verdichter_aus > 60.0 && Counter_Verdichter_aus < 600.0) { + Stellgrad_Kuehlventil = 1.0; + } else if (Istwert_Temperatur > 120.0 || Counter_Kuehlung_Freigabe <= 0.0) { + Stellgrad_Kuehlventil = 0.0; + } else { + Stellgrad_Kuehlventil = MAX(-Stellgrad_Kuehlung, 0.0) * + Skalierung_Ueberhitzung_PT1 * + Counter_Kuehlung_Freigabe; + } + + // Ende - f_PT1.Vapourize(...) + + // PWM Generierung Kuehlventil + // bool step(double Stellgrad,double sampling_time){ + + // f_PWMCoolingValve.Step(...) + Kuehlventil = PWM_Kuehlventil.step(Stellgrad_Kuehlventil, sampling_time); + + // Magnetventil Entfeuchtung + double T_Entfeuchtung; + if (!Startup_finished) { + T_Entfeuchtung = Istwert_Temperatur; + } else if (Entfeuchtungsventil) { + T_Entfeuchtung = + limit(T_Entfeuchtung + + ((Istwert_Temperatur - T_Entfeuchtung) * U_Entfeuchtung - + P_Entfeuchtung) / + (4.0 * C_Entfeuchtung), + -30.0, Istwert_Temperatur); + } else { + T_Entfeuchtung = + limit(T_Entfeuchtung + + ((Istwert_Temperatur - T_Entfeuchtung) * U_Entfeuchtung) / + (4.0 * C_Entfeuchtung), + -30.0, Istwert_Temperatur); + } + // Stellgrad Entfeuchtung + + if (Istwert_Temperatur > 120.0 || Counter_Entfeuchtung_Freigabe <= 0.0) { + Stellgrad_Entfeuchtungsventil = 0.0; + } else { + Stellgrad_Entfeuchtungsventil = MAX(-Stellgrad_Entfeuchtung, 0.0) * + Skalierung_Entfeuchtungsventil * + Counter_Entfeuchtung_Freigabe; + } + + // Abtauzyklus + bool Freigabe_Abtauzyklus = + Istwert_Feuchte > Sollwert_Feuchte_Absolut + 2.5; + if (!Freigabe_Abtauzyklus) { + Counter_Freigabe_Abtauzyklus = 0.0; + } else { + Counter_Freigabe_Abtauzyklus += sampling_time; + } + double Skalierung_Abtauzyklus_Dauer = 0.0; + ; + if (Abtauzyklus_Pause > 0.0 && Abtauzyklus_Dauer > 0.0) { + Skalierung_Abtauzyklus_Dauer = + limit(Counter_Freigabe_Abtauzyklus / + (10.0 * (Abtauzyklus_Pause + Abtauzyklus_Dauer) * 60.0), + 1.0, 5.0); + } + if (Counter_Abtauzyklus > + (Abtauzyklus_Pause + Abtauzyklus_Dauer * Skalierung_Abtauzyklus_Dauer) * + 60.0) { + Counter_Abtauzyklus = 0.0; + } else if ((T_Entfeuchtung < 0.0 && Freigabe_Abtauzyklus) || Abtauzyklus) { + Counter_Abtauzyklus += sampling_time; + } + + else { + Counter_Abtauzyklus = MAX(Counter_Abtauzyklus - sampling_time, 0.0); + } + Abtauzyklus = Counter_Abtauzyklus > Abtauzyklus_Pause * 60.0 && + Abtauzyklus_Pause > 0.0; + + if (Abtauzyklus) { + Stellgrad_Entfeuchtungsventil = 0.0; + } + // Ende -f_PWMCoolingValve.Step(...) + + + // PWM Entfeuchtungsventil + // f_PWMDeHumizeValve.Step(...) + Entfeuchtungsventil = PWM_Entfeuchtungsventil.step( + Stellgrad_Entfeuchtungsventil, sampling_time); + + // Druckausgleich vor Start Verdichter + if (!Verdichter && Counter_Entfeuchtung_Freigabe > 5.0) { + Entfeuchtungsventil = true; + } + + // Heizung Kessel + + if (Freigabe_Heizung) { + Stellgrad_HeizungKessel = + MAX(Stellgrad_Heizung * Counter_Heizung_Freigabe, 0.0); + } else { + Stellgrad_HeizungKessel = 0.0; + } + + // PWM Heizung Kessel + HeizungKessel = PWM_Heizung_Kessel.step(Stellgrad_HeizungKessel, 0.25); + + // Betauungsschutz + + double Stellgrad_Betauungsschutz_MAX = limit( + (90.0 + Stellgrad_Kuehlung_Mittelwert) / (90.0 - 80.0) * 100.0, 0.0, + limit((Sollwert_Temperatur - 25.0) / (-20.0 - 25.0) * Betauungsschutz, + 0.0, Betauungsschutz)); + + if (!Startup_finished) { + Stellgrad_Betauungsschutz = 0.0; + } + + // Tuerheizung + Stellgrad_HeizungTuer = + limit(Stellgrad_Tuer + Stellgrad_Betauungsschutz / 10.0, 0.0, 100.0); + + HeizungTuer = PWM_Heizung_Tuer.step(Stellgrad_HeizungTuer, 0.25); + + // Heizung Kesselrand + + Stellgrad_HeizungKesselrand = + limit(Stellgrad_Tuer * + limit(1.0 + Betauungsschutz / 100.0 * 2.0 * + (90.0 + Stellgrad_Kuehlung_Mittelwert) / + (90.0 - 80.0), + 1.0, 2.0) + + Stellgrad_Betauungsschutz, + 0.0, 100.0); + + // Ende - f_PWMDeHumizeValve.Step(...) + + + // PWM Kesselrand + // Ende - f_PWMKesselRand.Step(...) + HeizungKesselrand = PWM_Heizung_Kesselrand.step(Stellgrad_HeizungKesselrand, 0.25); + // Ende - f_PWMKesselRand.Step(...) + + { + // Binder Feuchtemodul + + // Sperrsignal Feuchtemodul + + bool Sperrsignal_Feuchte = false; + + // Gradient Feuchtemodul + + if (!Startup_finished) { + Temperatur_Feuchtemodul_Gradient = 0; + } else { + Temperatur_Feuchtemodul_Gradient += + ((Temperatur_Feuchtemodul - Temperatur_Feuchtemodul_alt) * 60.0 * + 4.0 - + Temperatur_Feuchtemodul_Gradient) / + (4.0 * 10.0); + } + + Sollwert_Temperatur_Feuchtemodul = + Sollwert_Temperatur_Feuchtemodul_MIN + + Stellgrad_Feuchtemodul_Mittelwert / 100.0 * + (Sollwert_Temperatur_Feuchtemodul_MAX - + Sollwert_Temperatur_Feuchtemodul_MIN); + + // Offset Stellgrad Feuchtemodul + + double Temperatur_Feuchtemodul_Standby = + Sollwert_Temperatur_Feuchtemodul - + (Stellgrad_Entfeuchtung_Mittelwert - 0.0) / (-100.0 - 0.0) * 60.0; + double Standby_Feuchtemodul = + limit((Temperatur_Feuchtemodul_Standby - Temperatur_Feuchtemodul) / + 10.0 * 5.0, + 0.0, 5.0); + + // Stellgrad Feuchtemodul + Stellgrad_Feuchtemodul = limit( + Stellgrad_Befeuchtung + + 2.0 * limit(Stellgrad_Befeuchtung - Stellgrad_Feuchtemodul_PT1, + -2.0, 2.0) + + Stellgrad_Feuchtemodul_Nachfuellen, + 0.0, 100.0); + + // Begrenzung Temperatur Feuchtemodul über Temperatur + double Stellgrad_Feuchtemodul_MAX_Temperatur = limit( + (Temperatur_Feuchtemodul_MAX - Temperatur_Feuchtemodul) / 40.0 * 100.0, + 0.0, 100.0); + + double Temperatur_Feuchtemodul_Gradient_MAX = 10.0; + if (Temperatur_Feuchtemodul < 90.0) { + Temperatur_Feuchtemodul_Gradient_MAX = 10.0; + } else { + Temperatur_Feuchtemodul_Gradient_MAX = limit( + 20.0 - + (Temperatur_Feuchtemodul - (Temperatur_Feuchtemodul_MAX - 60.0)) / + 60.0 * 20.0 - + Stellgrad_Feuchtemodul_MAX / 100.0 * 10.0, + 5.0, 20.0); + } + + double Stellgrad_Feuchtemodul_MAX_adaptiv = 10.0; + if (!Startup_finished) { + Stellgrad_Feuchtemodul_MAX_adaptiv = 10.0; + } else if (Temperatur_Feuchtemodul < 80.0) { + Stellgrad_Feuchtemodul_MAX_adaptiv = 10.0; + } else if (Stellgrad_Feuchtemodul + 20.0 > + Stellgrad_Feuchtemodul_MAX_adaptiv && + Stellgrad_Feuchtemodul_MAX_adaptiv < + Stellgrad_Feuchtemodul_MAX_Temperatur && + Temperatur_Feuchtemodul_Gradient < + 2.0 * Temperatur_Feuchtemodul_Gradient_MAX && + !Sperrsignal_Feuchte) { + Stellgrad_Feuchtemodul_MAX_adaptiv = + limit(Stellgrad_Feuchtemodul_MAX_adaptiv + + 20.0 * + limit((Temperatur_Feuchtemodul_Gradient_MAX - + Temperatur_Feuchtemodul_Gradient) / + Temperatur_Feuchtemodul_Gradient_MAX, + -2.0, 1.0) / + (60.0 * 4.0), + 0.0, Stellgrad_Feuchtemodul_MAX_Temperatur); + } else { + Stellgrad_Feuchtemodul_MAX_adaptiv = + limit(Stellgrad_Feuchtemodul_MAX_adaptiv - 5.0 / (60.0 * 4.0), 10.0, + Stellgrad_Feuchtemodul_MAX_Temperatur); + } + + // Begrenzung Stellgrad_Feuchtemodul + + Stellgrad_Feuchtemodul_MAX = + MIN(Stellgrad_Feuchtemodul_MAX_Temperatur - 5.0, + Stellgrad_Feuchtemodul_MAX_adaptiv + Stellgrad_Feuchtemodul_Boost); + + Stellgrad_Feuchtemodul = + MIN(Stellgrad_Feuchtemodul, Stellgrad_Feuchtemodul_MAX); + + // Stellgrad Feuchtemodul Boost + + if (!Startup_finished || Temperatur_Feuchtemodul < 80.0) { + Stellgrad_Feuchtemodul_Boost = 0.0; + } else if (Stellgrad_Feuchtemodul < + Stellgrad_Feuchtemodul_MAX_adaptiv - 10.0) { + Stellgrad_Feuchtemodul_Boost = + MIN(Stellgrad_Feuchtemodul_Boost + 10.0 / 60.0 * sampling_time, + 2.0 * Stellgrad_Feuchtemodul_MAX_Temperatur); + } else { + Stellgrad_Feuchtemodul_Boost = MAX( + Stellgrad_Feuchtemodul_Boost - (Stellgrad_Feuchtemodul + 10.0 - + Stellgrad_Feuchtemodul_MAX_adaptiv) / + 60.0 * sampling_time, + 0.0); + } + if (!Startup_finished) { + Stellgrad_Feuchtemodul_PT1 = Stellgrad_Feuchtemodul; + } else if (is_valid(Stellgrad_Feuchtemodul_PT1)) { + Stellgrad_Feuchtemodul_PT1 = 0.0; + } else { + Stellgrad_Feuchtemodul_PT1 = + Stellgrad_Feuchtemodul_PT1 + + (Stellgrad_Feuchtemodul - Stellgrad_Feuchtemodul_PT1) / (4.0 * 30.0); + } + + // Nachfüllen Befeuchtungsmodul + + double Stellgrad_Nachfuellen_Temperatur = 0.0; + double Skalierung_Nachfuellen_Temperatur_P_Anteil = 0.0; + double Skalierung_Nachfuellen_Temperatur_D_Anteil = 0.0; + + if (!Startup_finished) { + Stellgrad_Nachfuellen_Temperatur = 0.0; + Skalierung_Nachfuellen_Temperatur_D_Anteil = 0.0; + Skalierung_Nachfuellen_Temperatur_D_Anteil = 0.0; + Skalierung_Nachfuellen_Temperatur_I_Anteil = 0.0; + } else { + Stellgrad_Nachfuellen_Temperatur = limit( + MAX(Temperatur_Feuchtemodul - Sollwert_Temperatur_Feuchtemodul, 0.0) * + 2.0 + + MIN(Temperatur_Feuchtemodul - Sollwert_Temperatur_Feuchtemodul, + 0.0) * + 1.0, + -20.0, 50.0); + Skalierung_Nachfuellen_Temperatur_P_Anteil = limit( + MAX(Temperatur_Feuchtemodul - Sollwert_Temperatur_Feuchtemodul, 0.0) / + 20.0 + + MIN(Temperatur_Feuchtemodul - Sollwert_Temperatur_Feuchtemodul, + 0.0) / + 40.0, + -0.2, 5.0); + Skalierung_Nachfuellen_Temperatur_D_Anteil = + limit(Temperatur_Feuchtemodul_Gradient / 10.0, -5.0, 5.0); + Skalierung_Nachfuellen_Temperatur_I_Anteil = + limit(Skalierung_Nachfuellen_Temperatur_I_Anteil + + limit(Skalierung_Nachfuellen_Temperatur_P_Anteil + + Skalierung_Nachfuellen_Temperatur_D_Anteil, + -0.2, 25.0) * + sampling_time / 1200.0, + 0.0, 5.0); + } + double Stellgrad_Nachfuellen = 0.0; + Stellgrad_Feuchtemodul_Nachfuellen = 0.0; + + if (Temperatur_Feuchtemodul > Temperatur_Feuchtemodul_MAX && + Temperatur_Feuchtemodul_Gradient > 0.0) { + Stellgrad_Nachfuellen = 20.0; + Stellgrad_Feuchtemodul_Nachfuellen = 0.0; + } else { + Stellgrad_Nachfuellen = limit( + ((Stellgrad_Feuchtemodul_PT1 - Stellgrad_Feuchtemodul_Nachfuellen) * + (MAX(Skalierung_Nachfuellen_Temperatur_P_Anteil + + Skalierung_Nachfuellen_Temperatur_D_Anteil, + 0.0) + + Skalierung_Nachfuellen_Temperatur_I_Anteil) + + Stellgrad_Nachfuellen_Temperatur) * + 2.0 * 7.9681 / Durchflussmenge_Einlassventil_Feuchtemodul, + 0.0, 100.0); + Stellgrad_Feuchtemodul_Nachfuellen = + 0.5 * Stellgrad_Nachfuellen * + Durchflussmenge_Einlassventil_Feuchtemodul / 60.0 * 4.19 * 75.0 / + 600.0; + } + //(* Entleeren des Kessels *) + bool Entleeren_Kessel = false; + if (Startup_finished && Temperatur_Feuchtemodul < 70.0) { + Entleeren_Kessel = Counter_Entleeren_Kessel < 60.0; + Counter_Entleeren_Kessel += sampling_time; + } else { + Counter_Entleeren_Kessel = 0.0; + Entleeren_Kessel = false; + } + + //(* Abschlämmen des Kessels *) + Abschlaemmintegral = + Abschlaemmintegral + 0.1 * Durchflussmenge_Einlassventil_Feuchtemodul / + Durchflussmenge_Abschlaemmventil_Feuchtemodul * + Stellgrad_Nachfuellen / 100.0 * sampling_time; + + if (Entleeren_Kessel) { + Abschlaemmventil = true; + Stellgrad_Abschlaemmventil_zyklisch = 100.0; + } else { + Counter_Zyklus_Abschlaemmventil += sampling_time; + if (Abschlaemmintegral > 0.25 && Temperatur_Feuchtemodul_Gradient < 0.0) { + Abschlaemmventil = true; + Stellgrad_Abschlaemmventil_zyklisch = 2.5; + Counter_Zyklus_Abschlaemmventil = 0.0; + Abschlaemmintegral -= 0.25; + } else { + Abschlaemmventil = false; + if (Counter_Zyklus_Abschlaemmventil >= 10.0) { + Stellgrad_Abschlaemmventil_zyklisch = 0.0; + } + } + } + + // Stellgrad_Feuchtemodul = 2.0; + + // PWM Befeuchtungsmodul + HeizungFeuchtemodul = + PWM_Heizung_Feuchtemodul.step(Stellgrad_Feuchtemodul, 0.25); + // PWM Nachfüllen + Nachfuellen = PWM_Nachfuellen.step(Stellgrad_Nachfuellen, 0.25); + + // Abwassermanagement + if (!Entleerbehaelter_Unten || !Entleerbehaelter_Oben || Entleeren_Kessel) { + Counter_Nachlauf_Entleeren = 10.0; + Counter_Pause_Entleeren += sampling_time; + if (Counter_Pause_Entleeren > 30.0) { + Counter_Pause_Entleeren = 0.0; + } + + } else { + Counter_Nachlauf_Entleeren = + MAX(Counter_Nachlauf_Entleeren - sampling_time, 0.0); + Counter_Pause_Entleeren = 0.0; + } + bool Entleeren_Pause = false; + Entleeren = Counter_Nachlauf_Entleeren > 0.0; + Entleeren_Pause = Counter_Pause_Entleeren > 27.0; + Entleerpumpe = Entleeren && !Entleeren_Pause; + + if (!Startup_finished) { + Zyklus_Entleeren_Mittelwert = 600.0; + } else if (Entleeren && !Entleeren_alt) { + Zyklus_Entleeren_Mittelwert = limit( + Zyklus_Entleeren_Mittelwert + + (Counter_Zyklus_Entleeren - Zyklus_Entleeren_Mittelwert) / 10.0, + 10.0, 3600.0); + Counter_Zyklus_Entleeren = 0.0; + } else { + Counter_Zyklus_Entleeren += sampling_time; + } + + if (Steuerkontakt_Standby || Istwert_Temperatur > 110.0) { + Counter_Kuehlung_Freigabe = 0.0; + } else { + if (Stellgrad_Kuehlung < 0.0 || Stellgrad_Heizung < 2.0 || + Counter_Tuer_geschlossen < 300.0) { + Counter_Kuehlung_Freigabe = + MIN(Counter_Kuehlung_Freigabe + sampling_time / 10.0, 1.0); + } else { + Counter_Kuehlung_Freigabe = + MAX(Counter_Kuehlung_Freigabe - sampling_time / 300.0, 0.0); + } + } + Freigabe_Kuehlung = Counter_Kuehlung_Freigabe >= 1.0 || + (Freigabe_Kuehlung && Counter_Kuehlung_Freigabe > 0.0); + // * Freigabe Kühlung *) + + // (* Freigabe Entfeuchtung *) + if (Steuerkontakt_Standby || Istwert_Temperatur > 110.0) { + Counter_Entfeuchtung_Freigabe = 0.0; + } else { + if (Stellgrad_Entfeuchtung < 0.0 || Stellgrad_Befeuchtung < 2.0 || + Counter_Tuer_geschlossen < 300.0) { + Counter_Entfeuchtung_Freigabe = + MIN(Counter_Entfeuchtung_Freigabe + sampling_time / 10.0, 10.0); + } else { + Counter_Entfeuchtung_Freigabe = + MAX(Counter_Entfeuchtung_Freigabe - sampling_time / 300.0, 0.0); + } + } + Freigabe_Entfeuchtung = + Counter_Entfeuchtung_Freigabe >= 1.0 || + (Freigabe_Entfeuchtung && Counter_Entfeuchtung_Freigabe > 0.0); + + // (* Freigabe Heizung *) + if (Steuerkontakt_Standby || Istwert_Temperatur > 110.0) { + Counter_Heizung_Freigabe = 0.0; + } else { + if (Stellgrad_Heizung < 0.0 || Stellgrad_Kuehlung > -2.0 || + Counter_Tuer_geschlossen < 300.0) { + Counter_Heizung_Freigabe = + MIN(Counter_Heizung_Freigabe + sampling_time / 10.0, 10.0); + } else { + Counter_Heizung_Freigabe = + MAX(Counter_Heizung_Freigabe - sampling_time / 300.0, 0.0); + } + } + Freigabe_Heizung = Counter_Heizung_Freigabe >= 1.0 || + (Freigabe_Heizung && Counter_Heizung_Freigabe > 0.0); + // (* Freigabe Befeuchtung *) + if (Steuerkontakt_Standby || Istwert_Temperatur > 110.0) { + Counter_Befeuchtung_Freigabe = 0.0; + } else { + if (Stellgrad_Befeuchtung < 0.0 || Stellgrad_Entfeuchtung > -2.0 || + Counter_Tuer_geschlossen < 300.0) { + Counter_Befeuchtung_Freigabe = + MIN(Counter_Befeuchtung_Freigabe + sampling_time / 10.0, 10.0); + } else { + Counter_Befeuchtung_Freigabe = + MAX(Counter_Befeuchtung_Freigabe - sampling_time / 300.0, 0.0); + } + } + Freigabe_Befeuchtung = + Counter_Befeuchtung_Freigabe >= 1.0 || + (Freigabe_Befeuchtung && Counter_Befeuchtung_Freigabe > 0.0); + + // Verdichterabscaltung + + if (!Startup_finished) { + Drehzahl_Verdichter_adaptiv = Drehzahl_Verdichter_MAX; + } else if (Temperatursprung) { + Drehzahl_Verdichter_adaptiv = + MAX(Drehzahl_Verdichter_Kuehlung, Drehzahl_Verdichter_Entfeuchtung); + } else if (is_valid(Stellgrad_Kuehlung)) { + Drehzahl_Verdichter_adaptiv = + limit(Drehzahl_Verdichter_adaptiv + + (-Stellgrad_Kuehlung - 25.0) / 100.0 * + (Drehzahl_Verdichter_MAX - Drehzahl_Verdichter_MIN) / + (4.0 * 600.0), + Drehzahl_Verdichter_MIN, Drehzahl_Verdichter_MAX); + } + + Drehzahl_Verdichter_Kuehlung = + Drehzahl_Verdichter_MIN + + (MAX(-Stellgrad_Kuehlung_Mittelwert, -Stellgrad_Kuehlung) - 30.0) / + (90.0 - 30.0) * (Drehzahl_Verdichter_MAX - Drehzahl_Verdichter_MIN); + Drehzahl_Verdichter_Entfeuchtung = + Drehzahl_Verdichter_MIN + + 0.5 * + (MAX(-Stellgrad_Entfeuchtung_Mittelwert, -Stellgrad_Entfeuchtung) - + 50.0) / + (90.0 - 50.0) * (Drehzahl_Verdichter_MAX - Drehzahl_Verdichter_MIN); + + if (Verdichter) { + Drehzahl_Verdichter = + limit(MAX(Drehzahl_Verdichter_Kuehlung, + MAX(Drehzahl_Verdichter_Entfeuchtung, + Drehzahl_Verdichter_adaptiv)), + Drehzahl_Verdichter_MIN, Drehzahl_Verdichter_MAX); + } else { + Drehzahl_Verdichter = 1000.0; + } + + Stellgrad_Verdichter = + Drehzahl_Verdichter / Drehzahl_Verdichter_MAX * 100.0 * (160.0 / 200.0); + /* + (* -------------------- *) + (* Verflüssigerregelung *) + (* -------------------- *) */ + + Verfluessiger = Verfluessiger && + ((Drehzahl_Verdichter_adaptiv - Drehzahl_Verdichter_MIN) / ((Drehzahl_Verdichter_MAX - Drehzahl_Verdichter_MIN) < 0.30) && + (-Stellgrad_Kuehlung_Mittelwert < 30.0) && + (-Stellgrad_Entfeuchtung_Mittelwert < 60.0) || ((Drehzahl_Verdichter_adaptiv - Drehzahl_Verdichter_MIN) / (Drehzahl_Verdichter_MAX - Drehzahl_Verdichter_MIN) < 0.20) && + (-Stellgrad_Kuehlung_Mittelwert < 20.0) && + -Stellgrad_Entfeuchtung_Mittelwert < 50.0); + + }// Ende Feuchtemodul + + // ---------------------------------------- + // Werte die auf Veränderung geprüft werden + // ---------------------------------------- + Sammelalarm_quittiert_alt = Sammelalarm_quittiert; + Istwert_Temperatur_alt = Istwert_Temperatur; + Regelabweichung_Temperatur_alt = Regelabweichung_Temperatur; + Sollwert_Temperatur_alt = Sollwert_Temperatur; + Istwert_Feuchte_alt = Istwert_Feuchte; + Regelabweichung_Feuchte_alt_alt = Regelabweichung_Feuchte_alt; + Regelabweichung_Feuchte_alt = Regelabweichung_Feuchte; + Sollwert_Feuchte_alt = Sollwert_Feuchte; + Durchzug_alt = Durchzug; + Regelabweichung_Tuer_alt = Regelabweichung_Tuer; + HeizungFeuchtemodul_alt = HeizungFeuchtemodul; + Regelabweichung_Befeuchtung_alt_alt = Regelabweichung_Befeuchtung_alt; + Regelabweichung_Entfeuchtung_alt = Regelabweichung_Entfeuchtung; + + + + // ---------------- + // Rückgabewerte + // ---------------- + // F_Outputs out{}; + + binOut.bool_out01 = (std::abs((Sollwert_Temperatur - Istwert_Temperatur)) > Temperaturband); // du nutzt Temperaturband-Alarm + // separat; hier nur Beispiel + binOut.bool_out02 = (std::abs((Sollwert_Feuchte - Istwert_Feuchte)) > Feuchteband) && + (!Befeuchtung_aus) && (!Entfeuchtung_aus); + binOut.bool_out03 = Befeuchtung_aus || Entfeuchtung_aus; + binOut.bool_out07 = (!Status_Uebertemperatur) && + (!(std::abs(Istwert_Ueberwachungsregler - Istwert_Temperatur) > 20.0)); + alarmOut.Startup = Startup_finished; + + binOut.bool_out09 = HeizungKessel; + binOut.bool_out11 = HeizungTuer; + binOut.bool_out12 = HeizungKesselrand; + binOut.bool_out13 = Verfluessiger; + binOut.bool_out14 = Nachfuellen; + binOut.bool_out16 = Entleerpumpe; + binOut.bool_out17 = HeizungFeuchtemodul; + binOut.bool_out20 = Abschlaemmventil; + binOut.bool_out18 = Kuehlventil; + binOut.bool_out19 = Entfeuchtungsventil; + binOut.bool_out21 = Verdichter; + binOut.bool_out23 = !Sammelalarm_quittiert; + + analogOut.real_out01 = Istwert_Temperatur; + analogOut.real_out02 = Istwert_Temperatur; + analogOut.real_out04 = Istwert_Temperatur; + analogOut.real_out05 = limit(Istwert_Feuchte, 0.0, 100.0); + analogOut.real_out06 = limit(Istwert_Feuchte, 0.0, 100.0); + analogOut.real_out07 = Sollwert_Feuchte; + analogOut.real_out08 = limit(Istwert_Feuchte, 0.0, 100.0); + analogOut.real_out09 = Stellgrad_HeizungKessel; + analogOut.real_out10 = Stellgrad_Pumpe; + analogOut.real_out11 = Stellgrad_HeizungTuer; + analogOut.real_out12 = Stellgrad_HeizungKesselrand; + analogOut.real_out13 = Stellgrad_Feuchtemodul; + analogOut.real_out14 = Stellgrad_Abschlaemmventil_zyklisch; + analogOut.real_out16 = Temperatur_Feuchtemodul; + analogOut.Stellgrad_Feuchtemodul = Stellgrad_Feuchtemodul; + analogOut.real_out18 = Stellgrad_Kuehlventil; + analogOut.real_out19 = Stellgrad_Entfeuchtungsventil; + analogOut.real_out20 = Stellgrad_Luefter; + analogOut.real_out21 = Stellgrad_Verdichter; + analogOut.real_out25 = Schaltwert_Uebertemperatur; + analogOut.real_out26 = Schaltwert_Untertemperatur; + analogOut.Stellgrad_Heizung = Stellgrad_Heizung; + analogOut.Stellgrad_Kuehlung = Stellgrad_Kuehlung; + analogOut.Stellgrad_Befeuchtung = Stellgrad_Befeuchtung; + analogOut.Stellgrad_Entfeuchtung = Stellgrad_Entfeuchtung; + analogOut.Counter_Tuer = Counter_Tuer_offen; + + // alarms (wie ST) + alarmOut.alarm_01 = Bandalarm_Temperatur; + alarmOut.alarm_02 = Bandalarm_Feuchte; + alarmOut.alarm_03 = Tueralarm; + alarmOut.alarm_04 = false; + alarmOut.alarm_05 = false; + alarmOut.alarm_06 = Alarm_Wasser_Befeuchtungsmodul && !Befeuchtung_aus; + alarmOut.alarm_07 = Alarm_Abwasser_Befeuchtungsmodul; + alarmOut.alarm_08 = (Alarm_Heizung_Befeuchtungsmodul || Alarm_PT100_Befeuchtungsmodul) && + !Befeuchtung_aus; + + // alarm_09..alarm_15 sind im ST mit Selbsthaltung/Quittierung etc.: + alarmOut.alarm_09 = (((Istwert_Temperatur_Tuer < -50.0) || (Istwert_Temperatur_Tuer > 120.0)) && + Startup_finished) ||(alarm_09 && Sammelalarm_quittiert); + + alarmOut.alarm_10 = (std::abs(Istwert_Ueberwachungsregler - Istwert_Temperatur) > 20.0) || + ((((Istwert_Ueberwachungsregler < -50.0) || + (Istwert_Ueberwachungsregler > 120.0) && Startup_finished))) || + (alarm_10 && Sammelalarm_quittiert); + + alarmOut.alarm_11 = + Status_Uebertemperatur || StatusQuittierung_Uebertemperatur; + alarmOut.alarm_12 = + Status_Untertemperatur || StatusQuittierung_Untertemperatur; + + alarmOut.alarm_13 = (((Istwert_Temperatur_Verdampferausgang < -50.0) || + (Istwert_Temperatur_Verdampferausgang > 120.0)) && + Startup_finished) || + (alarm_13 && Sammelalarm_quittiert); + + alarmOut.alarm_14 = + (Counter_Wasserkanister_leer > 10.0 && Startup_finished) || + (alarm_14 && Sammelalarm_quittiert); + + alarmOut.alarm_15 = + ((analogInput.real_in11 > Sollwert_Feuchte_Max && !Befeuchtung_aus) || + (analogInput.real_in11 < Sollwert_Feuchte_Min && !Entfeuchtung_aus)) || + (alarm_15 && Sammelalarm_quittiert); + + // Selbsthaltung der Alarm-Bits (wie ST-OR alarm_x ...) + alarm_09 = alarmOut.alarm_09; + alarm_10 = alarmOut.alarm_10; + alarm_13 = alarmOut.alarm_13; + alarm_14 = alarmOut.alarm_14; + alarm_15 = alarmOut.alarm_15; + + // return out; + } + +private: + // ===== ST: VAR CONSTANT ===== + static constexpr double sampling_time = 0.25; + + static constexpr std::array, 4> Kennfeld_Ueberhitzung{ + {// 0: Temperatur + std::array{-20.0, -10.0, 0.0, 10.0, 20.0, 30.0, 40.0, 50.0, + 60.0, 70.0, 80.0, 90.0, 100.0}, + // 1: Skalierung Min + std::array{0.01, 0.02, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, + 0.8, 0.9, 1.0, 1.0}, + // 2: Skalierung Max + std::array{0.01, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, + 1.0, 1.0, 1.0}, + // 3: Sollwert Überhitzung + std::array{-6.0, -8.0, -10.0, -8.0, -6.0, -8.0, -10.0, -12.0, + -16.0, -20.0, -24.0, -28.0, -32.0}}}; + static constexpr std::array, 4> Kennfeld_Entfeuchtung{ + {// 0: Temperatur + std::array{-20.0, -10.0, 0.0, 10.0, 20.0, 30.0, 40.0, 50.0, + 60.0, 70.0, 80.0, 90.0, 100.0}, + // 1: Skalierung Entfeuchtung + std::array{0.08, 0.08, 0.08, 0.10, 0.12, 0.14, 0.16, 0.18, + 0.20, 0.22, 0.24, 0.26, 0.28}, + // 2: Abtauzyklus Pause + std::array{120.0, 120.0, 120.0, 120.0, 120.0, 90.0, 60.0, + 60.0, 60.0, 0.0, 0.0, 0.0, 0.0}, + // 3: Abtauzyklus Dauer + std::array{60.0, 60.0, 60.0, 30.0, 20.0, 10.0, 8.0, 4.0, 2.0, + 0.0, 0.0, 0.0, 0.0}}}; + + // Kennfelder (nur die, die oben genutzt werden; den Rest kannst du genauso + // hinzufügen) + static constexpr std::array Kennfeld_Regler_Heizung_Xp{ + 0.2, 0.5, 0.8, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0}; + static constexpr std::array Kennfeld_Regler_Kuehlung_Xp{ + 0.1, 0.1, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.0}; + static constexpr std::array, 9> + Kennfeld_Regler_Befeuchtung_Xp{ + {std::array{1.00, 0.54, 0.31, 0.18, 0.11, 0.07, 0.05, 0.03, + 0.02}, + std::array{1.00, 0.54, 0.31, 0.18, 0.11, 0.07, 0.05, 0.03, + 0.02}, + std::array{1.00, 0.54, 0.31, 0.18, 0.11, 0.07, 0.05, 0.03, + 0.02}, + std::array{1.00, 0.54, 0.31, 0.18, 0.11, 0.07, 0.05, 0.03, + 0.02}, + std::array{1.00, 0.54, 0.31, 0.18, 0.11, 0.07, 0.05, 0.03, + 0.02}, + std::array{1.00, 0.54, 0.31, 0.18, 0.11, 0.07, 0.05, 0.03, + 0.02}, + std::array{1.00, 0.54, 0.31, 0.18, 0.11, 0.07, 0.05, 0.03, + 0.02}, + std::array{1.00, 0.54, 0.31, 0.18, 0.11, 0.07, 0.05, 0.03, + 0.02}, + std::array{1.00, 0.54, 0.31, 0.18, 0.11, 0.07, 0.05, 0.03, + 0.02}}}; + static constexpr std::array, 9> + Kennfeld_Regler_Entfeuchtung_Xp{ + {std::array{1.00, 0.80, 0.60, 0.50, 0.40, 0.35, 0.30, 0.25, + 0.20}, + std::array{1.00, 0.80, 0.60, 0.50, 0.40, 0.35, 0.30, 0.25, + 0.20}, + std::array{1.00, 0.80, 0.60, 0.50, 0.40, 0.35, 0.30, 0.25, + 0.20}, + std::array{1.00, 0.80, 0.60, 0.50, 0.40, 0.35, 0.30, 0.25, + 0.20}, + std::array{1.00, 0.80, 0.60, 0.50, 0.40, 0.35, 0.30, 0.25, + 0.20}, + std::array{1.00, 0.80, 0.60, 0.50, 0.40, 0.35, 0.30, 0.25, + 0.20}, + std::array{1.00, 0.80, 0.60, 0.50, 0.40, 0.35, 0.30, 0.25, + 0.20}, + std::array{1.00, 0.80, 0.60, 0.50, 0.40, 0.35, 0.30, 0.25, + 0.20}, + std::array{1.00, 0.80, 0.60, 0.50, 0.40, 0.35, 0.30, 0.25, + 0.20}}}; + + static constexpr std::array, 3> + Kennfeld_Sollwert_Feuchte_Limit{ + {std::array{0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100}, + std::array{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80}, + std::array{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}}; + + // Zeitkonstanten etc. + static constexpr double Tau_Heizung_Tv = 10.0; + + // Faktoren + static constexpr double F_Xp_Heizung = 3.8; + static constexpr double F_Xp_Kuehlung = 33.6; + static constexpr double F_Xp_Befeuchtung_BINDER = 131.0; + static constexpr double F_Xp_Entfeuchtung = 100.0; + static constexpr double F_Xp_Tuer = 10.0; + + // ===== ST: VAR (Zustände / Merker) ===== + // (ich halte hier nur die, die im übersetzten Teil genutzt werden; den Rest + // kannst du 1:1 ergänzen) + double Istwert_Temperatur{}; + double Istwert_Temperatur_alt{}; + double Sollwert_Temperatur{}; + double Sollwert_Temperatur_alt{}; + double Sollwert_Gegenbefeuchten = 0.0; + double Regelabweichung_Befeuchtung_alt = 0.0; + double P_Anteil_Befeuchtung = 0.0; + double Counter_Entfeuchtung_Freigabe = 0.0; + bool Freigabe_Entfeuchtung = false; + double Counter_Heizung_Freigabe = 0.0; + bool Freigabe_Heizung = false; + double Counter_Befeuchtung_Freigabe = 0.0; + bool Freigabe_Befeuchtung = false; + bool Abtauzyklus = false; + double Counter_Zyklus_Entleeren = 0.0; + double Drehzahl_Verdichter_Kuehlung = 0.0; + double Drehzahl_Verdichter_Entfeuchtung = 0.0; + double Drehzahl_Verdichter = 0.0; + + /*PWM(double zyklus_min, double zyklus_max, double initial_zykluszeit = -1.0) + noexcept : Zyklus(0.0), Ausgabe(0.0), Zykluszeit((initial_zykluszeit > 0.0) ? + initial_zykluszeit : zyklus_max), Zyklus_MIN(zyklus_min), + Zyklus_MAX(zyklus_max) + {} + + bool step(double Stellgrad,double sampling_time,double Zyklus_MIN,double + Zyklus_MAX){*/ + PWM PWM_Heizung_Kessel = {10.0, 600.0, 0.0}; + PWM PWM_Heizung_Tuer = {10.0, 600.0, 0.0}; + PWM PWM_Nachfuellen = {10.0, 600.0, 0.0}; + PWM PWM_Heizung_Kesselrand = {10.0, 600.0, 0.0}; + PWM PWM_Heizung_Feuchtemodul = {10.0, 600.0, 0.0}; + PWM PWM_Kuehlventil = {10.0, 600.0, 0.0}; + PWM PWM_Entfeuchtungsventil = {10.0, 600.0, 0.0}; + + double Istwert_Ueberwachungsregler{}; + std::uint32_t Modus_Ueberwachungsregler{}; + double Offset_Ueberwachungsregler{}; + double Klasse_Ueberwachungsregler{}; + bool Wasserkanister_leer{}; + double Regler_Tuer_Tn = 700.0; + double Regler_Tuer_Tv = 60.0; + double Tau_Tuer_Tv = 60.0; + double Regler_Entfeuchtung_MAX = 0.0; + double Regler_Entfeuchtung_MIN = 0.0; + double Regler_Entfeuchtung_I_Anteil_MAX = 0.0; + double Regler_Entfeuchtung_I_Anteil_MIN = 0.0; + bool Freigabe_Kuehlung = false; + double Sollwert_Temperatur_Feuchtemodul_MIN = 110.0; + double Sollwert_Temperatur_Feuchtemodul_MAX = 130.0; + double Zyklus_Entleeren_Mittelwert = 600.0; + + double Grenzwert_Uebertemperatur{}; + double Schaltwert_Uebertemperatur{}; + bool Status_Uebertemperatur{}; + std::uint32_t Counter_Status_Uebertemperatur{}; + bool StatusQuittierung_Uebertemperatur{}; + + double Grenzwert_Untertemperatur{}; + double Schaltwert_Untertemperatur{}; + bool Status_Untertemperatur{}; + std::uint32_t Counter_Status_Untertemperatur{}; + bool StatusQuittierung_Untertemperatur{}; + + double Istwert_Feuchte{}; + double Istwert_Feuchte_alt{}; + double Sollwert_Feuchte{}; + double Sollwert_Feuchte_alt{}; + double Counter_Entleeren_Kessel{}; + + bool Regelung_AUS{}; + double Counter_Regelung_AUS{}; + bool Steuerkontakt_Standby{}; + bool Sammelalarm{}; + bool Sammelalarm_quittiert{}; + bool Sammelalarm_quittiert_alt{}; + double Regler_Kuehlung_Tv = 5.0; + double Tau_Kuehlung_Tv = 30.0; + double Theta_I_Kuehlung = 1.0; + + // Feuchte absolut + double p_H2Omax_Sollwert{}; + double p_H2Omax_Istwert{}; + double Taupunkt_Istwert{}; + double Sollwert_Feuchte_Absolut{}; + double Sollwert_Temperatur_Feuchtemodul{}; + double Counter_Kuehlung_Freigabe = 0.0; + + // Tür + bool Tuer_offen{}; + double Counter_Tuer_offen{}; + double Counter_Tuer_geschlossen{}; + double Istwert_Temperatur_Tuer{}; + double Regelabweichung_Tuer{}; + double Regelabweichung_Tuer_alt{}; + double Abschlaemmintegral = 0.0; + double Standby_Feuchtemodul = 0.0; + double Regelabweichung_Befeuchtung_alt_alt = 0.0; + double Regelabweichung_Entfeuchtung_alt = 0.0; + double Durchflussmenge_Einlassventil_Feuchtemodul = 400.0; + double Durchflussmenge_Abschlaemmventil_Feuchtemodul = 1500.0; + + // Startup / reset + std::uint32_t Counter_reset_flag{}; + bool Startup_finished{}; + + // Feuchte limit + std::uint16_t Index_Sollwert_Feuchte_Limit{}; + double Interpolation_Sollwert_Feuchte_Limit{}; + double Sollwert_Feuchte_Min{}; + double Sollwert_Feuchte_Max{}; + + // Abschaltung Feuchte-Regler + bool Sollwert_Feuchte_aktiv{}; + bool Steuerkontakt_Befeuchtung_aus{}; + bool Steuerkontakt_Entfeuchtung_aus{}; + bool Befeuchtung_aus{}; + bool Entfeuchtung_aus{}; + double Sollwert_Gegenheizen = 2.0; + // Parameter Indizes + std::uint16_t Index_Feuchte{}; + std::uint16_t Index_Temperatur{}; + std::uint16_t Index_Temperatur_ohne_Feuchte{}; + + // Reglerparameter + double Regler_Heizung_Xp{}; + double Regler_Kuehlung_Xp{}; + double Regler_Befeuchtung_Xp{}; + double Regler_Entfeuchtung_Xp{}; + double Regler_Tuer_Xp{}; + double Regler_Befeuchtung_Tv = 30.0; + double Regler_Befeuchtung_Tn = 100.0; + double Regler_Befeuchtung_Tz = 1200.0; + double Tau_Befeuchtung_Tv = 10.0; + double Tau_Befeuchtung_Tz = 5.0; + + // Regelkern Temperatur + double Sollwert_Temperatur_MIN{}; + double Sollwert_Temperatur_MAX{}; + + double Regelabweichung_Temperatur{}; + double Regelabweichung_Temperatur_alt{}; + double Regelabweichung_Temperatur_Mittelwert{}; + double Standardregelabweichung_Temperatur{}; + double Regelabweichung_Temperatur_Gradient{}; + double Standardgradient_Regelabweichung_Temperatur{}; + double Zykluszeit_Regelabweichung_Temperatur{}; + double Amplitude_Regelabweichung_Temperatur{}; + double Zykluszeit_Regelabweichung_Heizung{}; + double Zykluszeit_Regelabweichung_Kuehlung{}; + double Regelabweichung_Kuehlung_Gradient{}; + double Regelabweichung_Kuehlung_alt{}; + double Faktor_Kuehlung{}; + double Faktor_Gegenheizen_Band{}; + double I_Anteil_Kuehlung{}; + double D_Anteil_Kuehlung{}; + double Regelabweichung_Befeuchtung_Gradient{}; + double I_Anteil_Befeuchtung{}; + double Istwert_Temperatur_Verdampferausgang_PT1 = 0.0; + double D_Anteil_Befeuchtung{}; + bool Temperatursprung{}; + double Counter_Temperatursprung{}; + double Faktor_Entfeuchtung{}; + double Faktor_Gegenbefeuchten_Band = 5.0; + double I_Anteil_Entfeuchtung = 0.0; + double D_Anteil_Entfeuchtung = 0.0; + double I_Anteil_Tuer = 0.0; + double P_Anteil_Tuer; + double Regler_Heizung_MIN{}; + double Regler_Heizung_MAX{}; + double Regler_Heizung_I_Anteil_MIN{}; + double Regler_Heizung_I_Anteil_MAX{}; + double P_Anteil_Heizung{}; + double I_Anteil_Heizung{}; + double D_Anteil_Heizung{}; + double Stellgrad_Heizung{}; + double Stellgrad_Heizung_Mittelwert{}; + double Regelabweichung_Entfeuchtung_Gradient = 0.0; + double D_Anteil_Tuer = 0.0; + double Counter_Verdichter_aus = 0.0; + double Counter_Freigabe_Abtauzyklus = 0.0; + double Counter_Abtauzyklus; + double Stellgrad_Feuchtemodul_MAX{}; + double Skalierung_Nachfuellen_Temperatur_I_Anteil{}; + double Counter_Zyklus_Abschlaemmventil = 0.0; + const double Regler_Kuehlung_Tn = 200.0; + + double Stellgrad_Feuchtemodul_Boost{}; + const double Temperatur_Feuchtemodul_MAX = 200.0; + + // Feuchte - nur Platzhalter (weil spätere Ausdrücke referenzieren) + double Regelabweichung_Feuchte{}; + double Regelabweichung_Feuchte_alt{}; + double Regelabweichung_Feuchte_alt_alt{}; + double Regelabweichung_Feuchte_Mittelwert{}; + double Standardregelabweichung_Feuchte{}; + double Regelabweichung_Feuchte_Gradient{}; + double Standardgradient_Regelabweichung_Feuchte{}; + double Zykluszeit_Regelabweichung_Feuchte{}; + double Amplitude_Regelabweichung_Feuchte{}; + bool Feuchtesprung{}; + double Counter_Feuchtesprung = 0.0; + double Offset_Regelabweichung_Befeuchtung{}; + double Offset_Regelabweichung_Entfeuchtung{}; + double Stellgrad_Kuehlung{}; + double Stellgrad_Kuehlung_Mittelwert{}; + double Stellgrad_Befeuchtung{}; + double Stellgrad_Befeuchtung_Mittelwert{}; + double Stellgrad_Befeuchtung_Standby{}; + double Stellgrad_Entfeuchtung{}; + double Stellgrad_Entfeuchtung_Mittelwert{}; + double Z_Anteil_Befeuchtung{}; + + // Aktoren/Signale (Defaults, bis restliche Logik ergänzt ist) + bool HeizungKessel{}; + double Stellgrad_HeizungKessel{}; + bool HeizungTuer{}; + double Stellgrad_HeizungTuer{}; + bool HeizungKesselrand{}; + double Stellgrad_HeizungKesselrand{}; + bool Verfluessiger{}; + bool Nachfuellen{}; + bool Entleerpumpe{}; + bool HeizungFeuchtemodul{}; + bool HeizungFeuchtemodul_alt{}; + bool Abschlaemmventil{}; + double Stellgrad_Abschlaemmventil_zyklisch{}; + bool Kuehlventil{}; + double Stellgrad_Kuehlventil{}; + bool Entfeuchtungsventil{}; + double Stellgrad_Entfeuchtungsventil{}; + bool Verdichter{}; + double Stellgrad_Verdichter{}; + double Stellgrad_Pumpe{}; + double Stellgrad_Luefter{}; + double Stellgrad_Betauungsschutz{}; + double Temperatur_Feuchtemodul_Gradient = 0.0; + double Stellgrad_Feuchtemodul_MAX_adaptiv = 0.0; + double Counter_Nachlauf_Entleeren = 0.0; + double Counter_Pause_Entleeren = 0.0; + + // “Durchzug” (wird später in Überhitzungslogik gesetzt) + bool Durchzug{}; + bool Durchzug_alt{}; + double Counter_Durchzug{}; + + // Befeuchtungsmodul Zustände (Platzhalter, damit “Werte die auf Veränderung + // geprüft werden” passt) + double Temperatur_Feuchtemodul{}; + double Temperatur_Feuchtemodul_alt{}; + double Stellgrad_Feuchtemodul{}; + double Stellgrad_Feuchtemodul_Mittelwert{}; + double Stellgrad_Feuchtemodul_PT1{}; + double Stellgrad_Feuchtemodul_Nachfuellen{}; + bool Entleeren{}; + bool Entleeren_alt{}; + bool Entleerbehaelter_Oben{}; + bool Entleerbehaelter_Unten{}; + double Counter_Wasserkanister_leer{}; + double Regler_Entfeuchtung_Tv = 5.0; + double Regler_Entfeuchtung_Tn = 200.0; + double Tau_Entfeuchtung_Tv = 60.0; + double Theta_I_Entfeuchtung = 0.1; + double C_Entfeuchtung = 200.0; + double U_Entfeuchtung = 0.4; + double P_Entfeuchtung = 500.0; + double Regler_Entfeuchten_I_Anteil_MIN = 0.0; + double Drehzahl_Verdichter_MIN = 1800.0; + double Drehzahl_Verdichter_MAX = 4500.0; + double Drehzahl_Verdichter_adaptiv = 0.0; + + // Alarmbits mit Selbsthaltung + bool alarm_09{}; + bool alarm_10{}; + bool alarm_13{}; + bool alarm_14{}; + bool alarm_15{}; + bool Alarm_Wasser_Befeuchtungsmodul{}; + bool Alarm_Abwasser_Befeuchtungsmodul{}; + bool Alarm_PT100_Befeuchtungsmodul{}; + bool Alarm_Heizung_Befeuchtungsmodul{}; + bool Bandalarm_Temperatur{}; + bool Bandalarm_Feuchte{}; + bool Tueralarm{}; +}; + +// namespace UTILITY_FUNCTIONS + +// double PT100_ResistanceToTemperature_Linear(double R) +// { +// constexpr double R0 = 100.0; +// constexpr double alpha = 0.00385; // IEC-Näherung + +// return (R - R0) / (R0 * alpha); +// } + +class PT1 { +public: + PT1() = default; + void initialize(double fs, double t_cutoff) { + fs_ = fs; + ts_ = 1 / fs_; + double f_cutoff = 1. / t_cutoff; + tau_ = 1 / (2 * PI_CONST * f_cutoff); + lambda_ = 2 * tau_ / ts_; + b0_ = k_ / (1. + lambda_); + b1_ = k_ / (1. + lambda_); + a0_ = (1. - lambda_) / (1. + lambda_); + }; + + double step(double x) { + + double y = b0_ * x + s1_; + // s1 = b1*x - a1*y + s1_ = b1_ * x - a0_ * y; + return y; + }; + +private: + double s1_ = 0.; + double fs_ = 1.; + double ts_ = 1.; + double tau_ = 1.; + double a0_ = 0.; + double b0_ = 0.; + double b1_ = 0.; + double k_ = 1.; + double lambda_ = 1.; +}; + +#ifdef BUILD_TARGET_SOM +namespace appengine::state { +class IStateVariable; +} +#endif + +#ifdef BUILD_TARGET_SOM +class Controller : public ControllerBase { +public: + bool initialize(const char *configFilePath, + appengine::IAppLogic *appLogic) override; + void step() override; + void terminate() override; + +private: + appengine::IAppLogic *appLogic_{nullptr}; + + // Beispiel: du wirst für diese ST-Logik sehr viele StateVars mappen; + // hier nur exemplarisch: + std::shared_ptr tempVariable_; + std::shared_ptr tempSetPointVariable_; + + // TODO: bool_inXX / real_inXX / bool_outXX / real_outXX / alarm_XX als + // StateVariables holen (oder je nach AppEngine: arrays/IO mapping) + + ClimateAlgorithm algo_{}; + PT1 FILTERED_TEMP{}; + PT1 FILTER_TUER{}; + // Eingänge + std::shared_ptr const_duty_cycle_; + std::shared_ptr const_freq_; + std::shared_ptr Wasserstand_Oben_Config_; + std::shared_ptr Wasserstand_Unten_Config_; + std::shared_ptr Fuellstand_Config_; + std::shared_ptr SV_Tuer_Variable_; + std::shared_ptr SV_Verdampferausgang_; + std::shared_ptr SV_Befeuchtungsmodul_; + std::shared_ptr SV_Verdichter_on_; + std::shared_ptr Startup_; + std::shared_ptr CounterTuer_; + + // ausgänge + std::vector subscriptions_{}; + std::shared_ptr Heizung_Bef_Config_; + std::shared_ptr MV_Kuehlung_Config_; + std::shared_ptr Abschlaemmen_Config_; + std::shared_ptr Entleerpumpe_Config_; + std::shared_ptr Heizung_Kesselrand_Config_; + std::shared_ptr + Freigabe_Verfluessigerluefter_Config_; + std::shared_ptr Heizung_Innenraum_Config_; + std::shared_ptr Heizung_Tuer_Config_; + std::shared_ptr Uebertemperatur_Config_; + std::shared_ptr MV_Entfeuchtung_Config_; + std::shared_ptr MV_Druckluft_Config_; + std::shared_ptr + Ansteuerung_Wassereinlass_Config_; + std::shared_ptr + Ansteuerung_Verdichter_Config_; + std::shared_ptr Verdichter_Duty_Config; + std::shared_ptr Luefter_Innenraum_Config_; + + std::shared_ptr SV_Stellgrad_Heizung; + std::shared_ptr SV_Stellgrad_Kuehlung; + std::shared_ptr SV_Stellgrad_Befeuchtung; + std::shared_ptr SV_Stellgrad_Entfeuchtung; + // Regelgrößen + std::shared_ptr SV_Sollwert_Temperatur_; + std::shared_ptr SV_Temperatur_Variable_; + std::shared_ptr SV_Sollwert_Feuchte_; + std::shared_ptr SV_Feuchte_Variable_; + + // std::vector subscriptions_{}; +}; + +extern "C" BINDER_SIMULINK_API_EXPORT ControllerBase *create(); + +#else +class Controller { + +public: + bool initialize(const char *configFilePath); + void step(); + void terminate(); + +private: +#if 0 + appengine::IAppLogic *appLogic_{nullptr}; + + // Beispiel: du wirst für diese ST-Logik sehr viele StateVars mappen; + // hier nur exemplarisch: + std::shared_ptr tempVariable_; + std::shared_ptr tempSetPointVariable_; + + // TODO: bool_inXX / real_inXX / bool_outXX / real_outXX / alarm_XX als StateVariables holen + // (oder je nach AppEngine: arrays/IO mapping) + + ClimateAlgorithm algo_{}; + PT1 FILTERED_TEMP{} ; + PT1 FILTER_TUER{}; + // Eingänge + std::shared_ptr const_duty_cycle_; + std::shared_ptr const_freq_; + std::shared_ptr Wasserstand_Oben_Config_; + std::shared_ptr Wasserstand_Unten_Config_; + std::shared_ptr Fuellstand_Config_; + std::shared_ptr SV_Tuer_Variable_; + std::shared_ptr SV_Verdampferausgang_; + std::shared_ptr SV_Befeuchtungsmodul_; + std::shared_ptr SV_Verdichter_on_; + std::shared_ptr Startup_; + std::shared_ptr CounterTuer_; + + // ausgänge + std::vector subscriptions_{}; + std::shared_ptr Heizung_Bef_Config_; + std::shared_ptr MV_Kuehlung_Config_; + std::shared_ptr Abschlaemmen_Config_; + std::shared_ptr Entleerpumpe_Config_; + std::shared_ptr Heizung_Kesselrand_Config_; + std::shared_ptr Freigabe_Verfluessigerluefter_Config_; + std::shared_ptr Heizung_Innenraum_Config_; + std::shared_ptr Heizung_Tuer_Config_; + std::shared_ptr Uebertemperatur_Config_; + std::shared_ptr MV_Entfeuchtung_Config_; + std::shared_ptr MV_Druckluft_Config_; + std::shared_ptr Ansteuerung_Wassereinlass_Config_; + std::shared_ptr Ansteuerung_Verdichter_Config_; + std::shared_ptr Verdichter_Duty_Config; + std::shared_ptr Luefter_Innenraum_Config_; + + std::shared_ptr SV_Stellgrad_Heizung; + std::shared_ptr SV_Stellgrad_Kuehlung; + std::shared_ptr SV_Stellgrad_Befeuchtung; + std::shared_ptr SV_Stellgrad_Entfeuchtung; + // Regelgrößen + std::shared_ptr SV_Sollwert_Temperatur_; + std::shared_ptr SV_Temperatur_Variable_; + std::shared_ptr SV_Sollwert_Feuchte_; + std::shared_ptr SV_Feuchte_Variable_; + + //std::vector subscriptions_{}; +#endif +}; + +#endif + diff --git a/controller/libctrl_algo.so b/controller/libctrl_algo.so index f28ae24..316beff 100755 Binary files a/controller/libctrl_algo.so and b/controller/libctrl_algo.so differ diff --git a/tests/CMakeFiles/tests.dir/filter-test.cpp.o b/tests/CMakeFiles/tests.dir/filter-test.cpp.o deleted file mode 100755 index f2fa7e2..0000000 Binary files a/tests/CMakeFiles/tests.dir/filter-test.cpp.o and /dev/null differ