diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..85a65d3
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+build
+*.zip
+*.user
+app/.qtcreator/CMakeLists.txt.user
diff --git a/.qtcreator/CMakeLists.txt.user.fc8d3b1 b/.qtcreator/CMakeLists.txt.user.fc8d3b1
new file mode 100644
index 0000000..eecc273
--- /dev/null
+++ b/.qtcreator/CMakeLists.txt.user.fc8d3b1
@@ -0,0 +1,517 @@
+
+
+
+
+
+ EnvironmentId
+ {fc8d3b14-ba13-41ed-9488-a8a57abc777a}
+
+
+ ProjectExplorer.Project.ActiveTarget
+ 0
+
+
+ ProjectExplorer.Project.EditorSettings
+
+ true
+ true
+ true
+
+ Cpp
+
+ CppGlobal
+
+
+
+ QmlJS
+
+ QmlJSGlobal
+
+
+ 2
+ UTF-8
+ false
+ 4
+ false
+ 0
+ 80
+ true
+ true
+ 1
+ 0
+ false
+ true
+ false
+ 2
+ true
+ true
+ 0
+ 8
+ true
+ false
+ 1
+ false
+ true
+ true
+ *.md, *.MD, Makefile
+ false
+ true
+ true
+
+
+
+ ProjectExplorer.Project.PluginSettings
+
+
+ true
+ false
+ true
+ true
+ true
+ true
+
+ false
+
+
+ 0
+ true
+
+ true
+ true
+ Builtin.DefaultTidyAndClazy
+ 8
+ true
+
+ /home/yoct/evaluation/cli/tmp-bbr-algo/bbr-algo/CMakeLists.txt
+
+
+
+ true
+
+ 0
+
+
+
+ ProjectExplorer.Project.Target.0
+
+ Desktop
+ true
+ Desktop Qt 6.10.2
+ Desktop Qt 6.10.2
+ qt.qt6.6102.linux_gcc_64_kit
+ 0
+ 0
+ 0
+
+ Debug
+ 2
+ false
+
+ -DCMAKE_BUILD_TYPE:STRING=Debug
+-DCMAKE_COLOR_DIAGNOSTICS:BOOL=ON
+-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx}
+-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C}
+-DCMAKE_GENERATOR:STRING=Ninja
+-DCMAKE_MAKE_PROGRAM:STRING=/usr/bin/ninja
+-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX}
+-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtcreator/cmake-helper/qtcreator-project.cmake
+-DQT_CREATOR_ENABLE_MAINTENANCE_TOOL_PROVIDER:BOOL=ON
+-DQT_ENABLE_QML_DEBUG:BOOL=%{Qt:QT_ENABLE_QML_DEBUG}
+-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable}
+ 0
+ ./build/%{Asciify:%{Kit:FileSystemName}-%{BuildConfig:Name}}
+
+
+
+
+ all
+
+ false
+
+ true
+ Erstellen
+ CMakeProjectManager.MakeStep
+
+ 1
+ Erstellen
+ Erstellen
+ ProjectExplorer.BuildSteps.Build
+
+
+
+
+
+ clean
+
+ false
+
+ true
+ Erstellen
+ CMakeProjectManager.MakeStep
+
+ 1
+ Bereinigen
+ Bereinigen
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ false
+
+ Debug
+ CMakeProjectManager.CMakeBuildConfiguration
+ 0
+ 0
+
+
+ 0
+ Deployment
+ Deployment
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+
+ false
+ ProjectExplorer.DefaultDeployConfiguration
+
+
+
+
+
+
+
+
+ false
+
+ true
+ ApplicationManagerPlugin.Deploy.CMakePackageStep
+
+
+ install-package --acknowledge
+ true
+ Application Manager-Paket installieren
+ ApplicationManagerPlugin.Deploy.InstallPackageStep
+
+
+
+
+
+
+
+ 2
+ Deployment
+ Deployment
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+
+ false
+ ApplicationManagerPlugin.Deploy.Configuration
+
+ 2
+
+ false
+
+ false
+
+
+ true
+ true
+ 0
+ true
+
+
+ 2
+
+ false
+ -e cpu-cycles --call-graph dwarf,4096 -F 250
+
+ CMakeProjectManager.CMakeRunConfiguration.
+ app
+ false
+
+ true
+ true
+ true
+ %{RunConfig:Executable:Path}
+
+
+ true
+ true
+ 0
+ true
+
+
+ 2
+
+ false
+ -e cpu-cycles --call-graph dwarf,4096 -F 250
+
+ CMakeProjectManager.CMakeRunConfiguration.
+ tests
+ false
+
+ true
+ true
+ true
+ %{RunConfig:Executable:Path}
+
+ 2
+
+
+ Release
+ 2
+ false
+
+ -DCMAKE_BUILD_TYPE:STRING=Release
+-DCMAKE_COLOR_DIAGNOSTICS:BOOL=ON
+-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx}
+-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C}
+-DCMAKE_GENERATOR:STRING=Ninja
+-DCMAKE_MAKE_PROGRAM:STRING=/usr/bin/ninja
+-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX}
+-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtcreator/cmake-helper/qtcreator-project.cmake
+-DQT_CREATOR_ENABLE_MAINTENANCE_TOOL_PROVIDER:BOOL=ON
+-DQT_ENABLE_QML_DEBUG:BOOL=%{Qt:QT_ENABLE_QML_DEBUG}
+-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable}
+ ./build/%{Asciify:%{Kit:FileSystemName}-%{BuildConfig:Name}}
+
+
+
+
+ all
+
+ false
+
+ true
+ CMakeProjectManager.MakeStep
+
+ 1
+ Erstellen
+ Erstellen
+ ProjectExplorer.BuildSteps.Build
+
+
+
+
+
+ clean
+
+ false
+
+ true
+ CMakeProjectManager.MakeStep
+
+ 1
+ Bereinigen
+ Bereinigen
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ false
+
+ Release
+ CMakeProjectManager.CMakeBuildConfiguration
+ 1
+ 0
+
+
+ 0
+ Deployment
+ Deployment
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+
+ false
+ ProjectExplorer.DefaultDeployConfiguration
+
+
+
+
+
+
+
+
+ false
+
+ true
+ ApplicationManagerPlugin.Deploy.CMakePackageStep
+
+
+ install-package --acknowledge
+ true
+ Application Manager-Paket installieren
+ ApplicationManagerPlugin.Deploy.InstallPackageStep
+
+
+
+
+
+
+
+ 2
+ Deployment
+ Deployment
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+
+ false
+ ApplicationManagerPlugin.Deploy.Configuration
+
+ 2
+
+ false
+
+ false
+
+
+ true
+ true
+ 0
+ true
+
+
+ 2
+
+ false
+ -e cpu-cycles --call-graph dwarf,4096 -F 250
+
+ CMakeProjectManager.CMakeRunConfiguration.
+ app
+ false
+
+ true
+ true
+ true
+ %{RunConfig:Executable:Path}
+
+
+ true
+ true
+ 0
+ true
+
+
+ 2
+
+ false
+ -e cpu-cycles --call-graph dwarf,4096 -F 250
+
+ CMakeProjectManager.CMakeRunConfiguration.
+ tests
+ false
+
+ true
+ true
+ true
+ %{RunConfig:Executable:Path}
+
+ 2
+
+ 2
+
+
+ 0
+ Deployment
+ Deployment
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+
+ false
+ ProjectExplorer.DefaultDeployConfiguration
+
+
+
+
+
+
+
+
+ false
+
+ true
+ ApplicationManagerPlugin.Deploy.CMakePackageStep
+
+
+ install-package --acknowledge
+ true
+ Application Manager-Paket installieren
+ ApplicationManagerPlugin.Deploy.InstallPackageStep
+
+
+
+
+
+
+
+ 2
+ Deployment
+ Deployment
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+
+ false
+ ApplicationManagerPlugin.Deploy.Configuration
+
+ 2
+
+ true
+ true
+ 0
+ true
+
+
+ 2
+
+ false
+ -e cpu-cycles --call-graph dwarf,4096 -F 250
+
+ CMakeProjectManager.CMakeRunConfiguration.
+ app
+ false
+
+ true
+ true
+ true
+ %{RunConfig:Executable:Path}
+
+
+ true
+ true
+ 0
+ true
+
+
+ 2
+
+ false
+ -e cpu-cycles --call-graph dwarf,4096 -F 250
+
+ CMakeProjectManager.CMakeRunConfiguration.
+ tests
+ false
+
+ true
+ true
+ true
+ %{RunConfig:Executable:Path}
+
+ 2
+
+
+
+ ProjectExplorer.Project.TargetCount
+ 1
+
+
+ Version
+ 22
+
+
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..01b6493
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,27 @@
+cmake_minimum_required(VERSION 3.19)
+project(bbr-algo LANGUAGES CXX)
+
+set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+
+find_package(Qt6 REQUIRED COMPONENTS Core)
+
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+
+
+option(BUILD_TARGET_SOM "TARGET_SOM" OFF)
+
+
+include_directories(app)
+add_subdirectory(app)
+
+# Ks the 'plant' of the regulatroy system
+# commented as long as 'MATLAB/extern/include' not avaliable
+# include_directories(ks)
+# add_subdirectory(ks)
+
+# add_subdirectory(config)
+
+enable_testing()
+add_subdirectory(tests)
diff --git a/Jenkinsfile b/Jenkinsfile
index 3275b5b..91749cc 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -10,7 +10,7 @@ pipeline {
stage('Clean-Jenkinsfile') {
steps {
//sh 'rm -rf build'
- echo "Building branch ${env.BRANCH_NAME}"
+ echo "Cleaning branch ${env.BRANCH_NAME}"
}
}
stage('Configure') {
diff --git a/Testing/Temporary/CTestCostData.txt b/Testing/Temporary/CTestCostData.txt
new file mode 100644
index 0000000..ed97d53
--- /dev/null
+++ b/Testing/Temporary/CTestCostData.txt
@@ -0,0 +1 @@
+---
diff --git a/Testing/Temporary/LastTest.log b/Testing/Temporary/LastTest.log
new file mode 100644
index 0000000..db26a29
--- /dev/null
+++ b/Testing/Temporary/LastTest.log
@@ -0,0 +1,3 @@
+Start testing: Mar 19 16:16 CET
+----------------------------------------------------------
+End testing: Mar 19 16:16 CET
diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt
new file mode 100644
index 0000000..15c8f84
--- /dev/null
+++ b/app/CMakeLists.txt
@@ -0,0 +1,29 @@
+
+
+
+qt_standard_project_setup()
+
+qt_add_executable(app main.cpp
+ )
+
+qt_add_library(app_lib STATIC
+ filter.h main.cpp filter.cpp
+ Controller.hpp main.cpp Controller.cpp
+ pwm.h pwm.cpp
+ climate-algorithm.h climate-algorithm.cpp
+ pid.h pid.cpp
+ datamodel.h datamodel.cpp
+ dataset.h dataset.cpp
+
+ text-templates.h
+
+ )
+
+target_include_directories(app_lib PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
+target_include_directories(app_lib PRIVATE ${Qt6Core_INCLUDE_DIRS})
+
+# add_executable(app main.cpp filter.cpp)
+target_link_libraries(app PRIVATE
+ app_lib
+ Qt::Core
+)
diff --git a/app/Controller.cpp b/app/Controller.cpp
new file mode 100644
index 0000000..7dad55e
--- /dev/null
+++ b/app/Controller.cpp
@@ -0,0 +1,224 @@
+#include "Controller.hpp"
+
+
+#ifdef BUILD_TARGET_SOM
+#include "application/AppLogic.hpp"
+#include "application/Environment.hpp"
+#include "application/EventLogger.hpp"
+#include "deviceConfig/model/DeviceConfiguration.hpp"
+#include "deviceConfig/model/state/GuardedAnalogConfiguration.hpp"
+#include "state/DeviceState.hpp"
+
+
+
+bool Controller::initialize(const char *configFilePath, appengine::IAppLogic *appLogic) {
+ appLogic_ = appLogic;
+ auto deviceState = appLogic->deviceState();
+
+
+
+
+ // Beispiel:
+ SV_Temperatur_Variable_ = deviceState.getVariableByKey("Temperatur_Innenraum");
+ SV_Feuchte_Variable_ = deviceState.getVariableByKey("Humidity");
+ SV_Tuer_Variable_ = deviceState.getVariableByKey("Temperatur_Tuer");
+ Wasserstand_Oben_Config_ = deviceState.getVariableByKey("Wasserstand_Hoch");
+ Wasserstand_Unten_Config_ = deviceState.getVariableByKey("Wasserstand_Tief");
+ Fuellstand_Config_ = deviceState.getVariableByKey("Fuellstand");
+ Heizung_Bef_Config_ = deviceState.getVariableByKey("Heizung_Bef");
+ MV_Kuehlung_Config_ = deviceState.getVariableByKey("MV_Kuehlung");
+ Abschlaemmen_Config_ = deviceState.getVariableByKey("Abschlaemmen");
+ Entleerpumpe_Config_ = deviceState.getVariableByKey("Entleerpumpe");
+ Heizung_Kesselrand_Config_ = deviceState.getVariableByKey("Heizung_Kesselrand");
+ Freigabe_Verfluessigerluefter_Config_ = deviceState.getVariableByKey("Freigabe_Verfluessigerluefter");
+ Heizung_Innenraum_Config_ = deviceState.getVariableByKey("Heizung_Innenraum");
+ Heizung_Tuer_Config_ = deviceState.getVariableByKey("Heizung_Tuer");
+ Uebertemperatur_Config_ = deviceState.getVariableByKey("Uebertemperatur");
+ MV_Entfeuchtung_Config_ = deviceState.getVariableByKey("MV_Entfeuchtung");
+ MV_Druckluft_Config_ = deviceState.getVariableByKey("MV_Druckluft");
+ Ansteuerung_Wassereinlass_Config_ = deviceState.getVariableByKey("Ansteuerung_Wassereinlass");
+ Ansteuerung_Verdichter_Config_ = deviceState.getVariableByKey("Ansteuerung_Verdichter");
+ Luefter_Innenraum_Config_ = deviceState.getVariableByKey("Luefter_Innenraum");
+ SV_Verdampferausgang_ = deviceState.getVariableByKey("Temperatur_Verdampferausgang");
+ SV_Befeuchtungsmodul_ = deviceState.getVariableByKey("Temperatur_Befeuchtungsmodul");
+ const_duty_cycle_ = deviceState.getVariableByKey("steady_duty");
+ const_freq_ = deviceState.getVariableByKey("steady_freq");
+ Verdichter_Duty_Config = deviceState.getVariableByKey("Ansteuerung_Verdichter_duty");
+ SV_Stellgrad_Heizung = deviceState.getVariableByKey("Stellgrad_Heizung");
+ SV_Stellgrad_Kuehlung = deviceState.getVariableByKey("Stellgrad_Kuehlung");
+ SV_Stellgrad_Befeuchtung = deviceState.getVariableByKey("Stellgrad_Befeuchtung");
+ SV_Stellgrad_Entfeuchtung = deviceState.getVariableByKey("Stellgrad_Entfeuchtung");
+ SV_Verdichter_on_ = deviceState.getVariableByKey("Verdichter_on");
+ Startup_ = deviceState.getVariableByKey("Startup_finished");
+ CounterTuer_ = deviceState.getVariableByKey("Counter_Tuer");
+
+ const_duty_cycle_ ->setValue(1000.0);
+ const_freq_->setValue(1000.0);
+
+ auto TempConfig = dynamic_cast(SV_Temperatur_Variable_->configuration());
+ auto FeuchteConfig = dynamic_cast(SV_Feuchte_Variable_->configuration());
+
+
+ auto Sollwert_Temp_Config = TempConfig.setPointConfiguration();
+ auto Sollwert_Feuchte_Config = FeuchteConfig.setPointConfiguration();
+ SV_Sollwert_Temperatur_ = deviceState.getVariableByKey(Sollwert_Temp_Config->name());
+ SV_Sollwert_Feuchte_ = deviceState.getVariableByKey(Sollwert_Feuchte_Config->name());
+
+
+
+
+
+
+// std::vector subscriptions_{};
+// std::shared_ptr Heizung_Bef_;
+// std::shared_ptr MV_Kuehlung_;
+// std::shared_ptr Abschlaemmen_;
+// std::shared_ptr Entleerpumpe_;
+// std::shared_ptr Heizung_Kesselrand;
+// std::shared_ptr Freigabe_Verfluessigerluefter;
+// std::shared_ptr Heizung_Innenraum;
+// std::shared_ptr Heizung_Tuer;
+// std::shared_ptr Uebertemperatur;
+// std::shared_ptr MV_Entfeuchtung;
+// std::shared_ptr MV_Druckluft;
+// std::shared_ptr Ansteuerung_Wassereinlass;
+// std::shared_ptr Wasserstand_oben_Config_;
+// std::shared_ptr Wasserstand_oben_Config_;
+// std::shared_ptr Ansteuerung_Verdichter;
+// std::shared_ptr Luefter_Innenraum;
+// std::shared_ptr heatingPower_Freq_;
+// std::vector subscriptions_{};
+// 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::shared_ptr SV_Tuer_Variable_;
+
+ // tempSetPointVariable_ = deviceState.getVariableByKey("Temperature_Setpoint");
+
+ // TODO: alle bool_inXX/real_inXX und bool_outXX/real_outXX/alarm_XX Variablen hier holen.
+// struct Inputs {
+// // 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{};
+
+// 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
+// };
+
+ //Initialize PT1 Filter
+
+ FILTERED_TEMP.initialize(0.25,1);
+ FILTER_TUER.initialize(0.25,1);
+ return true;
+}
+
+#endif
+
+
+
+void Controller::step() {
+#ifdef BUILD_TARGET_SOM
+ ClimateAlgorithm::Inputs in{};
+ in.Istwert_Temperatur = FILTERED_TEMP.step(SV_Temperatur_Variable_->toType());
+ in.Sollwert_Temperatur = SV_Sollwert_Temperatur_ ->toType();
+ in.Entleerbehaelter_Oben = Wasserstand_Oben_Config_->toType();
+ in.Entleerbehaelter_Unten = Wasserstand_Unten_Config_->toType();
+ in.Istwert_Feuchte = SV_Feuchte_Variable_->toType();
+ in.Sollwert_Feuchte = SV_Sollwert_Feuchte_->toType();
+ in.Istwert_Temperatur_Tuer = FILTER_TUER.step(SV_Tuer_Variable_->toType());
+ in.Betauungsschutz = 50.0;
+ in.Grenzwert_Untertemperatur = -80.0;
+ in.Feuchteband=10.0;
+ in.Istwert_Temperatur_Verdampferausgang = SV_Verdampferausgang_->toType();
+ in.Sollwert_Feuchte = SV_Sollwert_Feuchte_->toType();
+ in.Istwert_Ueberwachungsregler=in.Istwert_Temperatur;
+ in.Klasse_Ueberwachungsregler = 3.0;
+ in.reset_flag =false;
+ in.Sammelalarm = false;
+ in.Sollwert_Feuchte_aktiv = true;
+ in.Temperaturband = 5.0;
+ in.Temperatur_Feuchtemodul = SV_Befeuchtungsmodul_->toType();
+ in.Wasserkanister_leer = false;
+ in.Tuer_offen = false;
+
+
+ // TODO: reset_flag und bool_inXX lesen:
+ // in.reset_flag = deviceState.getVariableByKey("reset_flag")->toType();
+ // in.Sammelalarm_quittiert = ... bool_in01
+ // ...
+ // in.Istwert_Temperatur = real_in01
+ // ...
+
+ // Minimal-Beispiel (falls du erstmal nur Temperatur/Setpoint testest):
+ //in.Istwert_Temperatur = tempVariable_ ? tempVariable_->toType() : 0.0;
+ //in.Sollwert_Temperatur = tempSetPointVariable_ ? tempSetPointVariable_->toType() : 25.0;
+
+ auto out = algo_.step(in);
+
+ Heizung_Bef_Config_ -> setValue(out.bool_out17);
+ MV_Kuehlung_Config_ ->setValue(out.bool_out18);
+ Abschlaemmen_Config_->setValue(out.bool_out20);
+ Entleerpumpe_Config_->setValue(out.bool_out16);
+ Heizung_Kesselrand_Config_->setValue(out.bool_out12);
+ Freigabe_Verfluessigerluefter_Config_->setValue(out.bool_out13);
+ Heizung_Innenraum_Config_->setValue(out.bool_out09);
+ Heizung_Tuer_Config_->setValue(out.bool_out11);
+ Uebertemperatur_Config_->setValue(true);
+ MV_Entfeuchtung_Config_->setValue(out.bool_out19);
+ MV_Druckluft_Config_->setValue(false);
+
+ Ansteuerung_Wassereinlass_Config_->setValue(out.bool_out14);
+ //Ansteuerung_Verdichter_Config_->setValue(out.real_out21*20.0);
+ SV_Verdichter_on_->setValue(1);
+ Ansteuerung_Verdichter_Config_->setValue(static_cast (out.real_out21*10.0));
+ Verdichter_Duty_Config->setValue(500);
+
+ SV_Stellgrad_Heizung->setValue(out.Stellgrad_Heizung);
+ SV_Stellgrad_Kuehlung->setValue(out.Stellgrad_Kuehlung);
+ SV_Stellgrad_Befeuchtung ->setValue(out.Stellgrad_Befeuchtung);
+ SV_Stellgrad_Entfeuchtung->setValue(out.Stellgrad_Entfeuchtung);
+ Startup_->setValue(out.Startup);
+ CounterTuer_->setValue(out.Counter_Tuer);
+
+ // TODO: bool_outXX / real_outXX / alarm_XX setzen:
+ // deviceState.getVariableByKey("bool_out01")->set(out.bool_out01);
+ // deviceState.getVariableByKey("real_out09")->set(out.real_out09);
+#endif
+}
+
+void Controller::terminate() {
+#ifdef BUILD_TARGET_SOM
+ subscriptions_.clear();
+#endif
+}
+
+#ifdef BUILD_TARGET_SOM
+ControllerBase *create() {
+
+ return new Controller;
+}
+#endif
diff --git a/app/Controller.hpp b/app/Controller.hpp
new file mode 100644
index 0000000..e1ac976
--- /dev/null
+++ b/app/Controller.hpp
@@ -0,0 +1,2530 @@
+#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/app/climate-algorithm.cpp b/app/climate-algorithm.cpp
new file mode 100644
index 0000000..516ef5c
--- /dev/null
+++ b/app/climate-algorithm.cpp
@@ -0,0 +1 @@
+// todo: create, import file header
\ No newline at end of file
diff --git a/app/climate-algorithm.h b/app/climate-algorithm.h
new file mode 100644
index 0000000..be15a5c
--- /dev/null
+++ b/app/climate-algorithm.h
@@ -0,0 +1,22 @@
+// todo: create, import file header
+
+#ifndef CLIMATE_ALGORITHM_H
+#define CLIMATE_ALGORITHM_H
+#include
+#include
+
+//todo - install
+// #include
+
+#include "filter.h"
+#include "pwm.hpp"
+#include "pid.h"
+
+
+class ClimateAlgorithm {
+public:
+private:
+
+}
+
+#endif // CLIMATE_ALGORITHM_H
diff --git a/app/datamodel.cpp b/app/datamodel.cpp
new file mode 100644
index 0000000..c9abb23
--- /dev/null
+++ b/app/datamodel.cpp
@@ -0,0 +1,29 @@
+
+/*
+File: datamodel.cpp
+Description: This is a C++ source file containing implementation code for a data collection (called model) used for
+ the realisation of a climate chamber control algorithm
+Rev: 0.1 - draft
+Created: 20.03.26
+Author: Uwe Jakobeit
+Copyright: Binder GmbH TUT
+Purpose: Configuration data and run-time datasets are provided for a controller simulation
+
+Notes: [Any relevant details, such as dependencies, usage examples, or known issues.]
+*/
+
+#include "datamodel.h"
+
+DataModel::DataModel()
+{
+
+ // uj todo - set defaults, if JSON input fails
+ // for now only hard-coded data
+ Kennfeld_Ueberhitzung = Kennfeld_Ueberhitzung_Default;
+ // In English:
+ HeadlineOverheat = HeadlineOverheatDefault;
+
+ Kennfeld_Entfeuchtung = Kennfeld_Entfeuchtung_Default;
+
+ Kennfeld_Ueberhitzung = Kennfeld_Ueberhitzung_Default;
+}
\ No newline at end of file
diff --git a/app/datamodel.h b/app/datamodel.h
new file mode 100644
index 0000000..3de8c40
--- /dev/null
+++ b/app/datamodel.h
@@ -0,0 +1,64 @@
+#ifndef DATAMODEL_H
+#define DATAMODEL_H
+
+#include "dataset.h"
+
+
+#define HeadlineOverheat Kennfeld_Ueberhitzung
+#define HeadlineOverheatDefault Kennfeld_Ueberhitzung_Default
+
+
+class DataModel{
+public:
+ DataModel();
+
+private:
+ QList> Kennfeld_Ueberhitzung;
+ QList> Kennfeld_Entfeuchtung;
+ QList> Kennfeld_Regler_Heizung_Xp;
+
+ QList> Kennfeld_Ueberhitzung_Default = {
+ {-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}, // 0: Temperatur
+ {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}, // 1: Skalierung Min
+ {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}, // 1: Skalierung Max
+ {-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} // 3: Sollwert Überhitzung
+ };
+
+ QList> Kennfeld_Entfeuchtung_Default{
+ { -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}, // 0: Temperatur
+ { 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}, // 1: Skalierung Entfeuchtung
+ { 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}, // 2: Abtauzyklus Pause
+ { 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} // 3: Abtauzyklus Dauer
+ };
+
+ QList Kennfeld_Regler_Heizung_Xp_Default{
+ 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};
+
+ QList 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};
+
+ QList> Kennfeld_Regler_Befeuchtung_Xp{
+ {1.00, 0.54, 0.31, 0.18, 0.11, 0.07, 0.05, 0.03, 0.02},
+ {1.00, 0.54, 0.31, 0.18, 0.11, 0.07, 0.05, 0.03, 0.02},
+ {1.00, 0.54, 0.31, 0.18, 0.11, 0.07, 0.05, 0.03, 0.02},
+ {1.00, 0.54, 0.31, 0.18, 0.11, 0.07, 0.05, 0.03, 0.02},
+ {1.00, 0.54, 0.31, 0.18, 0.11, 0.07, 0.05, 0.03, 0.02},
+ {1.00, 0.54, 0.31, 0.18, 0.11, 0.07, 0.05, 0.03, 0.02},
+ {1.00, 0.54, 0.31, 0.18, 0.11, 0.07, 0.05, 0.03, 0.02},
+ {1.00, 0.54, 0.31, 0.18, 0.11, 0.07, 0.05, 0.03, 0.02},
+ {1.00, 0.54, 0.31, 0.18, 0.11, 0.07, 0.05, 0.03, 0.02}};
+
+ QList> Kennfeld_Regler_Entfeuchtung_Xp{
+ {1.00, 0.80, 0.60, 0.50, 0.40, 0.35, 0.30, 0.25, 0.20},
+ {1.00, 0.80, 0.60, 0.50, 0.40, 0.35, 0.30, 0.25, 0.20},
+ {1.00, 0.80, 0.60, 0.50, 0.40, 0.35, 0.30, 0.25, 0.20},
+ {1.00, 0.80, 0.60, 0.50, 0.40, 0.35, 0.30, 0.25, 0.20},
+ {1.00, 0.80, 0.60, 0.50, 0.40, 0.35, 0.30, 0.25, 0.20},
+ {1.00, 0.80, 0.60, 0.50, 0.40, 0.35, 0.30, 0.25, 0.20},
+ {1.00, 0.80, 0.60, 0.50, 0.40, 0.35, 0.30, 0.25, 0.20},
+ {1.00, 0.80, 0.60, 0.50, 0.40, 0.35, 0.30, 0.25, 0.20},
+ {1.00, 0.80, 0.60, 0.50, 0.40, 0.35, 0.30, 0.25, 0.20}};
+};
+
+
+#endif // DATAMODEL_H
diff --git a/app/dataset.cpp b/app/dataset.cpp
new file mode 100644
index 0000000..d1ac897
--- /dev/null
+++ b/app/dataset.cpp
@@ -0,0 +1,60 @@
+/*
+File: dataset.cpp
+Description: This is a C++ source file containing implementation code handling configuration data
+Rev: 0.1
+Created: 20.03.2026
+Author: Uwe Jakobeit
+Copyright: Binder GmbH, TUT 2026
+Purpose: [Briefly describe the file's functionality, e.g., "Implements a class for managing user data."]
+ Implementation of classes which provide changes of dataset without (re-)comiling
+Notes: [Any relevant details, such as dependencies, usage examples, or known issues.]
+*/
+
+
+#include "dataset.h"
+
+
+using namespace std;
+
+// Read config file and setup headlines ( characteristics )
+Dataset::Dataset(QString& configFile)
+{
+ // headline << &mHeadLineTemperature
+ // << &mHeadLineHumidity
+ // << &mHeadLineOverheat;
+
+
+ // Now you can create a QVector of pointers to QVectorBase
+ QVector mixedVectors;
+
+// QVector mHeadlineVector;
+
+
+
+
+ // Usage
+ QVector intVec = {1, 2, 3};
+ QVector dblVec = {1.0, 2, 3};
+
+ QVector stringVec = {"hello", "world"};
+
+ mixedVectors.append(new QVectorWrapper(intVec));
+ mixedVectors.append(new QVectorWrapper(stringVec));
+
+ mHeadlineVector.append(new QVectorWrapper(intVec));
+ mHeadlineVector.append(new QVectorWrapper(stringVec));
+
+ // Iterate and use polymorphic behavior
+ for (QVectorBase* vec : mixedVectors) {
+ vec->print();
+ }
+ // // Clean up
+ // qDeleteAll(mixedVectors);
+ // mixedVectors.clear();
+}
+
+QVectorBase* Dataset::HeadLine(uint8_t LineId)
+{
+
+ return mHeadlineVector.at(LineId);
+}
diff --git a/app/dataset.h b/app/dataset.h
new file mode 100644
index 0000000..b3822fe
--- /dev/null
+++ b/app/dataset.h
@@ -0,0 +1,69 @@
+// #include
+// #include
+// #include
+#include
+#include
+
+using namespace std;
+enum class LineId {
+ Temperature,
+ Humidity,
+ OverHeat
+};
+
+
+#if 0
+class Dataset{
+
+public:
+ Dataset(QString& configFile);
+
+ // return headlines (Kennlinien) of known types from ST code
+ QVector* HeadLine(enum class LineId);
+private:
+
+ // Class members (m_, but don't like the '_' )
+ vector headline;
+
+ vector mHeadLineTemperature;
+ vector mHeadLineOverheat;
+ vector mHeadLineHumidity;
+};
+
+#endif
+
+#include
+#include
+
+
+
+
+// Forward declaration of a base class for polymorphic behavior
+class QVectorBase {
+public:
+ virtual ~QVectorBase() = default;
+ virtual void print() const = 0;
+};
+
+// Template class to wrap a QVector and inherit from QVectorBase
+template
+class QVectorWrapper : public QVectorBase {
+public:
+ QVector vec;
+
+ QVectorWrapper() = default;
+ explicit QVectorWrapper(const QVector& v) : vec(v) {}
+
+ void print() const override {
+ qDebug() << "Vector of" << sizeof(T) << "bytes:" << vec;
+ }
+};
+
+class Dataset{
+ public:
+ Dataset(QString& configFile);
+ QVectorBase *HeadLine(uint8_t LineId);
+
+ private:
+ QVector mHeadlineVector;
+};
\ No newline at end of file
diff --git a/app/filter.cpp b/app/filter.cpp
new file mode 100644
index 0000000..b1bbf3f
--- /dev/null
+++ b/app/filter.cpp
@@ -0,0 +1,20 @@
+#include "filter.h"
+
+PT1Filter::PT1Filter(double tau, double dt) : output(0.0) {
+ filterFactor = dt / (tau + dt);
+}
+
+double PT1Filter::update(double input) {
+ output += filterFactor * (input - output);
+ return output;
+}
+
+double PT1Filter::step(double input) {
+ output += filterFactor * (input - output);
+ return output;
+};
+
+
+void PT1Filter::reset() {
+ output = 0.0;
+}
\ No newline at end of file
diff --git a/app/filter.h b/app/filter.h
new file mode 100644
index 0000000..0b221d4
--- /dev/null
+++ b/app/filter.h
@@ -0,0 +1,20 @@
+#ifndef FILTER_H
+#define FILTER_H
+
+#pragma once
+
+class PT1Filter {
+private:
+ double output;
+ double filterFactor;
+
+public:
+ PT1Filter(double tau, double dt);
+ double update(double input);
+ double step(double input);
+ void reset();
+};
+
+
+
+#endif // FILTER_H
diff --git a/app/main.cpp b/app/main.cpp
new file mode 100644
index 0000000..55bdef2
--- /dev/null
+++ b/app/main.cpp
@@ -0,0 +1,30 @@
+#include
+#include
+
+#include "Controller.hpp"
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication a(argc, argv);
+
+ // Set up code that uses the Qt event loop here.
+ // Call QCoreApplication::quit() or QCoreApplication::exit() to quit the application.
+ // A not very useful example would be including
+ // #include
+ // near the top of the file and calling
+ // QTimer::singleShot(5000, &a, &QCoreApplication::quit);
+ // which quits the application after 5 seconds.
+
+ // If you do not need a running Qt event loop, remove the call
+ // to QCoreApplication::exec() or use the Non-Qt Plain C++ Application template.
+
+ Controller bbr;
+
+
+ qDebug() << "Perform one bbr setp";
+ bbr.step();
+
+ return 0;
+
+ // return QCoreApplication::exec();
+}
diff --git a/app/pid.cpp b/app/pid.cpp
new file mode 100644
index 0000000..5d71a58
--- /dev/null
+++ b/app/pid.cpp
@@ -0,0 +1,9 @@
+// todo: create, import file header
+
+#include "pid.h"
+
+PID::PID()
+{
+
+}
+
diff --git a/app/pid.h b/app/pid.h
new file mode 100644
index 0000000..b17daff
--- /dev/null
+++ b/app/pid.h
@@ -0,0 +1,12 @@
+#ifndef PWM_H
+#define PWM_H
+
+class PID{
+public:
+ PID();
+
+private:
+
+};
+
+#endif //PWM_H
diff --git a/app/pwm.cpp b/app/pwm.cpp
new file mode 100644
index 0000000..10fcb82
--- /dev/null
+++ b/app/pwm.cpp
@@ -0,0 +1,18 @@
+// todo: create, import file header
+
+#include "pwm.h"
+
+PWM::PWM(double cycleTime_Min,double cycleTime_Max)
+{
+ m_cycle = 0.0;
+ m_out = 0.0;
+ m_cycleTime = 0.0;
+ m_cycleTime_Min = cycleTime_Min;
+ m_cycleTime_Max = cycleTime_Max;
+}
+
+bool PWM::step(double setValue,double samplingTime)
+{
+ bool output_bool;
+ return output_bool;
+}
diff --git a/app/pwm.h b/app/pwm.h
new file mode 100644
index 0000000..665f013
--- /dev/null
+++ b/app/pwm.h
@@ -0,0 +1,20 @@
+#ifndef PWM_H
+#define PWM_H
+
+#include
+
+class PWM
+{
+public:
+ PWM(double cycleTime_Min,double cycleTime_Max);
+
+ bool step(double setValue,double samplingTime);
+
+private:
+ double m_cycle = 0.0;
+ double m_out = 0.0;
+ double m_cycleTime = 0.0;
+ double m_cycleTime_Min = 0.0;
+ double m_cycleTime_Max = 0.0;
+};
+#endif // PWM_H
diff --git a/app/text-templates.h b/app/text-templates.h
new file mode 100644
index 0000000..4d1fffc
--- /dev/null
+++ b/app/text-templates.h
@@ -0,0 +1,19 @@
+// CPP Source file header ( as well h-file header, so far (20.03.26)
+
+/*
+File: filename.cpp
+Description: This is a C++ source file containing implementation code for a program or library component.
+Rev: 0.1
+Created: [Date]
+Author: [Your Name]
+Copyright: [Your Organization or Name] [Year(s)]
+Purpose: [Briefly describe the file's functionality, e.g., "Implements a class for managing user data."]
+Notes: [Any relevant details, such as dependencies, usage examples, or known issues.]
+*/
+
+
+// CPP Source function header
+// todo
+
+// Header file function header
+// todo
\ No newline at end of file
diff --git a/config/CMakeLists.txt b/config/CMakeLists.txt
new file mode 100644
index 0000000..f2f450e
--- /dev/null
+++ b/config/CMakeLists.txt
@@ -0,0 +1,38 @@
+
+if(0)
+
+# qt_standard_project_setup()
+
+# qt_add_executable(app main.cpp
+# )
+
+add_library(config_lib STATIC dataset.h dataset.cpp
+ )
+
+target_include_directories(config_lib PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
+target_include_directories(config_lib PRIVATE ${Qt6Core_INCLUDE_DIRS})
+
+# add_executable(app main.cpp filter.cpp)
+target_link_libraries(app PRIVATE config_lib
+)
+endif()
+
+
+qt_standard_project_setup()
+
+qt_add_executable(app main.cpp
+ )
+
+qt_add_library(config_lib STATIC dataset.h dataset.cpp
+)
+
+
+target_include_directories(config_lib PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
+target_include_directories(config_lib PRIVATE ${Qt6Core_INCLUDE_DIRS})
+
+# add_executable(app main.cpp filter.cpp)
+target_link_libraries(app PRIVATE
+ config_lib
+ Qt::Core
+)
+
diff --git a/ks/CMakeLists.txt b/ks/CMakeLists.txt
new file mode 100644
index 0000000..33b6305
--- /dev/null
+++ b/ks/CMakeLists.txt
@@ -0,0 +1,25 @@
+cmake_minimum_required(VERSION 3.28)
+project(ks_lib LANGUAGES CXX)
+
+qt_standard_project_setup()
+
+file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
+file(GLOB_RECURSE HEADERS CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/*.hpp")
+
+
+# qt_add_executable(ks main.cpp
+# )
+
+qt_add_library(${PROJECT_NAME} STATIC main.cpp
+ ${SOURCES}
+ ${HEADERS}
+ )
+
+target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/Models/FP56/Model_grt_rtw)
+target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
+target_include_directories(${PROJECT_NAME} PRIVATE ${Qt6Core_INCLUDE_DIRS})
+
+# add_executable(app main.cpp filter.cpp)
+target_link_libraries(${PROJECT_NAME} PRIVATE
+ Qt::Core
+)
diff --git a/ks/Models/FP56/Model.slx b/ks/Models/FP56/Model.slx
new file mode 100755
index 0000000..c0ee925
Binary files /dev/null and b/ks/Models/FP56/Model.slx differ
diff --git a/ks/Models/FP56/Model.slx.autosave b/ks/Models/FP56/Model.slx.autosave
new file mode 100755
index 0000000..f276a21
Binary files /dev/null and b/ks/Models/FP56/Model.slx.autosave differ
diff --git a/ks/Models/FP56/Model.slxc b/ks/Models/FP56/Model.slxc
new file mode 100755
index 0000000..705fb52
Binary files /dev/null and b/ks/Models/FP56/Model.slxc differ
diff --git a/ks/Models/FP56/Model_grt_rtw/Model.bat b/ks/Models/FP56/Model_grt_rtw/Model.bat
new file mode 100755
index 0000000..5d341b8
--- /dev/null
+++ b/ks/Models/FP56/Model_grt_rtw/Model.bat
@@ -0,0 +1,16 @@
+
+set skipSetupArg=%2
+if "%skipSetupArg%" NEQ "skip_setup_msvc" (
+call "setup_msvc.bat"
+)
+
+cd .
+
+if "%1"=="" (nmake -f Model.mk all) else (nmake -f Model.mk %1)
+@if errorlevel 1 goto error_exit
+
+exit /B 0
+
+:error_exit
+echo The make command returned an error of %errorlevel%
+exit /B 1
\ No newline at end of file
diff --git a/ks/Models/FP56/Model_grt_rtw/Model.cpp b/ks/Models/FP56/Model_grt_rtw/Model.cpp
new file mode 100755
index 0000000..c72bf89
--- /dev/null
+++ b/ks/Models/FP56/Model_grt_rtw/Model.cpp
@@ -0,0 +1,358 @@
+/*
+ * Model.cpp
+ *
+ * Code generation for model "Model".
+ *
+ * Model version : 1.2
+ * Simulink Coder version : 9.7 (R2022a) 13-Nov-2021
+ * C++ source code generated on : Sat Mar 28 11:28:04 2026
+ *
+ * Target selection: grt.tlc
+ * Note: GRT includes extra infrastructure and instrumentation for prototyping
+ * Embedded hardware selection: Intel->x86-64 (Windows64)
+ * Code generation objectives: Unspecified
+ * Validation result: Not run
+ */
+
+#include "Model.h"
+#include "rtwtypes.h"
+#include "Model_private.h"
+
+extern "C" {
+
+#include "rt_nonfinite.h"
+
+}
+/*
+ * This function updates continuous states using the ODE3 fixed-step
+ * solver algorithm
+ */
+ void Model::rt_ertODEUpdateContinuousStates(RTWSolverInfo *si )
+{
+ /* Solver Matrices */
+ static const real_T rt_ODE3_A[3]{
+ 1.0/2.0, 3.0/4.0, 1.0
+ };
+
+ static const real_T rt_ODE3_B[3][3]{
+ { 1.0/2.0, 0.0, 0.0 },
+
+ { 0.0, 3.0/4.0, 0.0 },
+
+ { 2.0/9.0, 1.0/3.0, 4.0/9.0 }
+ };
+
+ time_T t { rtsiGetT(si) };
+
+ time_T tnew { rtsiGetSolverStopTime(si) };
+
+ time_T h { rtsiGetStepSize(si) };
+
+ real_T *x { rtsiGetContStates(si) };
+
+ ODE3_IntgData *id { static_cast(rtsiGetSolverData(si)) };
+
+ real_T *y { id->y };
+
+ real_T *f0 { id->f[0] };
+
+ real_T *f1 { id->f[1] };
+
+ real_T *f2 { id->f[2] };
+
+ real_T hB[3];
+ int_T i;
+ int_T nXc { 3 };
+
+ rtsiSetSimTimeStep(si,MINOR_TIME_STEP);
+
+ /* Save the state values at time t in y, we'll use x as ynew. */
+ (void) std::memcpy(y, x,
+ static_cast(nXc)*sizeof(real_T));
+
+ /* Assumes that rtsiSetT and ModelOutputs are up-to-date */
+ /* f0 = f(t,y) */
+ rtsiSetdX(si, f0);
+ Model_derivatives();
+
+ /* f(:,2) = feval(odefile, t + hA(1), y + f*hB(:,1), args(:)(*)); */
+ hB[0] = h * rt_ODE3_B[0][0];
+ for (i = 0; i < nXc; i++) {
+ x[i] = y[i] + (f0[i]*hB[0]);
+ }
+
+ rtsiSetT(si, t + h*rt_ODE3_A[0]);
+ rtsiSetdX(si, f1);
+ this->step();
+ Model_derivatives();
+
+ /* f(:,3) = feval(odefile, t + hA(2), y + f*hB(:,2), args(:)(*)); */
+ for (i = 0; i <= 1; i++) {
+ hB[i] = h * rt_ODE3_B[1][i];
+ }
+
+ for (i = 0; i < nXc; i++) {
+ x[i] = y[i] + (f0[i]*hB[0] + f1[i]*hB[1]);
+ }
+
+ rtsiSetT(si, t + h*rt_ODE3_A[1]);
+ rtsiSetdX(si, f2);
+ this->step();
+ Model_derivatives();
+
+ /* tnew = t + hA(3);
+ ynew = y + f*hB(:,3); */
+ for (i = 0; i <= 2; i++) {
+ hB[i] = h * rt_ODE3_B[2][i];
+ }
+
+ for (i = 0; i < nXc; i++) {
+ x[i] = y[i] + (f0[i]*hB[0] + f1[i]*hB[1] + f2[i]*hB[2]);
+ }
+
+ rtsiSetT(si, tnew);
+ rtsiSetSimTimeStep(si,MAJOR_TIME_STEP);
+}
+
+/* Model step function */
+void Model::step()
+{
+ real_T rtb_Gain1;
+ real_T rtb_Gain4;
+ if (rtmIsMajorTimeStep((&Model_M))) {
+ /* set solver stop time */
+ if (!((&Model_M)->Timing.clockTick0+1)) {
+ rtsiSetSolverStopTime(&(&Model_M)->solverInfo, (((&Model_M)
+ ->Timing.clockTickH0 + 1) * (&Model_M)->Timing.stepSize0 * 4294967296.0));
+ } else {
+ rtsiSetSolverStopTime(&(&Model_M)->solverInfo, (((&Model_M)
+ ->Timing.clockTick0 + 1) * (&Model_M)->Timing.stepSize0 + (&Model_M)
+ ->Timing.clockTickH0 * (&Model_M)->Timing.stepSize0 * 4294967296.0));
+ }
+ } /* end MajorTimeStep */
+
+ /* Update absolute time of base rate at minor time step */
+ if (rtmIsMinorTimeStep((&Model_M))) {
+ (&Model_M)->Timing.t[0] = rtsiGetT(&(&Model_M)->solverInfo);
+ }
+
+ /* Outport: '/Temperatur' incorporates:
+ * Integrator: '/Integrator1'
+ */
+ Model_Y.Temperatur = Model_X.Integrator1_CSTATE;
+
+ /* Gain: '/Gain1' incorporates:
+ * Integrator: '/Integrator'
+ * Integrator: '/Integrator1'
+ * Sum: '/Plus1'
+ */
+ rtb_Gain1 = Model_P.alphaHD * Model_P.AHD * (Model_X.Integrator_CSTATE -
+ Model_X.Integrator1_CSTATE);
+
+ /* Gain: '/Gain' incorporates:
+ * Inport: '/Stellgrad'
+ * Sum: '/Plus'
+ */
+ Model_B.Gain = 1.0 / (Model_P.mHD * Model_P.CHD) * (Model_U.Stellgrad -
+ rtb_Gain1);
+
+ /* Gain: '/Gain4' incorporates:
+ * Integrator: '/Integrator1'
+ * Integrator: '/Integrator2'
+ * Sum: '/Plus4'
+ */
+ rtb_Gain4 = Model_P.alphaSW * Model_P.Ai * (Model_X.Integrator1_CSTATE -
+ Model_X.Integrator2_CSTATE);
+
+ /* Gain: '/Gain2' incorporates:
+ * Sum: '/Plus2'
+ */
+ Model_B.Gain2 = 1.0 / (Model_P.ml * Model_P.Cl + Model_P.mES * Model_P.CES) *
+ (rtb_Gain1 - rtb_Gain4);
+
+ /* Gain: '/Gain5' incorporates:
+ * Constant: '/Constant'
+ * Gain: '/Gain7'
+ * Integrator: '/Integrator2'
+ * Sum: '/Plus5'
+ * Sum: '/Plus7'
+ */
+ Model_B.Gain5 = (rtb_Gain4 - Model_P.alpha_aussen * Model_P.A_Aussen *
+ (Model_X.Integrator2_CSTATE - Model_P.Constant_Value)) * (1.0
+ / (Model_P.mSW * Model_P.CSW));
+ if (rtmIsMajorTimeStep((&Model_M))) {
+ /* Matfile logging */
+ rt_UpdateTXYLogVars((&Model_M)->rtwLogInfo, ((&Model_M)->Timing.t));
+ } /* end MajorTimeStep */
+
+ if (rtmIsMajorTimeStep((&Model_M))) {
+ /* signal main to stop simulation */
+ { /* Sample time: [0.0s, 0.0s] */
+ if ((rtmGetTFinal((&Model_M))!=-1) &&
+ !((rtmGetTFinal((&Model_M))-((((&Model_M)->Timing.clockTick1+(&Model_M)
+ ->Timing.clockTickH1* 4294967296.0)) * 0.05)) > ((((&Model_M)
+ ->Timing.clockTick1+(&Model_M)->Timing.clockTickH1* 4294967296.0))
+ * 0.05) * (DBL_EPSILON))) {
+ rtmSetErrorStatus((&Model_M), "Simulation finished");
+ }
+ }
+
+ rt_ertODEUpdateContinuousStates(&(&Model_M)->solverInfo);
+
+ /* Update absolute time for base rate */
+ /* The "clockTick0" counts the number of times the code of this task has
+ * been executed. The absolute time is the multiplication of "clockTick0"
+ * and "Timing.stepSize0". Size of "clockTick0" ensures timer will not
+ * overflow during the application lifespan selected.
+ * Timer of this task consists of two 32 bit unsigned integers.
+ * The two integers represent the low bits Timing.clockTick0 and the high bits
+ * Timing.clockTickH0. When the low bit overflows to 0, the high bits increment.
+ */
+ if (!(++(&Model_M)->Timing.clockTick0)) {
+ ++(&Model_M)->Timing.clockTickH0;
+ }
+
+ (&Model_M)->Timing.t[0] = rtsiGetSolverStopTime(&(&Model_M)->solverInfo);
+
+ {
+ /* Update absolute timer for sample time: [0.05s, 0.0s] */
+ /* The "clockTick1" counts the number of times the code of this task has
+ * been executed. The resolution of this integer timer is 0.05, which is the step size
+ * of the task. Size of "clockTick1" ensures timer will not overflow during the
+ * application lifespan selected.
+ * Timer of this task consists of two 32 bit unsigned integers.
+ * The two integers represent the low bits Timing.clockTick1 and the high bits
+ * Timing.clockTickH1. When the low bit overflows to 0, the high bits increment.
+ */
+ (&Model_M)->Timing.clockTick1++;
+ if (!(&Model_M)->Timing.clockTick1) {
+ (&Model_M)->Timing.clockTickH1++;
+ }
+ }
+ } /* end MajorTimeStep */
+}
+
+/* Derivatives for root system: '' */
+void Model::Model_derivatives()
+{
+ XDot_Model_T *_rtXdot;
+ _rtXdot = ((XDot_Model_T *) (&Model_M)->derivs);
+
+ /* Derivatives for Integrator: '/Integrator1' */
+ _rtXdot->Integrator1_CSTATE = Model_B.Gain2;
+
+ /* Derivatives for Integrator: '/Integrator' */
+ _rtXdot->Integrator_CSTATE = Model_B.Gain;
+
+ /* Derivatives for Integrator: '/Integrator2' */
+ _rtXdot->Integrator2_CSTATE = Model_B.Gain5;
+}
+
+/* Model initialize function */
+void Model::initialize()
+{
+ /* Registration code */
+
+ /* initialize non-finites */
+ rt_InitInfAndNaN(sizeof(real_T));
+
+ {
+ /* Setup solver object */
+ rtsiSetSimTimeStepPtr(&(&Model_M)->solverInfo, &(&Model_M)
+ ->Timing.simTimeStep);
+ rtsiSetTPtr(&(&Model_M)->solverInfo, &rtmGetTPtr((&Model_M)));
+ rtsiSetStepSizePtr(&(&Model_M)->solverInfo, &(&Model_M)->Timing.stepSize0);
+ rtsiSetdXPtr(&(&Model_M)->solverInfo, &(&Model_M)->derivs);
+ rtsiSetContStatesPtr(&(&Model_M)->solverInfo, (real_T **) &(&Model_M)
+ ->contStates);
+ rtsiSetNumContStatesPtr(&(&Model_M)->solverInfo, &(&Model_M)
+ ->Sizes.numContStates);
+ rtsiSetNumPeriodicContStatesPtr(&(&Model_M)->solverInfo, &(&Model_M)
+ ->Sizes.numPeriodicContStates);
+ rtsiSetPeriodicContStateIndicesPtr(&(&Model_M)->solverInfo, &(&Model_M)
+ ->periodicContStateIndices);
+ rtsiSetPeriodicContStateRangesPtr(&(&Model_M)->solverInfo, &(&Model_M)
+ ->periodicContStateRanges);
+ rtsiSetErrorStatusPtr(&(&Model_M)->solverInfo, (&rtmGetErrorStatus((&Model_M))));
+ rtsiSetRTModelPtr(&(&Model_M)->solverInfo, (&Model_M));
+ }
+
+ rtsiSetSimTimeStep(&(&Model_M)->solverInfo, MAJOR_TIME_STEP);
+ (&Model_M)->intgData.y = (&Model_M)->odeY;
+ (&Model_M)->intgData.f[0] = (&Model_M)->odeF[0];
+ (&Model_M)->intgData.f[1] = (&Model_M)->odeF[1];
+ (&Model_M)->intgData.f[2] = (&Model_M)->odeF[2];
+ (&Model_M)->contStates = ((X_Model_T *) &Model_X);
+ rtsiSetSolverData(&(&Model_M)->solverInfo, static_cast(&(&Model_M)
+ ->intgData));
+ rtsiSetIsMinorTimeStepWithModeChange(&(&Model_M)->solverInfo, false);
+ rtsiSetSolverName(&(&Model_M)->solverInfo,"ode3");
+ rtmSetTPtr((&Model_M), &(&Model_M)->Timing.tArray[0]);
+ rtmSetTFinal((&Model_M), 10.0);
+ (&Model_M)->Timing.stepSize0 = 0.05;
+
+ /* Setup for data logging */
+ {
+ static RTWLogInfo rt_DataLoggingInfo;
+ rt_DataLoggingInfo.loggingInterval = (nullptr);
+ (&Model_M)->rtwLogInfo = &rt_DataLoggingInfo;
+ }
+
+ /* Setup for data logging */
+ {
+ rtliSetLogXSignalInfo((&Model_M)->rtwLogInfo, (nullptr));
+ rtliSetLogXSignalPtrs((&Model_M)->rtwLogInfo, (nullptr));
+ rtliSetLogT((&Model_M)->rtwLogInfo, "tout");
+ rtliSetLogX((&Model_M)->rtwLogInfo, "");
+ rtliSetLogXFinal((&Model_M)->rtwLogInfo, "");
+ rtliSetLogVarNameModifier((&Model_M)->rtwLogInfo, "rt_");
+ rtliSetLogFormat((&Model_M)->rtwLogInfo, 4);
+ rtliSetLogMaxRows((&Model_M)->rtwLogInfo, 0);
+ rtliSetLogDecimation((&Model_M)->rtwLogInfo, 1);
+ rtliSetLogY((&Model_M)->rtwLogInfo, "");
+ rtliSetLogYSignalInfo((&Model_M)->rtwLogInfo, (nullptr));
+ rtliSetLogYSignalPtrs((&Model_M)->rtwLogInfo, (nullptr));
+ }
+
+ /* Matfile logging */
+ rt_StartDataLoggingWithStartTime((&Model_M)->rtwLogInfo, 0.0, rtmGetTFinal
+ ((&Model_M)), (&Model_M)->Timing.stepSize0, (&rtmGetErrorStatus((&Model_M))));
+
+ /* InitializeConditions for Integrator: '/Integrator1' */
+ Model_X.Integrator1_CSTATE = Model_P.T_amb;
+
+ /* InitializeConditions for Integrator: '/Integrator' */
+ Model_X.Integrator_CSTATE = Model_P.T_amb;
+
+ /* InitializeConditions for Integrator: '/Integrator2' */
+ Model_X.Integrator2_CSTATE = Model_P.T_amb;
+}
+
+/* Model terminate function */
+void Model::terminate()
+{
+ /* (no terminate code required) */
+}
+
+/* Constructor */
+Model::Model() :
+ Model_U(),
+ Model_Y(),
+ Model_B(),
+ Model_X(),
+ Model_M()
+{
+ /* Currently there is no constructor body generated.*/
+}
+
+/* Destructor */
+Model::~Model()
+{
+ /* Currently there is no destructor body generated.*/
+}
+
+/* Real-Time Model get method */
+RT_MODEL_Model_T * Model::getRTM()
+{
+ return (&Model_M);
+}
diff --git a/ks/Models/FP56/Model_grt_rtw/Model.h b/ks/Models/FP56/Model_grt_rtw/Model.h
new file mode 100644
index 0000000..f49784c
--- /dev/null
+++ b/ks/Models/FP56/Model_grt_rtw/Model.h
@@ -0,0 +1,408 @@
+/*
+ * Model.h
+ *
+ * Code generation for model "Model".
+ *
+ * Model version : 1.1
+ * Simulink Coder version : 9.7 (R2022a) 13-Nov-2021
+ * C++ source code generated on : Thu Mar 26 17:54:04 2026
+ *
+ * Target selection: grt.tlc
+ * Note: GRT includes extra infrastructure and instrumentation for prototyping
+ * Embedded hardware selection: Intel->x86-64 (Windows64)
+ * Code generation objectives: Unspecified
+ * Validation result: Not run
+ */
+
+#ifndef RTW_HEADER_Model_h_
+#define RTW_HEADER_Model_h_
+#include "rtwtypes.h"
+#include "rtw_continuous.h"
+#include "rtw_solver.h"
+#include "rt_logging.h"
+#include "Model_types.h"
+#include
+#include
+
+extern "C" {
+
+#include "rt_nonfinite.h"
+
+}
+/* Macros for accessing real-time model data structure */
+#ifndef rtmGetContStateDisabled
+#define rtmGetContStateDisabled(rtm) ((rtm)->contStateDisabled)
+#endif
+
+#ifndef rtmSetContStateDisabled
+#define rtmSetContStateDisabled(rtm, val) ((rtm)->contStateDisabled = (val))
+#endif
+
+#ifndef rtmGetContStates
+#define rtmGetContStates(rtm) ((rtm)->contStates)
+#endif
+
+#ifndef rtmSetContStates
+#define rtmSetContStates(rtm, val) ((rtm)->contStates = (val))
+#endif
+
+#ifndef rtmGetContTimeOutputInconsistentWithStateAtMajorStepFlag
+#define rtmGetContTimeOutputInconsistentWithStateAtMajorStepFlag(rtm) ((rtm)->CTOutputIncnstWithState)
+#endif
+
+#ifndef rtmSetContTimeOutputInconsistentWithStateAtMajorStepFlag
+#define rtmSetContTimeOutputInconsistentWithStateAtMajorStepFlag(rtm, val) ((rtm)->CTOutputIncnstWithState = (val))
+#endif
+
+#ifndef rtmGetDerivCacheNeedsReset
+#define rtmGetDerivCacheNeedsReset(rtm) ((rtm)->derivCacheNeedsReset)
+#endif
+
+#ifndef rtmSetDerivCacheNeedsReset
+#define rtmSetDerivCacheNeedsReset(rtm, val) ((rtm)->derivCacheNeedsReset = (val))
+#endif
+
+#ifndef rtmGetFinalTime
+#define rtmGetFinalTime(rtm) ((rtm)->Timing.tFinal)
+#endif
+
+#ifndef rtmGetIntgData
+#define rtmGetIntgData(rtm) ((rtm)->intgData)
+#endif
+
+#ifndef rtmSetIntgData
+#define rtmSetIntgData(rtm, val) ((rtm)->intgData = (val))
+#endif
+
+#ifndef rtmGetOdeF
+#define rtmGetOdeF(rtm) ((rtm)->odeF)
+#endif
+
+#ifndef rtmSetOdeF
+#define rtmSetOdeF(rtm, val) ((rtm)->odeF = (val))
+#endif
+
+#ifndef rtmGetOdeY
+#define rtmGetOdeY(rtm) ((rtm)->odeY)
+#endif
+
+#ifndef rtmSetOdeY
+#define rtmSetOdeY(rtm, val) ((rtm)->odeY = (val))
+#endif
+
+#ifndef rtmGetPeriodicContStateIndices
+#define rtmGetPeriodicContStateIndices(rtm) ((rtm)->periodicContStateIndices)
+#endif
+
+#ifndef rtmSetPeriodicContStateIndices
+#define rtmSetPeriodicContStateIndices(rtm, val) ((rtm)->periodicContStateIndices = (val))
+#endif
+
+#ifndef rtmGetPeriodicContStateRanges
+#define rtmGetPeriodicContStateRanges(rtm) ((rtm)->periodicContStateRanges)
+#endif
+
+#ifndef rtmSetPeriodicContStateRanges
+#define rtmSetPeriodicContStateRanges(rtm, val) ((rtm)->periodicContStateRanges = (val))
+#endif
+
+#ifndef rtmGetRTWLogInfo
+#define rtmGetRTWLogInfo(rtm) ((rtm)->rtwLogInfo)
+#endif
+
+#ifndef rtmGetZCCacheNeedsReset
+#define rtmGetZCCacheNeedsReset(rtm) ((rtm)->zCCacheNeedsReset)
+#endif
+
+#ifndef rtmSetZCCacheNeedsReset
+#define rtmSetZCCacheNeedsReset(rtm, val) ((rtm)->zCCacheNeedsReset = (val))
+#endif
+
+#ifndef rtmGetdX
+#define rtmGetdX(rtm) ((rtm)->derivs)
+#endif
+
+#ifndef rtmSetdX
+#define rtmSetdX(rtm, val) ((rtm)->derivs = (val))
+#endif
+
+#ifndef rtmGetErrorStatus
+#define rtmGetErrorStatus(rtm) ((rtm)->errorStatus)
+#endif
+
+#ifndef rtmSetErrorStatus
+#define rtmSetErrorStatus(rtm, val) ((rtm)->errorStatus = (val))
+#endif
+
+#ifndef rtmGetStopRequested
+#define rtmGetStopRequested(rtm) ((rtm)->Timing.stopRequestedFlag)
+#endif
+
+#ifndef rtmSetStopRequested
+#define rtmSetStopRequested(rtm, val) ((rtm)->Timing.stopRequestedFlag = (val))
+#endif
+
+#ifndef rtmGetStopRequestedPtr
+#define rtmGetStopRequestedPtr(rtm) (&((rtm)->Timing.stopRequestedFlag))
+#endif
+
+#ifndef rtmGetT
+#define rtmGetT(rtm) (rtmGetTPtr((rtm))[0])
+#endif
+
+#ifndef rtmGetTFinal
+#define rtmGetTFinal(rtm) ((rtm)->Timing.tFinal)
+#endif
+
+#ifndef rtmGetTPtr
+#define rtmGetTPtr(rtm) ((rtm)->Timing.t)
+#endif
+
+/* Block signals (default storage) */
+struct B_Model_T {
+ real_T Gain; /* '/Gain' */
+ real_T Gain2; /* '/Gain2' */
+ real_T Gain5; /* '/Gain5' */
+};
+
+/* Continuous states (default storage) */
+struct X_Model_T {
+ real_T Integrator1_CSTATE; /* '/Integrator1' */
+ real_T Integrator_CSTATE; /* '/Integrator' */
+ real_T Integrator2_CSTATE; /* '/Integrator2' */
+};
+
+/* State derivatives (default storage) */
+struct XDot_Model_T {
+ real_T Integrator1_CSTATE; /* '/Integrator1' */
+ real_T Integrator_CSTATE; /* '/Integrator' */
+ real_T Integrator2_CSTATE; /* '/Integrator2' */
+};
+
+/* State disabled */
+struct XDis_Model_T {
+ boolean_T Integrator1_CSTATE; /* '/Integrator1' */
+ boolean_T Integrator_CSTATE; /* '/Integrator' */
+ boolean_T Integrator2_CSTATE; /* '/Integrator2' */
+};
+
+#ifndef ODE3_INTG
+#define ODE3_INTG
+
+/* ODE3 Integration Data */
+struct ODE3_IntgData {
+ real_T *y; /* output */
+ real_T *f[3]; /* derivatives */
+};
+
+#endif
+
+/* External inputs (root inport signals with default storage) */
+struct ExtU_Model_T {
+ real_T Stellgrad; /* '/Stellgrad' */
+};
+
+/* External outputs (root outports fed by signals with default storage) */
+struct ExtY_Model_T {
+ real_T Temperatur; /* '/Temperatur' */
+};
+
+/* Parameters (default storage) */
+struct P_Model_T_ {
+ real_T AHD; /* Variable: AHD
+ * Referenced by: '