diff --git a/CMakeLists.txt b/CMakeLists.txt
index 345a112..3106d51 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,50 +1,11 @@
-cmake_minimum_required (VERSION 3.5.1)
+cmake_minimum_required (VERSION 3.0.0)
project (OpenDiscon)
-# OpenDiscon include directories
-set (OPENDISCON_INCLUDE_DIRS ${OPENDISCON_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/src/ikClwindconWTCon/)
-set (OPENDISCON_INCLUDE_DIRS ${OPENDISCON_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/src/ikClwindconWTConfig/)
-set (OPENDISCON_INCLUDE_DIRS ${OPENDISCON_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/src/ikTpman/)
-set (OPENDISCON_INCLUDE_DIRS ${OPENDISCON_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/src/ikPowman/)
+# choose a configuration
+set( CONFIGURATION "CL-Windcon" CACHE STRING
+"Choose a configuration.\n\
+Available configurations are:\n\
+CL-Windcon" )
-# OpenDiscon source files
-set (OPENDISCON_SOURCES ${OPENDISCON_SOURCES} ${PROJECT_SOURCE_DIR}/src/ikTpman/ikTpman.c)
-set (OPENDISCON_SOURCES ${OPENDISCON_SOURCES} ${PROJECT_SOURCE_DIR}/src/ikPowman/ikPowman.c)
-set (OPENDISCON_SOURCES ${OPENDISCON_SOURCES} ${PROJECT_SOURCE_DIR}/src/ikClwindconWTConfig/ikClwindconWTConfig.c)
-set (OPENDISCON_SOURCES ${OPENDISCON_SOURCES} ${PROJECT_SOURCE_DIR}/src/ikClwindconWTCon/ikClwindconWTCon.c)
-set (OPENDISCON_SOURCES ${OPENDISCON_SOURCES} ${PROJECT_SOURCE_DIR}/src/discon/discon.c)
-
-# OpenWitcon include directories
-set (OPENWITCON_INCLUDE_DIRS ${OPENWITCON_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikConLoop)
-set (OPENWITCON_INCLUDE_DIRS ${OPENWITCON_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikLinCon)
-set (OPENWITCON_INCLUDE_DIRS ${OPENWITCON_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikLutbl)
-set (OPENWITCON_INCLUDE_DIRS ${OPENWITCON_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikNotchList)
-set (OPENWITCON_INCLUDE_DIRS ${OPENWITCON_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikRegionSelector)
-set (OPENWITCON_INCLUDE_DIRS ${OPENWITCON_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikSlti)
-set (OPENWITCON_INCLUDE_DIRS ${OPENWITCON_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikStpgen)
-set (OPENWITCON_INCLUDE_DIRS ${OPENWITCON_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikTfList)
-set (OPENWITCON_INCLUDE_DIRS ${OPENWITCON_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikVfnotch)
-
-# OpenWitcon source files
-set (OPENDISCON_SOURCES ${OPENDISCON_SOURCES} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikConLoop/ikConLoop.c)
-set (OPENDISCON_SOURCES ${OPENDISCON_SOURCES} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikLinCon/ikLinCon.c)
-set (OPENDISCON_SOURCES ${OPENDISCON_SOURCES} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikLutbl/ikLutbl.c)
-set (OPENDISCON_SOURCES ${OPENDISCON_SOURCES} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikNotchList/ikNotchList.c)
-set (OPENDISCON_SOURCES ${OPENDISCON_SOURCES} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikRegionSelector/ikRegionSelector.c)
-set (OPENDISCON_SOURCES ${OPENDISCON_SOURCES} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikSlti/ikSlti.c)
-set (OPENDISCON_SOURCES ${OPENDISCON_SOURCES} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikStpgen/ikStpgen.c)
-set (OPENDISCON_SOURCES ${OPENDISCON_SOURCES} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikTfList/ikTfList.c)
-set (OPENDISCON_SOURCES ${OPENDISCON_SOURCES} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikVfnotch/ikVfnotch.c)
-
-# shared OpenDiscon library
-include_directories ("${OPENDISCON_INCLUDE_DIRS}")
-include_directories ("${OPENWITCON_INCLUDE_DIRS}")
-include_directories ("${PROJECT_BINARY_DIR}")
-include (GenerateExportHeader)
-add_library (OpenDiscon SHARED ${OPENDISCON_SOURCES})
-GENERATE_EXPORT_HEADER (OpenDiscon
- BASE_NAME OpenDiscon
- EXPORT_MACRO_NAME OpenDiscon_EXPORT
- EXPORT_FILE_NAME OpenDiscon_EXPORT.h
- STATIC_DEFINE OpenDiscon_BUILT_AS_STATIC
-)
+# run configuration-specific cmake script
+include( ${PROJECT_SOURCE_DIR}/CONFIGURATION/${CONFIGURATION}/CMakeLists.txt )
diff --git a/CONFIGURATION/CL-Windcon/CMakeLists.txt b/CONFIGURATION/CL-Windcon/CMakeLists.txt
new file mode 100644
index 0000000..0fb7937
--- /dev/null
+++ b/CONFIGURATION/CL-Windcon/CMakeLists.txt
@@ -0,0 +1,55 @@
+# choose a distribution
+set( DISTRIBUTION "DISCON" CACHE STRING
+"Choose a distribution.\n\
+Available distributions are:\n\
+DISCON\n\
+S-Function" )
+
+# OpenDiscon include directories
+set (OPENDISCON_INCLUDE_DIRS ${OPENDISCON_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/CONFIGURATION/${CONFIGURATION}/src/ikClwindconResetSensorSignals/)
+set (OPENDISCON_INCLUDE_DIRS ${OPENDISCON_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/CONFIGURATION/${CONFIGURATION}/src/ikClwindconWTCon/)
+set (OPENDISCON_INCLUDE_DIRS ${OPENDISCON_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/CONFIGURATION/${CONFIGURATION}/src/ikClwindconWTConfig/)
+set (OPENDISCON_INCLUDE_DIRS ${OPENDISCON_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/CONFIGURATION/${CONFIGURATION}/src/ikClwindconInputMod/)
+set (OPENDISCON_INCLUDE_DIRS ${OPENDISCON_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/CONFIGURATION/${CONFIGURATION}/src/ikTpman/)
+set (OPENDISCON_INCLUDE_DIRS ${OPENDISCON_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/CONFIGURATION/${CONFIGURATION}/src/ikPowman/)
+set (OPENDISCON_INCLUDE_DIRS ${OPENDISCON_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/CONFIGURATION/${CONFIGURATION}/src/ikSpdman/)
+
+# OpenDiscon source files
+set (OPENDISCON_SOURCES ${OPENDISCON_SOURCES} ${PROJECT_SOURCE_DIR}/CONFIGURATION/${CONFIGURATION}/src/ikSpdman/ikSpdman.c)
+set (OPENDISCON_SOURCES ${OPENDISCON_SOURCES} ${PROJECT_SOURCE_DIR}/CONFIGURATION/${CONFIGURATION}/src/ikTpman/ikTpman.c)
+set (OPENDISCON_SOURCES ${OPENDISCON_SOURCES} ${PROJECT_SOURCE_DIR}/CONFIGURATION/${CONFIGURATION}/src/ikPowman/ikPowman.c)
+set (OPENDISCON_SOURCES ${OPENDISCON_SOURCES} ${PROJECT_SOURCE_DIR}/CONFIGURATION/${CONFIGURATION}/src/ikClwindconInputMod/ikClwindconInputMod.c)
+set (OPENDISCON_SOURCES ${OPENDISCON_SOURCES} ${PROJECT_SOURCE_DIR}/CONFIGURATION/${CONFIGURATION}/src/ikClwindconWTConfig/ikClwindconWTConfig.c)
+set (OPENDISCON_SOURCES ${OPENDISCON_SOURCES} ${PROJECT_SOURCE_DIR}/CONFIGURATION/${CONFIGURATION}/src/ikClwindconWTCon/ikClwindconWTCon.c)
+set (OPENDISCON_SOURCES ${OPENDISCON_SOURCES} ${PROJECT_SOURCE_DIR}/CONFIGURATION/${CONFIGURATION}/src/ikClwindconResetSensorSignals/ikClwindconResetSensorSignals.c)
+
+# OpenWitcon include directories
+set (OPENWITCON_INCLUDE_DIRS ${OPENWITCON_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikConLoop)
+set (OPENWITCON_INCLUDE_DIRS ${OPENWITCON_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikLinCon)
+set (OPENWITCON_INCLUDE_DIRS ${OPENWITCON_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikLutbl)
+set (OPENWITCON_INCLUDE_DIRS ${OPENWITCON_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikNotchList)
+set (OPENWITCON_INCLUDE_DIRS ${OPENWITCON_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikRegionSelector)
+set (OPENWITCON_INCLUDE_DIRS ${OPENWITCON_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikSlti)
+set (OPENWITCON_INCLUDE_DIRS ${OPENWITCON_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikStpgen)
+set (OPENWITCON_INCLUDE_DIRS ${OPENWITCON_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikTfList)
+set (OPENWITCON_INCLUDE_DIRS ${OPENWITCON_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikVfnotch)
+set (OPENWITCON_INCLUDE_DIRS ${OPENWITCON_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikIpc)
+set (OPENWITCON_INCLUDE_DIRS ${OPENWITCON_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikVector)
+set (OPENWITCON_INCLUDE_DIRS ${OPENWITCON_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikSensorDiagnoser)
+
+# OpenWitcon source files
+set (OPENDISCON_SOURCES ${OPENDISCON_SOURCES} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikConLoop/ikConLoop.c)
+set (OPENDISCON_SOURCES ${OPENDISCON_SOURCES} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikLinCon/ikLinCon.c)
+set (OPENDISCON_SOURCES ${OPENDISCON_SOURCES} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikLutbl/ikLutbl.c)
+set (OPENDISCON_SOURCES ${OPENDISCON_SOURCES} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikNotchList/ikNotchList.c)
+set (OPENDISCON_SOURCES ${OPENDISCON_SOURCES} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikRegionSelector/ikRegionSelector.c)
+set (OPENDISCON_SOURCES ${OPENDISCON_SOURCES} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikSlti/ikSlti.c)
+set (OPENDISCON_SOURCES ${OPENDISCON_SOURCES} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikStpgen/ikStpgen.c)
+set (OPENDISCON_SOURCES ${OPENDISCON_SOURCES} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikTfList/ikTfList.c)
+set (OPENDISCON_SOURCES ${OPENDISCON_SOURCES} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikVfnotch/ikVfnotch.c)
+set (OPENDISCON_SOURCES ${OPENDISCON_SOURCES} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikIpc/ikIpc.c)
+set (OPENDISCON_SOURCES ${OPENDISCON_SOURCES} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikVector/ikVector.c)
+set (OPENDISCON_SOURCES ${OPENDISCON_SOURCES} ${PROJECT_SOURCE_DIR}/OpenWitcon/src/ikSensorDiagnoser/ikSensorDiagnoser.c)
+
+# run distribution-specific cmake script
+include( ${PROJECT_SOURCE_DIR}/CONFIGURATION/${CONFIGURATION}/DISTRIBUTION/${DISTRIBUTION}/CMakeLists.txt )
diff --git a/CONFIGURATION/CL-Windcon/DISTRIBUTION/DISCON/CMakeLists.txt b/CONFIGURATION/CL-Windcon/DISTRIBUTION/DISCON/CMakeLists.txt
new file mode 100644
index 0000000..f170fdc
--- /dev/null
+++ b/CONFIGURATION/CL-Windcon/DISTRIBUTION/DISCON/CMakeLists.txt
@@ -0,0 +1,14 @@
+set (OPENDISCON_SOURCES ${OPENDISCON_SOURCES} ${PROJECT_SOURCE_DIR}/CONFIGURATION/${CONFIGURATION}/src/discon/discon.c)
+
+# shared OpenDiscon library
+include_directories ("${OPENDISCON_INCLUDE_DIRS}")
+include_directories ("${OPENWITCON_INCLUDE_DIRS}")
+include_directories ("${PROJECT_BINARY_DIR}")
+include (GenerateExportHeader)
+add_library (OpenDiscon SHARED ${OPENDISCON_SOURCES})
+GENERATE_EXPORT_HEADER (OpenDiscon
+ BASE_NAME OpenDiscon
+ EXPORT_MACRO_NAME OpenDiscon_EXPORT
+ EXPORT_FILE_NAME OpenDiscon_EXPORT.h
+ STATIC_DEFINE OpenDiscon_BUILT_AS_STATIC
+)
diff --git a/CONFIGURATION/CL-Windcon/DISTRIBUTION/S-Function/CMakeLists.txt b/CONFIGURATION/CL-Windcon/DISTRIBUTION/S-Function/CMakeLists.txt
new file mode 100644
index 0000000..7fd08ca
--- /dev/null
+++ b/CONFIGURATION/CL-Windcon/DISTRIBUTION/S-Function/CMakeLists.txt
@@ -0,0 +1,10 @@
+set (OPENDISCON_SOURCES ${OPENDISCON_SOURCES} ${PROJECT_SOURCE_DIR}/CONFIGURATION/${CONFIGURATION}/src/sfunc/sfunc.c)
+
+string (REPLACE ";" " -I" OPENDISCON_INCLUDE_DIRS "${OPENDISCON_INCLUDE_DIRS}")
+string (REPLACE ";" " " OPENDISCON_SOURCES "${OPENDISCON_SOURCES}")
+
+string (REPLACE ";" " -I" OPENWITCON_INCLUDE_DIRS "${OPENWITCON_INCLUDE_DIRS}")
+string (REPLACE ";" " " OPENWITCON_SOURCES "${OPENWITCON_SOURCES}")
+
+configure_file (${PROJECT_SOURCE_DIR}/CONFIGURATION/${CONFIGURATION}/src/sfunc/makeOpenDiscon.m ${PROJECT_BINARY_DIR}/)
+configure_file (${PROJECT_SOURCE_DIR}/CONFIGURATION/${CONFIGURATION}/src/sfunc/OpenDiscon_block.mdl ${PROJECT_BINARY_DIR}/)
diff --git a/CONFIGURATION/CL-Windcon/src/discon/discon.c b/CONFIGURATION/CL-Windcon/src/discon/discon.c
new file mode 100644
index 0000000..6c9cb14
--- /dev/null
+++ b/CONFIGURATION/CL-Windcon/src/discon/discon.c
@@ -0,0 +1,100 @@
+/*
+Copyright (C) 2017 IK4-IKERLAN
+
+This file is part of OpenDiscon.
+
+OpenDiscon is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+OpenDiscon is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with OpenDiscon. If not, see .
+*/
+
+#define NINT(a) ((a) >= 0.0 ? (int) ((a)+0.5) : ((a)-0.5))
+
+#include "ikClwindconResetSensorSignals.h"
+#include "ikClwindconInputMod.h"
+#include "ikClwindconWTConfig.h"
+#include "OpenDiscon_EXPORT.h"
+#include
+
+void OpenDiscon_EXPORT DISCON(float *DATA, int FLAG, const char *INFILE, const char *OUTNAME, char *MESSAGE) {
+ int err;
+ static ikClwindconWTCon con;
+ double output = -12.0;
+ static FILE *f = NULL;
+ const double deratingRatio = 0.0; /* later to be got via the supercontroller interface */
+
+ if (NINT(DATA[0]) == 0) {
+ ikClwindconWTConParams param;
+ ikClwindconWTCon_initParams(¶m);
+ setParams(¶m);
+ ikClwindconWTCon_init(&con, ¶m);
+ f = fopen("log.bin", "wb");
+ }
+
+ con.in.deratingRatio = deratingRatio;
+ con.in.externalMaximumTorque = 230.0; /* kNm */
+ con.in.externalMinimumTorque = 0.0; /* kNm */
+ con.in.externalMaximumPitch = 90.0; /* deg */
+ con.in.externalMinimumPitch = 0.0; /* deg */
+ con.in.generatorSpeed = (double) DATA[19]; /* rad/s */
+ con.in.rotorSpeed = (double) DATA[20]; /* rad/s */
+ con.in.maximumSpeed = 480.0/30*3.1416; /* rpm to rad/s */
+ con.in.azimuth = 180.0/3.1416 * (double) DATA[59]; /* rad to deg */
+ con.in.maximumIndividualPitch = 0.0; /* deg */
+ con.in.yawErrorReference = 0.0; /* deg */
+ con.in.yawError = 180.0/3.1416 * (double) DATA[23]; /* rad to deg */
+ con.in.bladeRootMoments[0].c[0] = 1.0e-3 * (double) DATA[68]; /* Nm to kNm */
+ con.in.bladeRootMoments[0].c[1] = 1.0e-3 * (double) DATA[29]; /* Nm to kNm */
+ con.in.bladeRootMoments[0].c[2] = 0.0; /* kNm */
+ con.in.bladeRootMoments[1].c[0] = 1.0e-3 * (double) DATA[69]; /* Nm to kNm */
+ con.in.bladeRootMoments[1].c[1] = 1.0e-3 * (double) DATA[30]; /* Nm to kNm */
+ con.in.bladeRootMoments[1].c[2] = 0.0; /* kNm */
+ con.in.bladeRootMoments[2].c[0] = 1.0e-3 * (double) DATA[70]; /* Nm to kNm */
+ con.in.bladeRootMoments[2].c[1] = 1.0e-3 * (double) DATA[31]; /* Nm to kNm */
+ con.in.bladeRootMoments[2].c[2] = 0.0; /* kNm */
+
+ ikClwindconInputMod(&(con.in));
+ ikClwindconResetSensorSignals(&(con.in));
+ ikClwindconWTCon_step(&con);
+
+ /* ####################################### */
+
+ DATA[46] = (float) (con.out.torqueDemand*1.0e3); /* kNm to Nm */
+ DATA[41] = (float) (con.out.pitchDemandBlade1/180.0*3.1416); /* deg to rad */
+ DATA[42] = (float) (con.out.pitchDemandBlade2/180.0*3.1416); /* deg to rad */
+ DATA[43] = (float) (con.out.pitchDemandBlade3/180.0*3.1416); /* deg to rad */
+ err = ikClwindconWTCon_getOutput(&con, &output, "collective pitch demand");
+ DATA[44] = (float) (output/180.0*3.1416); /* deg to rad (collective pitch angle) */
+
+ err = ikClwindconWTCon_getOutput(&con, &output, "individual pitch control>pitch y from control");
+ fwrite(&(output), 1, sizeof(output), f);
+ err = ikClwindconWTCon_getOutput(&con, &output, "individual pitch control>pitch z from control");
+ fwrite(&(output), 1, sizeof(output), f);
+ err = ikClwindconWTCon_getOutput(&con, &output, "individual pitch control>My");
+ fwrite(&(output), 1, sizeof(output), f);
+ err = ikClwindconWTCon_getOutput(&con, &output, "individual pitch control>Mz");
+ fwrite(&(output), 1, sizeof(output), f);
+ err = ikClwindconWTCon_getOutput(&con, &output, "individual pitch control>pitch increment 1");
+ fwrite(&(output), 1, sizeof(output), f);
+ err = ikClwindconWTCon_getOutput(&con, &output, "individual pitch control>pitch increment 2");
+ fwrite(&(output), 1, sizeof(output), f);
+ err = ikClwindconWTCon_getOutput(&con, &output, "individual pitch control>pitch increment 3");
+ fwrite(&(output), 1, sizeof(output), f);
+ err = ikClwindconWTCon_getOutput(&con, &output, "generator speed equivalent");
+ fwrite(&(output), 1, sizeof(output), f);
+ err = ikClwindconWTCon_getOutput(&con, &output, "speed sensor manager>signal 1");
+ fwrite(&(output), 1, sizeof(output), f);
+ err = ikClwindconWTCon_getOutput(&con, &output, "speed sensor manager>signal 2");
+ fwrite(&(output), 1, sizeof(output), f);
+ err = ikClwindconWTCon_getOutput(&con, &output, "speed sensor manager>signal 3");
+ fwrite(&(output), 1, sizeof(output), f);
+}
diff --git a/CONFIGURATION/CL-Windcon/src/ikClwindconInputMod/ikClwindconInputMod.c b/CONFIGURATION/CL-Windcon/src/ikClwindconInputMod/ikClwindconInputMod.c
new file mode 100644
index 0000000..647ab40
--- /dev/null
+++ b/CONFIGURATION/CL-Windcon/src/ikClwindconInputMod/ikClwindconInputMod.c
@@ -0,0 +1,61 @@
+/*
+Copyright (C) 2017 IK4-IKERLAN
+
+This file is part of OpenDiscon.
+
+OpenDiscon is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+OpenDiscon is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with OpenDiscon. If not, see .
+*/
+
+/**
+ * @file ikClwindconInputMod.c
+ *
+ * @brief CL-Windcon wind turbine controller input modification
+ */
+
+#include "ikClwindconInputMod.h"
+
+void ikClwindconInputMod(ikClwindconWTConInputs *in) {
+
+ ikGeneratorSpeedSingalFail(in);
+
+}
+
+void ikGeneratorSpeedSingalFail(ikClwindconWTConInputs *in) {
+ static int _n = 0;
+
+ /*! [Speed sensor fault] */
+ /*
+ ####################################################################
+ Speed sensor fault
+
+ A generator speed measurement of val is enforced after N sampling
+ intervals (N <= 0 to disable).
+
+ Set parameters here:
+ */
+ const int N = 10000;
+ const double val = 0.0;
+ /*
+ ####################################################################
+ */
+ /*! [Speed sensor fault] */
+
+ if (0 < N && _n < N) {
+ _n++;
+ return;
+ }
+
+ in->generatorSpeed = val;
+
+}
diff --git a/CONFIGURATION/CL-Windcon/src/ikClwindconInputMod/ikClwindconInputMod.h b/CONFIGURATION/CL-Windcon/src/ikClwindconInputMod/ikClwindconInputMod.h
new file mode 100644
index 0000000..e2be026
--- /dev/null
+++ b/CONFIGURATION/CL-Windcon/src/ikClwindconInputMod/ikClwindconInputMod.h
@@ -0,0 +1,43 @@
+/*
+Copyright (C) 2017 IK4-IKERLAN
+
+This file is part of OpenDiscon.
+
+OpenDiscon is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+OpenDiscon is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with OpenDiscon. If not, see .
+*/
+
+/**
+ * @file ikClwindconInputMod.h
+ *
+ * @brief CL-Windcon wind turbine controller input modification
+ */
+
+#ifndef IKCLWINDCONINPUTMOD_H
+#define IKCLWINDCONINPUTMOD_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ikClwindconWTCon.h"
+
+ void ikClwindconInputMod(ikClwindconWTConInputs *in);
+ void ikGeneratorSpeedSingalFail(ikClwindconWTConInputs *in);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* IKCLWINDCONINPUTMOD_H */
+
diff --git a/CONFIGURATION/CL-Windcon/src/ikClwindconResetSensorSignals/ikClwindconResetSensorSignals.c b/CONFIGURATION/CL-Windcon/src/ikClwindconResetSensorSignals/ikClwindconResetSensorSignals.c
new file mode 100644
index 0000000..a323e74
--- /dev/null
+++ b/CONFIGURATION/CL-Windcon/src/ikClwindconResetSensorSignals/ikClwindconResetSensorSignals.c
@@ -0,0 +1,53 @@
+/*
+Copyright (C) 2017 IK4-IKERLAN
+
+This file is part of OpenDiscon.
+
+OpenDiscon is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+OpenDiscon is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with OpenDiscon. If not, see .
+*/
+
+/**
+ * @file ikClwindconInputMod.c
+ *
+ * @brief CL-Windcon wind turbine controller input modification
+ */
+
+#include "ikClwindconResetSensorSignals.h"
+
+void ikClwindconResetSensorSignals(ikClwindconWTConInputs *in) {
+
+ ikAllOK(in);
+
+}
+
+void ikAllOK(ikClwindconWTConInputs *in) {
+ /*! [Reset Speed sensor fault] */
+ /*
+ ####################################################################
+
+ Set parameters here:
+ */
+ const int nSteps = 3000;
+ static int _t;
+ /*
+ ####################################################################
+ */
+ if (!(_t < nSteps) && !(nSteps < _t)){
+ in->ResetSignal = 1;
+ _t++;
+ } else {
+ _t++;
+ in->ResetSignal = 0;
+ }
+}
diff --git a/CONFIGURATION/CL-Windcon/src/ikClwindconResetSensorSignals/ikClwindconResetSensorSignals.h b/CONFIGURATION/CL-Windcon/src/ikClwindconResetSensorSignals/ikClwindconResetSensorSignals.h
new file mode 100644
index 0000000..50213e3
--- /dev/null
+++ b/CONFIGURATION/CL-Windcon/src/ikClwindconResetSensorSignals/ikClwindconResetSensorSignals.h
@@ -0,0 +1,44 @@
+/*
+Copyright (C) 2017 IK4-IKERLAN
+
+This file is part of OpenDiscon.
+
+OpenDiscon is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+OpenDiscon is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with OpenDiscon. If not, see .
+*/
+
+/**
+ * @file ikClwindconInputMod.h
+ *
+ * @brief CL-Windcon wind turbine controller input modification
+ */
+
+#ifndef IKCLWINDCONRESETSENSORSIGNALS_H
+#define IKCLWINDCONRESETSENSORSIGNALS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ikClwindconWTCon.h"
+#include "ikSensorDiagnoser.h"
+
+ void ikClwindconResetSensorSignals(ikClwindconWTConInputs *in);
+ void ikAllOK(ikClwindconWTConInputs *in);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* IKCLWINDCONINPUTMOD_H */
+
diff --git a/src/ikClwindconWTCon/ikClwindconWTCon.c b/CONFIGURATION/CL-Windcon/src/ikClwindconWTCon/ikClwindconWTCon.c
similarity index 68%
rename from src/ikClwindconWTCon/ikClwindconWTCon.c
rename to CONFIGURATION/CL-Windcon/src/ikClwindconWTCon/ikClwindconWTCon.c
index 1b25e4e..4287561 100644
--- a/src/ikClwindconWTCon/ikClwindconWTCon.c
+++ b/CONFIGURATION/CL-Windcon/src/ikClwindconWTCon/ikClwindconWTCon.c
@@ -48,6 +48,12 @@ int ikClwindconWTCon_init(ikClwindconWTCon *self, const ikClwindconWTConParams *
if (err) return -5;
err = ikPowman_init(&(self->priv.powerManager), &(params_.powerManager));
if (err) return -6;
+ err = ikIpc_init(&(self->priv.ipc), &(params_.individualPitchControl));
+ if (err) return -7;
+ err = ikConLoop_init(&(self->priv.yawByIpc), &(params_.yawByIpc));
+ if (err) return -8;
+ err = ikSpdman_init(&(self->priv.speedSensorManager), &(params_.speedSensorManager));
+ if (err) return -9;
/* initialise feedback signals */
self->priv.torqueFromTorqueCon = 0.0;
@@ -63,12 +69,20 @@ void ikClwindconWTCon_initParams(ikClwindconWTConParams *params) {
ikConLoop_initParams(&(params->torqueControl));
ikTpman_initParams(&(params->torquePitchManager));
ikPowman_initParams(&(params->powerManager));
+ ikIpc_initParams(&(params->individualPitchControl));
+ ikConLoop_initParams(&(params->yawByIpc));
+ ikSpdman_initParams(&(params->speedSensorManager));
}
int ikClwindconWTCon_step(ikClwindconWTCon *self) {
+ int i;
+
+ /* run speed sensor manager */
+ ikSpdman_step(&(self->priv.speedSensorManager), self->in.generatorSpeed, self->in.rotorSpeed, self->in.azimuth, self->in.ResetSignal);
+ ikSpdman_getOutput(&(self->priv.speedSensorManager), &(self->priv.generatorSpeedEquivalent), "generator speed equivalent");
/* run power manager */
- self->priv.maxTorqueFromPowman = ikPowman_step(&(self->priv.powerManager), self->in.deratingRatio, self->in.maximumSpeed, self->in.generatorSpeed);
+ self->priv.maxTorqueFromPowman = ikPowman_step(&(self->priv.powerManager), self->in.deratingRatio, self->in.maximumSpeed, self->priv.generatorSpeedEquivalent);
ikPowman_getOutput(&(self->priv.powerManager), &(self->priv.minPitchFromPowman), "minimum pitch");
ikPowman_getOutput(&(self->priv.powerManager), &(self->priv.belowRatedTorque), "below rated torque");
@@ -84,21 +98,39 @@ int ikClwindconWTCon_step(ikClwindconWTCon *self) {
ikTpman_getOutput(&(self->priv.tpManager), &(self->priv.minTorque), "minimum torque");
/* run drivetrain damper */
- self->priv.torqueFromDtdamper = ikConLoop_step(&(self->priv.dtdamper), 0.0, self->in.generatorSpeed, -(self->in.externalMaximumTorque), self->in.externalMaximumTorque);
+ self->priv.torqueFromDtdamper = ikConLoop_step(&(self->priv.dtdamper), 0.0, self->priv.generatorSpeedEquivalent, -(self->in.externalMaximumTorque), self->in.externalMaximumTorque);
/* run torque control */
- self->priv.torqueFromTorqueCon = ikConLoop_step(&(self->priv.torquecon), self->in.maximumSpeed, self->in.generatorSpeed, self->priv.minTorque, self->priv.maxTorque);
+ self->priv.torqueFromTorqueCon = ikConLoop_step(&(self->priv.torquecon), self->in.maximumSpeed, self->priv.generatorSpeedEquivalent, self->priv.minTorque, self->priv.maxTorque);
/* calculate torque demand */
self->out.torqueDemand = self->priv.torqueFromDtdamper + self->priv.torqueFromTorqueCon;
/* run collective pitch control */
- self->priv.collectivePitchDemand = ikConLoop_step(&(self->priv.colpitchcon), self->in.maximumSpeed, self->in.generatorSpeed, self->priv.minPitch, self->priv.maxPitch);
+ self->priv.collectivePitchDemand = ikConLoop_step(&(self->priv.colpitchcon), self->in.maximumSpeed, self->priv.generatorSpeedEquivalent, self->priv.minPitch, self->priv.maxPitch);
+
+ /* run yaw by ipc */
+ self->priv.individualPitchForYaw = ikConLoop_step(&(self->priv.yawByIpc), self->in.yawErrorReference, self->in.yawError, -self->in.maximumIndividualPitch, self->in.maximumIndividualPitch);
+
+ /* run individual pitch control */
+ self->priv.ipc.in.azimuth = self->in.azimuth;
+ self->priv.ipc.in.collectivePitch = self->priv.collectivePitchDemand;
+ self->priv.ipc.in.maximumPitch = self->priv.maxPitch;
+ self->priv.ipc.in.minimumPitch = self->priv.minPitch;
+ for (i = 0; i < 3; i++) {
+ self->priv.ipc.in.bladeRootMoments[i] = self->in.bladeRootMoments[i];
+ }
+ self->priv.ipc.in.demandedMy = 0.0;
+ self->priv.ipc.in.demandedMz = 0.0;
+ self->priv.ipc.in.maximumIndividualPitch = self->in.maximumIndividualPitch;
+ self->priv.ipc.in.externalPitchY = self->priv.individualPitchForYaw;
+ self->priv.ipc.in.externalPitchZ = 0.0;
+ ikIpc_step(&(self->priv.ipc));
/* run IPC */
- self->out.pitchDemandBlade1 = self->priv.collectivePitchDemand;
- self->out.pitchDemandBlade2 = self->priv.collectivePitchDemand;
- self->out.pitchDemandBlade3 = self->priv.collectivePitchDemand;
+ self->out.pitchDemandBlade1 = self->priv.ipc.out.pitch[0];
+ self->out.pitchDemandBlade2 = self->priv.ipc.out.pitch[1];
+ self->out.pitchDemandBlade3 = self->priv.ipc.out.pitch[2];
return self->priv.tpManState;
}
@@ -144,6 +176,14 @@ int ikClwindconWTCon_getOutput(const ikClwindconWTCon *self, double *output, con
*output = self->priv.minPitchFromPowman;
return 0;
}
+ if (!strcmp(name, "individual pitch for yaw")) {
+ *output = self->priv.individualPitchForYaw;
+ return 0;
+ }
+ if (!strcmp(name, "generator speed equivalent")) {
+ *output = self->priv.generatorSpeedEquivalent;
+ return 0;
+ }
/* pick up the block names */
sep = strstr(name, ">");
@@ -173,6 +213,21 @@ int ikClwindconWTCon_getOutput(const ikClwindconWTCon *self, double *output, con
if (err) return -1;
else return 0;
}
+ if (!strncmp(name, "individual pitch control", strlen(name) - strlen(sep))) {
+ err = ikIpc_getOutput(&(self->priv.ipc), output, sep + 1);
+ if (err) return -1;
+ else return 0;
+ }
+ if (!strncmp(name, "yaw by ipc", strlen(name) - strlen(sep))) {
+ err = ikConLoop_getOutput(&(self->priv.yawByIpc), output, sep + 1);
+ if (err) return -1;
+ else return 0;
+ }
+ if (!strncmp(name, "speed sensor manager", strlen(name) - strlen(sep))) {
+ err = ikSpdman_getOutput(&(self->priv.speedSensorManager), output, sep + 1);
+ if (err) return -1;
+ else return 0;
+ }
return -2;
diff --git a/src/ikClwindconWTCon/ikClwindconWTCon.h b/CONFIGURATION/CL-Windcon/src/ikClwindconWTCon/ikClwindconWTCon.h
similarity index 81%
rename from src/ikClwindconWTCon/ikClwindconWTCon.h
rename to CONFIGURATION/CL-Windcon/src/ikClwindconWTCon/ikClwindconWTCon.h
index 04ae6fb..ceac94c 100644
--- a/src/ikClwindconWTCon/ikClwindconWTCon.h
+++ b/CONFIGURATION/CL-Windcon/src/ikClwindconWTCon/ikClwindconWTCon.h
@@ -33,6 +33,8 @@ extern "C" {
#include "ikConLoop.h"
#include "ikTpman.h"
#include "ikPowman.h"
+#include "ikIpc.h"
+#include "ikSpdman.h"
/**
* @struct ikClwindconWTConInputs
@@ -45,7 +47,14 @@ extern "C" {
double externalMinimumPitch; /**.
#include "ikClwindconWTConfig.h"
void setParams(ikClwindconWTConParams *param) {
- double T = 0.01;
+ /*! [Sampling interval] */
+ /*
+ ####################################################################
+ Sampling interval
+
+ Set sampling interval here:
+ */
+ const double T = 0.01; /* [s] */
+ /*
+ ####################################################################
+ */
+ /*! [Sampling interval] */
ikTuneDrivetrainDamper(&(param->drivetrainDamper), T);
ikTuneSpeedRange(&(param->torqueControl));
@@ -40,12 +51,18 @@ void setParams(ikClwindconWTConParams *param) {
ikTuneTorqueLowpassFilter(&(param->torqueControl), T);
ikTuneTorqueNotches(&(param->torqueControl), T);
ikTuneTorquePI(&(param->torqueControl), T);
+ ikConfigureRotorForIpc(&(param->individualPitchControl));
+ ikTuneIpcMyPI(&(param->individualPitchControl.controlMy), T);
+ ikTuneIpcMzPI(&(param->individualPitchControl.controlMz), T);
+ ikTuneYawByIpc(&(param->yawByIpc), T);
+ ikTuneYawByIpcLowpassFilter(&(param->yawByIpc), T);
+ ikConfigureSpeedManager(&(param->speedSensorManager), T);
}
void ikTuneDrivetrainDamper(ikConLoopParams *params, double T) {
- /*! [CL-Windcon drivetrain damper] */
+ /*! [Drivetrain damper] */
/*
####################################################################
Drivetrain damper
@@ -58,13 +75,13 @@ void ikTuneDrivetrainDamper(ikConLoopParams *params, double T) {
Set parameters here:
*/
- double G = 0.0382; /* [kNm s^2/rad] 4 Nm s/rpm */
- double d = 0.1; /* [-] */
- double w = 21.1; /* [rad/s] */
+ const double G = 0.0382; /* [kNm s^2/rad] 4 Nm s/rpm */
+ const double d = 0.1; /* [-] */
+ const double w = 21.1; /* [rad/s] */
/*
####################################################################
*/
- /*! [CL-Windcon drivetrain damper] */
+ /*! [Drivetrain damper] */
/*
@@ -228,8 +245,8 @@ void ikTunePitchLowpassFilter(ikConLoopParams *params, double T) {
Set parameters here:
*/
- double w = 5.6; /* [rad/s] */
- double d = 0.5; /* [-] */
+ const double w = 5.6; /* [rad/s] */
+ const double d = 0.5; /* [-] */
/*
####################################################################
*/
@@ -276,9 +293,9 @@ void ikTunePitchNotches(ikConLoopParams *params, double T) {
Set parameters here:
*/
- double w = 1.59; /* [rad/s] */
- double dnum = 0.01; /* [-] */
- double dden = 0.2; /* [-] */
+ const double w = 1.59; /* [rad/s] */
+ const double dnum = 0.01; /* [-] */
+ const double dden = 0.2; /* [-] */
/*
####################################################################
*/
@@ -307,8 +324,8 @@ void ikTunePitchPI(ikConLoopParams *params, double T) {
Set parameters here:
*/
- double Kp = -0.3939; /* [degs/rad] 7.2e-4 rad/rpm */
- double Ki = -0.1313; /* [deg/rad] 2.4e-4 rad/rpms */
+ const double Kp = -0.3939; /* [degs/rad] 7.2e-4 rad/rpm */
+ const double Ki = -0.1313; /* [deg/rad] 2.4e-4 rad/rpms */
/*
####################################################################
*/
@@ -354,8 +371,8 @@ void ikTuneTorqueLowpassFilter(ikConLoopParams *params, double T) {
Set parameters here:
*/
- double w = 3.39; /* [rad/s] */
- double d = 0.5; /* [-] */
+ const double w = 3.39; /* [rad/s] */
+ const double d = 0.5; /* [-] */
/*
####################################################################
*/
@@ -402,9 +419,9 @@ void ikTuneTorqueNotches(ikConLoopParams *params, double T) {
Set parameters here:
*/
- double w = 1.59; /* [rad/s] */
- double dnum = 0.01; /* [-] */
- double dden = 0.2; /* [-] */
+ const double w = 1.59; /* [rad/s] */
+ const double dnum = 0.01; /* [-] */
+ const double dden = 0.2; /* [-] */
/*
####################################################################
*/
@@ -433,14 +450,13 @@ void ikTuneTorquePI(ikConLoopParams *params, double T) {
Set parameters here:
*/
- double Kp = -34.3775; /* [kNms/rad] 3600 Nm/rpm */
- double Ki = -11.4592; /* [kNm/rad] 1200 Nm/rpms */
+ const double Kp = -34.3775; /* [kNms/rad] 3600 Nm/rpm */
+ const double Ki = -11.4592; /* [kNm/rad] 1200 Nm/rpms */
/*
####################################################################
*/
/*! [Torque PI] */
-
/*
tune the torque control to this tf:
(Kp + Ki*T/2)z - (Kp - Ki*T/2)
@@ -465,3 +481,231 @@ void ikTuneTorquePI(ikConLoopParams *params, double T) {
params->linearController.postGainTfs.tfParams[0].a[2] = 0.0;
}
+
+void ikConfigureRotorForIpc(ikIpcParams *params) {
+
+ params->azimuthOffset = 0.0;
+ params->bladeOrder = 1;
+
+}
+
+void ikTuneIpcMyPI(ikConLoopParams *params, double T) {
+
+ /*! [IPC My PI] */
+ /*
+ ####################################################################
+ IPC My PI
+
+ Transfer function:
+
+ C(s) = (Kp*s + Ki)/s
+
+ The sampling time is given by function parameter T.
+
+ Set parameters here:
+ */
+ const double Kp = 0.0; /* [deg/kNm] */
+ const double Ki = -0.1e-3; /* [deg/kNms] */
+ /*
+ ####################################################################
+ */
+ /*! [IPC My PI] */
+
+ /*
+ tune the ipc My control to this tf:
+ (Kp + Ki*T/2)z - (Kp - Ki*T/2)
+ C(z) = ------------------------------
+ z - 1
+ rad/s --> kNm
+ */
+ params->linearController.errorTfs.tfParams[0].enable = 1;
+ params->linearController.errorTfs.tfParams[0].b[0] = (Kp + Ki*T/2);
+ params->linearController.errorTfs.tfParams[0].b[1] = -(Kp - Ki*T/2);
+ params->linearController.errorTfs.tfParams[0].b[2] = 0.0;
+ params->linearController.errorTfs.tfParams[0].a[0] = 1.0;
+ params->linearController.errorTfs.tfParams[0].a[1] = 0.0;
+ params->linearController.errorTfs.tfParams[0].a[2] = 0.0;
+
+ params->linearController.postGainTfs.tfParams[0].enable = 1;
+ params->linearController.postGainTfs.tfParams[0].b[0] = 1.0;
+ params->linearController.postGainTfs.tfParams[0].b[1] = 0.0;
+ params->linearController.postGainTfs.tfParams[0].b[2] = 0.0;
+ params->linearController.postGainTfs.tfParams[0].a[0] = 1.0;
+ params->linearController.postGainTfs.tfParams[0].a[1] = -1.0;
+ params->linearController.postGainTfs.tfParams[0].a[2] = 0.0;
+
+}
+
+void ikTuneIpcMzPI(ikConLoopParams *params, double T) {
+
+ /*! [IPC Mz PI] */
+ /*
+ ####################################################################
+ IPC Mz PI
+
+ Transfer function:
+
+ C(s) = (Kp*s + Ki)/s
+
+ The sampling time is given by function parameter T.
+
+ Set parameters here:
+ */
+ const double Kp = 0.0; /* [deg/kNm] */
+ const double Ki = -0.1e-3; /* [deg/kNms] */
+ /*
+ ####################################################################
+ */
+ /*! [IPC Mz PI] */
+
+ /*
+ tune the ipc Mz control to this tf:
+ (Kp + Ki*T/2)z - (Kp - Ki*T/2)
+ C(z) = ------------------------------
+ z - 1
+ rad/s --> kNm
+ */
+ params->linearController.errorTfs.tfParams[0].enable = 1;
+ params->linearController.errorTfs.tfParams[0].b[0] = (Kp + Ki*T/2);
+ params->linearController.errorTfs.tfParams[0].b[1] = -(Kp - Ki*T/2);
+ params->linearController.errorTfs.tfParams[0].b[2] = 0.0;
+ params->linearController.errorTfs.tfParams[0].a[0] = 1.0;
+ params->linearController.errorTfs.tfParams[0].a[1] = 0.0;
+ params->linearController.errorTfs.tfParams[0].a[2] = 0.0;
+
+ params->linearController.postGainTfs.tfParams[0].enable = 1;
+ params->linearController.postGainTfs.tfParams[0].b[0] = 1.0;
+ params->linearController.postGainTfs.tfParams[0].b[1] = 0.0;
+ params->linearController.postGainTfs.tfParams[0].b[2] = 0.0;
+ params->linearController.postGainTfs.tfParams[0].a[0] = 1.0;
+ params->linearController.postGainTfs.tfParams[0].a[1] = -1.0;
+ params->linearController.postGainTfs.tfParams[0].a[2] = 0.0;
+
+}
+
+void ikTuneYawByIpc(ikConLoopParams *params, double T) {
+/*
+This is an original implementation of the yaw by IPC strategy in 87e4a2fe8e8ac8fc51305a3f840e23a0deaf6caa of https://github.com/TUDelft-DataDrivenControl/DRC_Fortran
+*/
+
+ /*! [Yaw by IPC PI] */
+ /*
+ ####################################################################
+ Yaw by IPC PI
+
+ Transfer function:
+
+ C(s) = (Kp*s + Ki)/s
+
+ The sampling time is given by function parameter T.
+
+ Set parameters here:
+ */
+ const double Kp = 0.0; /* [-] */
+ const double Ki = 0.0; /* [1/s] */
+ /*
+ ####################################################################
+ */
+ /*! [Yaw by IPC PI] */
+
+ /*
+ tune the yaw by ipc control to this tf:
+ (Kp + Ki*T/2)z - (Kp - Ki*T/2)
+ C(z) = ------------------------------
+ z - 1
+ deg --> deg
+ */
+ params->linearController.errorTfs.tfParams[0].enable = 1;
+ params->linearController.errorTfs.tfParams[0].b[0] = (Kp + Ki*T/2);
+ params->linearController.errorTfs.tfParams[0].b[1] = -(Kp - Ki*T/2);
+ params->linearController.errorTfs.tfParams[0].b[2] = 0.0;
+ params->linearController.errorTfs.tfParams[0].a[0] = 1.0;
+ params->linearController.errorTfs.tfParams[0].a[1] = 0.0;
+ params->linearController.errorTfs.tfParams[0].a[2] = 0.0;
+
+ params->linearController.postGainTfs.tfParams[0].enable = 1;
+ params->linearController.postGainTfs.tfParams[0].b[0] = 1.0;
+ params->linearController.postGainTfs.tfParams[0].b[1] = 0.0;
+ params->linearController.postGainTfs.tfParams[0].b[2] = 0.0;
+ params->linearController.postGainTfs.tfParams[0].a[0] = 1.0;
+ params->linearController.postGainTfs.tfParams[0].a[1] = -1.0;
+ params->linearController.postGainTfs.tfParams[0].a[2] = 0.0;
+
+}
+
+void ikTuneYawByIpcLowpassFilter(ikConLoopParams *params, double T) {
+/*
+This is an original implementation of the yaw by IPC strategy in 87e4a2fe8e8ac8fc51305a3f840e23a0deaf6caa of https://github.com/TUDelft-DataDrivenControl/DRC_Fortran
+*/
+
+ /*! [Yaw by IPC lowpass filter] */
+ /*
+ ####################################################################
+ Yaw error feedback low pass filter
+
+ Transfer function:
+ H(s) = w^2 / (s^2 + 2*d*w*s + w^2)
+
+ The sampling time is given by function parameter T.
+
+ The default values have been kindly provided by TUDelft, who have calculated them to suit the DTU 10MW reference wind turbine from FP7 project INNWIND.
+ Set parameters here:
+ */
+ const double w = 0.6283185; /* [rad/s] */
+ const double d = 1.0; /* [-] */
+ /*
+ ####################################################################
+ */
+ /*! [Yaw by IPC lowpass filter] */
+
+ /*
+ tune the yaw by ipc control feedback filter to this tf:
+ (0.5*T*w)^2 z^2 + 2z + 1
+ H(z) = ----------------------------- ------------------------------------------------------------------------------------------------------------------------
+ 1 + T*d*w + (0.5*T*w)^2 z^2 - 2*(1 - (0.5*T*w)^2) / (1 + T*d*w + (0.5*T*w)^2)z + (1 - T*d*w + (0.5*T*w)^2) / (1 + T*d*w + (0.5*T*w)^2)
+ */
+ params->linearController.measurementTfs.tfParams[0].enable = 1;
+ params->linearController.measurementTfs.tfParams[0].b[0] = 1.0;
+ params->linearController.measurementTfs.tfParams[0].b[1] = 2.0;
+ params->linearController.measurementTfs.tfParams[0].b[2] = 1.0;
+ params->linearController.measurementTfs.tfParams[0].a[0] = 1.0;
+ params->linearController.measurementTfs.tfParams[0].a[1] = -2 * (1 - (0.5*T*w)*(0.5*T*w)) / (1 + T*d*w + (0.5*T*w)*(0.5*T*w));
+ params->linearController.measurementTfs.tfParams[0].a[2] = (1 - T*d*w + (0.5*T*w)*(0.5*T*w)) / (1 + T*d*w + (0.5*T*w)*(0.5*T*w));
+
+ params->linearController.measurementTfs.tfParams[1].enable = 1;
+ params->linearController.measurementTfs.tfParams[1].b[0] = (0.5*T*w)*(0.5*T*w) / (1 + T*d*w + (0.5*T*w)*(0.5*T*w));
+
+}
+
+void ikConfigureSpeedManager(ikSpdmanParams *params, double T) {
+
+ /*! [Speed sensor manager] */
+ /*
+ ####################################################################
+ Speed sensor management
+
+ Differences between the generator speed, rotor speed and azimuth derivative
+ (the latter two multiplied by the gearbox ratio) are considered a fault if
+ they are larger than tol for longer than N sampling intervals T.
+
+ Set parameters here:
+ */
+ const int N = 4; /* [-] */
+ const double tol = 1.0; /* [rad/s] */
+ const double gbRatio = 50.0; /* [-] */
+ /*
+ ####################################################################
+ */
+ /*! [Speed sensor manager] */
+
+ params->diagnoser.nStepsToFault = N;
+ params->diagnoser.tolerance = tol;
+
+ params->gearboxRatio = gbRatio;
+ params->T = T;
+ params->minAzimuth = 0.0;
+ params->maxAzimuth = 360.0;
+
+
+
+}
diff --git a/src/ikClwindconWTConfig/ikClwindconWTConfig.h b/CONFIGURATION/CL-Windcon/src/ikClwindconWTConfig/ikClwindconWTConfig.h
similarity index 83%
rename from src/ikClwindconWTConfig/ikClwindconWTConfig.h
rename to CONFIGURATION/CL-Windcon/src/ikClwindconWTConfig/ikClwindconWTConfig.h
index c5e3e7e..a02a7e9 100644
--- a/src/ikClwindconWTConfig/ikClwindconWTConfig.h
+++ b/CONFIGURATION/CL-Windcon/src/ikClwindconWTConfig/ikClwindconWTConfig.h
@@ -58,6 +58,18 @@ extern "C" {
void ikTunePitchPIGainSchedule(ikConLoopParams *params);
+ void ikConfigureRotorForIpc(ikIpcParams *params);
+
+ void ikTuneIpcMyPI(ikConLoopParams *params, double T);
+
+ void ikTuneIpcMzPI(ikConLoopParams *params, double T);
+
+ void ikTuneYawByIpc(ikConLoopParams *params, double T);
+
+ void ikTuneYawByIpcLowpassFilter(ikConLoopParams *params, double T);
+
+ void ikConfigureSpeedManager(ikSpdmanParams *params, double T);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/ikPowman/ikPowman.c b/CONFIGURATION/CL-Windcon/src/ikPowman/ikPowman.c
similarity index 98%
rename from src/ikPowman/ikPowman.c
rename to CONFIGURATION/CL-Windcon/src/ikPowman/ikPowman.c
index 29b515f..b7447c3 100644
--- a/src/ikPowman/ikPowman.c
+++ b/CONFIGURATION/CL-Windcon/src/ikPowman/ikPowman.c
@@ -25,6 +25,9 @@ along with OpenDiscon. If not, see .
/* @cond */
+#include
+#include
+
#include "ikPowman.h"
int ikPowman_init(ikPowman *self, const ikPowmanParams *params) {
diff --git a/src/ikPowman/ikPowman.h b/CONFIGURATION/CL-Windcon/src/ikPowman/ikPowman.h
similarity index 100%
rename from src/ikPowman/ikPowman.h
rename to CONFIGURATION/CL-Windcon/src/ikPowman/ikPowman.h
diff --git a/CONFIGURATION/CL-Windcon/src/ikSpdman/ikSpdman.c b/CONFIGURATION/CL-Windcon/src/ikSpdman/ikSpdman.c
new file mode 100644
index 0000000..3bc7500
--- /dev/null
+++ b/CONFIGURATION/CL-Windcon/src/ikSpdman/ikSpdman.c
@@ -0,0 +1,143 @@
+/*
+Copyright (C) 2017 IK4-IKERLAN
+
+This file is part of OpenDiscon.
+
+OpenDiscon is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+OpenDiscon is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with OpenDiscon. If not, see .
+*/
+
+/**
+ * @file ikSpdman.c
+ *
+ * @brief Class ikSpdman implementation
+ */
+
+/* @cond */
+
+#include
+#include
+
+#include "ikSpdman.h"
+
+int ikSpdman_init(ikSpdman *self, const ikSpdmanParams *params) {
+ int err;
+ int err_ = 0;
+
+ /* pass on member parameters */
+ err = ikSensorDiagnoser_init(&(self->diagnoser), &(params->diagnoser));
+ if (err && !err_) err_ = -1;
+
+ /* register parameter values */
+ self->gbratio = params->gearboxRatio;
+ if (0.0 > params->T) return -2;
+ self->T = params->T;
+ if (params->maxAzimuth <= params->minAzimuth) return -3;
+ self->azimuthRange = params->maxAzimuth - params->minAzimuth;
+
+ return err_;
+}
+
+void ikSpdman_initParams(ikSpdmanParams *params) {
+
+ /* pass on member parameters */
+ ikSensorDiagnoser_initParams(&(params->diagnoser));
+
+ /* set default values */
+ params->gearboxRatio = 1.0;
+ params->T = 1.0;
+ params->minAzimuth = 0.0;
+ params->maxAzimuth = 360.0;
+}
+
+int ikSpdman_step(ikSpdman *self, double generatorSpeed, double rotorSpeed, double azimuth, int ResetSignal) {
+ int i;
+ double diff;
+
+ /* prepare signals */
+ self->signals[0] = generatorSpeed;
+ self->signals[1] = self->gbratio*rotorSpeed;
+ diff = azimuth - self->lastAzimuth;
+ diff = diff < self->azimuthRange/2 ? diff : diff - self->azimuthRange;
+ diff = diff > -self->azimuthRange/2 ? diff : diff + self->azimuthRange;
+ self->signals[2] = self->gbratio * diff / self->T / 180.0 * 3.14159265358979;
+ self->lastAzimuth = azimuth;
+ self->diagnoser.ResetSignal = ResetSignal;
+ /* run diagnoser */
+ ikSensorDiagnoser_step(&(self->diagnoser), self->ok, self->signals);
+
+ /* compute status */
+ self->status = 0;
+ for (i = 0; i < 3; i++) {
+ if (!self->ok[i]) {
+ if (!self->status) self->status = -1 - i;
+ else self->status = 4;
+ }
+ }
+
+ /* choose the signal to output */
+ switch (self->status) {
+ case -1 :
+ self->outputSpeed = self->signals[1];
+ break;
+ default :
+ self->outputSpeed = self->signals[0];
+ }
+
+ return self->status;
+}
+
+int ikSpdman_getOutput(const ikSpdman *self, double *output, const char *name) {
+ const char *sep;
+
+ /* pick up the signal names */
+ if (!strcmp(name, "generator speed equivalent")) {
+ *output = self->outputSpeed;
+ return 0;
+ }
+ if (!strcmp(name, "signal 1")) {
+ *output = self->signals[0];
+ return 0;
+ }
+ if (!strcmp(name, "signal 2")) {
+ *output = self->signals[1];
+ return 0;
+ }
+ if (!strcmp(name, "signal 3")) {
+ *output = self->signals[2];
+ return 0;
+ }
+ if (!strcmp(name, "ok 1")) {
+ *output = self->ok[0];
+ return 0;
+ }
+ if (!strcmp(name, "ok 2")) {
+ *output = self->ok[1];
+ return 0;
+ }
+ if (!strcmp(name, "ok 3")) {
+ *output = self->ok[2];
+ return 0;
+ }
+
+ /* pick up the block names */
+ sep = strstr(name, ">");
+ if (NULL == sep) return -1;
+
+ return -2;
+}
+
+/* @endcond */
+
+
+
diff --git a/CONFIGURATION/CL-Windcon/src/ikSpdman/ikSpdman.h b/CONFIGURATION/CL-Windcon/src/ikSpdman/ikSpdman.h
new file mode 100644
index 0000000..94fe24f
--- /dev/null
+++ b/CONFIGURATION/CL-Windcon/src/ikSpdman/ikSpdman.h
@@ -0,0 +1,159 @@
+/*
+Copyright (C) 2017 IK4-IKERLAN
+
+This file is part of OpenDiscon.
+
+OpenDiscon is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+OpenDiscon is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with OpenDiscon. If not, see .
+*/
+
+/**
+ * @file ikSpdman.h
+ *
+ * @brief Class ikSpdman interface
+ */
+
+#ifndef IKSPDMAN_H
+#define IKSPDMAN_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ikSensorDiagnoser.h"
+
+ /**
+ * @struct ikSpdman
+ * @brief Speed sensor manager
+ *
+ * This takes the generator speed, rotor speed and azimuth angle measurements, cross-checks them and outputs a usable generator speed signal when possible.
+ *
+ * @par Inputs
+ * @li generator speed: generator speed in rad/s, specify via @link ikSpdman_step @endlink
+ * @li rotor speed: rotor speed in rad/s, specify via @link ikSpdman_step @endlink
+ * @li azimuth: rotor azimuth angle in degrees, specify via @link ikSpdman_step @endlink
+ *
+ * @par Outputs
+ * @li generator speed equivalent: generator speed for use by controller, in rad/s, get via @link ikSpdman_getOutput @endlink
+ * @li status: status code, returned by @link ikSpdman_step @endlink, alternatively get via @link ikSpdman_getOutput @endlink
+ *
+ * @par Unit block
+ *
+ * @image html ikSpdman_unit_block.svg
+ *
+ * @par Block diagram
+ *
+ * @image html ikSpdman_block_diagram.svg
+ *
+ * @par Map
+ *
+
+
ok 1
ok 2
ok 3
status
mux
+
1
1
1
0
1
+
0
1
1
-1
2
+
1
0
1
-2
1
+
1
1
0
-3
1
+
0
0
1
-4
1
+
0
1
0
-4
1
+
1
0
0
-4
1
+
0
0
0
-4
1
+
+ *
+ * @par Methods
+ * @li @link ikSpdman_initParams @endlink initialise initialisation parameter structure
+ * @li @link ikSpdman_init @endlink initialise an instance
+ * @li @link ikSpdman_step @endlink execute periodic calculations
+ * @li @link ikSpdman_getOutput @endlink get output value
+ */
+ typedef struct ikSpdman {
+ /**
+ * Private members
+ */
+ /* @cond */
+ ikSensorDiagnoser diagnoser;
+ double gbratio;
+ double T;
+ double azimuthRange;
+ double lastAzimuth;
+ double signals[3];
+ int ok[3];
+ double outputSpeed;
+ int status;
+ /* @endcond */
+ } ikSpdman;
+
+ /**
+ * @struct ikSpdmanParams
+ * @brief Speed sensor manager initialisation parameters
+ */
+ typedef struct ikSpdmanParams {
+ ikSensorDiagnoserParams diagnoser; /**"
+ LastModifiedBy "ielorza"
+ ModifiedDateFormat "%"
+ LastModifiedDate "Fri Jan 05 11:00:16 2018"
+ RTWModifiedTimeStamp 437050811
+ ModelVersionFormat "1.%"
+ ConfigurationManager "none"
+ SampleTimeColors off
+ SampleTimeAnnotations off
+ LibraryLinkDisplay "disabled"
+ WideLines off
+ ShowLineDimensions off
+ ShowPortDataTypes off
+ ShowDesignRanges off
+ ShowLoopsOnError on
+ IgnoreBidirectionalLines off
+ ShowStorageClass off
+ ShowTestPointIcons on
+ ShowSignalResolutionIcons on
+ ShowViewerIcons on
+ SortedOrder off
+ ExecutionContextIcon off
+ ShowLinearizationAnnotations on
+ BlockNameDataTip off
+ BlockParametersDataTip off
+ BlockDescriptionStringDataTip off
+ ToolBar on
+ StatusBar on
+ BrowserShowLibraryLinks off
+ BrowserLookUnderMasks off
+ SimulationMode "normal"
+ PauseTimes "5"
+ NumberOfSteps 1
+ SnapshotBufferSize 10
+ SnapshotInterval 10
+ NumberOfLastSnapshots 0
+ LinearizationMsg "none"
+ Profile off
+ ParamWorkspaceSource "MATLABWorkspace"
+ AccelSystemTargetFile "accel.tlc"
+ AccelTemplateMakefile "accel_default_tmf"
+ AccelMakeCommand "make_rtw"
+ TryForcingSFcnDF off
+ Object {
+ $PropName "DataLoggingOverride"
+ $ObjectID 6
+ $ClassName "Simulink.SimulationData.ModelLoggingInfo"
+ model_ "OpenDiscon_block"
+ overrideMode_ [0.0]
+ Array {
+ Type "Cell"
+ Dimension 1
+ Cell "OpenDiscon_block"
+ PropName "logAsSpecifiedByModels_"
+ }
+ Array {
+ Type "Cell"
+ Dimension 1
+ Cell []
+ PropName "logAsSpecifiedByModelsSSIDs_"
+ }
+ }
+ RecordCoverage off
+ CovPath "/"
+ CovSaveName "covdata"
+ CovMetricSettings "dw"
+ CovNameIncrementing off
+ CovHtmlReporting on
+ CovForceBlockReductionOff on
+ CovEnableCumulative on
+ covSaveCumulativeToWorkspaceVar on
+ CovSaveSingleToWorkspaceVar on
+ CovCumulativeVarName "covCumulativeData"
+ CovCumulativeReport off
+ CovReportOnPause on
+ CovModelRefEnable "Off"
+ CovExternalEMLEnable off
+ CovSFcnEnable off
+ CovBoundaryAbsTol 0.000010
+ CovBoundaryRelTol 0.010000
+ ExtModeBatchMode off
+ ExtModeEnableFloating on
+ ExtModeTrigType "manual"
+ ExtModeTrigMode "normal"
+ ExtModeTrigPort "1"
+ ExtModeTrigElement "any"
+ ExtModeTrigDuration 1000
+ ExtModeTrigDurationFloating "auto"
+ ExtModeTrigHoldOff 0
+ ExtModeTrigDelay 0
+ ExtModeTrigDirection "rising"
+ ExtModeTrigLevel 0
+ ExtModeArchiveMode "off"
+ ExtModeAutoIncOneShot off
+ ExtModeIncDirWhenArm off
+ ExtModeAddSuffixToVar off
+ ExtModeWriteAllDataToWs off
+ ExtModeArmWhenConnect on
+ ExtModeSkipDownloadWhenConnect off
+ ExtModeLogAll on
+ ExtModeAutoUpdateStatusClock on
+ BufferReuse on
+ ShowModelReferenceBlockVersion off
+ ShowModelReferenceBlockIO off
+ Array {
+ Type "Handle"
+ Dimension 1
+ Simulink.ConfigSet {
+ $ObjectID 7
+ Version "1.14.2"
+ Array {
+ Type "Handle"
+ Dimension 9
+ Simulink.SolverCC {
+ $ObjectID 8
+ Version "1.14.2"
+ StartTime "0.0"
+ StopTime "10.0"
+ AbsTol "auto"
+ FixedStep "auto"
+ InitialStep "auto"
+ MaxNumMinSteps "-1"
+ MaxOrder 5
+ ZcThreshold "auto"
+ ConsecutiveZCsStepRelTol "10*128*eps"
+ MaxConsecutiveZCs "1000"
+ ExtrapolationOrder 4
+ NumberNewtonIterations 1
+ MaxStep "auto"
+ MinStep "auto"
+ MaxConsecutiveMinStep "1"
+ RelTol "1e-3"
+ SolverMode "Auto"
+ EnableConcurrentExecution off
+ ConcurrentTasks off
+ Solver "ode45"
+ SolverName "ode45"
+ SolverJacobianMethodControl "auto"
+ ShapePreserveControl "DisableAll"
+ ZeroCrossControl "UseLocalSettings"
+ ZeroCrossAlgorithm "Nonadaptive"
+ AlgebraicLoopSolver "TrustRegion"
+ SolverResetMethod "Fast"
+ PositivePriorityOrder off
+ AutoInsertRateTranBlk off
+ SampleTimeConstraint "Unconstrained"
+ InsertRTBMode "Whenever possible"
+ }
+ Simulink.DataIOCC {
+ $ObjectID 9
+ Version "1.14.2"
+ Decimation "1"
+ ExternalInput "[t, u]"
+ FinalStateName "xFinal"
+ InitialState "xInitial"
+ LimitDataPoints on
+ MaxDataPoints "1000"
+ LoadExternalInput off
+ LoadInitialState off
+ SaveFinalState off
+ SaveCompleteFinalSimState off
+ SaveFormat "Array"
+ SignalLoggingSaveFormat "Dataset"
+ SaveOutput on
+ SaveState off
+ SignalLogging on
+ DSMLogging on
+ InspectSignalLogs off
+ VisualizeSimOutput on
+ SaveTime on
+ ReturnWorkspaceOutputs off
+ StateSaveName "xout"
+ TimeSaveName "tout"
+ OutputSaveName "yout"
+ SignalLoggingName "logsout"
+ DSMLoggingName "dsmout"
+ OutputOption "RefineOutputTimes"
+ OutputTimes "[]"
+ ReturnWorkspaceOutputsName "out"
+ Refine "1"
+ }
+ Simulink.OptimizationCC {
+ $ObjectID 10
+ Version "1.14.2"
+ Array {
+ Type "Cell"
+ Dimension 8
+ Cell "BooleansAsBitfields"
+ Cell "PassReuseOutputArgsAs"
+ Cell "PassReuseOutputArgsThreshold"
+ Cell "ZeroExternalMemoryAtStartup"
+ Cell "ZeroInternalMemoryAtStartup"
+ Cell "OptimizeModelRefInitCode"
+ Cell "NoFixptDivByZeroProtection"
+ Cell "UseSpecifiedMinMax"
+ PropName "DisabledProps"
+ }
+ BlockReduction on
+ BooleanDataType on
+ ConditionallyExecuteInputs on
+ InlineParams off
+ UseIntDivNetSlope off
+ UseFloatMulNetSlope off
+ DefaultUnderspecifiedDataType "double"
+ UseSpecifiedMinMax off
+ InlineInvariantSignals off
+ OptimizeBlockIOStorage on
+ BufferReuse on
+ EnhancedBackFolding off
+ CachingGlobalReferences off
+ GlobalBufferReuse on
+ StrengthReduction off
+ ExpressionFolding on
+ BooleansAsBitfields off
+ BitfieldContainerType "uint_T"
+ EnableMemcpy on
+ MemcpyThreshold 64
+ PassReuseOutputArgsAs "Structure reference"
+ ExpressionDepthLimit 128
+ FoldNonRolledExpr on
+ LocalBlockOutputs on
+ RollThreshold 5
+ SystemCodeInlineAuto off
+ StateBitsets off
+ DataBitsets off
+ ActiveStateOutputEnumStorageType "Native Integer"
+ UseTempVars off
+ ZeroExternalMemoryAtStartup on
+ ZeroInternalMemoryAtStartup on
+ InitFltsAndDblsToZero off
+ NoFixptDivByZeroProtection off
+ EfficientFloat2IntCast off
+ EfficientMapNaN2IntZero on
+ OptimizeModelRefInitCode off
+ LifeSpan "inf"
+ MaxStackSize "Inherit from target"
+ BufferReusableBoundary on
+ SimCompilerOptimization "Off"
+ AccelVerboseBuild off
+ ParallelExecutionInRapidAccelerator on
+ }
+ Simulink.DebuggingCC {
+ $ObjectID 11
+ Version "1.14.2"
+ RTPrefix "error"
+ ConsistencyChecking "none"
+ ArrayBoundsChecking "none"
+ SignalInfNanChecking "none"
+ SignalRangeChecking "none"
+ ReadBeforeWriteMsg "UseLocalSettings"
+ WriteAfterWriteMsg "UseLocalSettings"
+ WriteAfterReadMsg "UseLocalSettings"
+ AlgebraicLoopMsg "warning"
+ ArtificialAlgebraicLoopMsg "warning"
+ SaveWithDisabledLinksMsg "warning"
+ SaveWithParameterizedLinksMsg "warning"
+ CheckSSInitialOutputMsg on
+ UnderspecifiedInitializationDetection "Simplified"
+ MergeDetectMultiDrivingBlocksExec "none"
+ CheckExecutionContextPreStartOutputMsg off
+ CheckExecutionContextRuntimeOutputMsg off
+ SignalResolutionControl "UseLocalSettings"
+ BlockPriorityViolationMsg "warning"
+ MinStepSizeMsg "warning"
+ TimeAdjustmentMsg "none"
+ MaxConsecutiveZCsMsg "error"
+ MaskedZcDiagnostic "warning"
+ IgnoredZcDiagnostic "warning"
+ SolverPrmCheckMsg "warning"
+ InheritedTsInSrcMsg "warning"
+ DiscreteInheritContinuousMsg "warning"
+ MultiTaskDSMMsg "error"
+ MultiTaskCondExecSysMsg "error"
+ MultiTaskRateTransMsg "error"
+ SingleTaskRateTransMsg "none"
+ TasksWithSamePriorityMsg "warning"
+ SigSpecEnsureSampleTimeMsg "warning"
+ CheckMatrixSingularityMsg "none"
+ IntegerOverflowMsg "warning"
+ Int32ToFloatConvMsg "warning"
+ ParameterDowncastMsg "error"
+ ParameterOverflowMsg "error"
+ ParameterUnderflowMsg "none"
+ ParameterPrecisionLossMsg "warning"
+ ParameterTunabilityLossMsg "warning"
+ FixptConstUnderflowMsg "none"
+ FixptConstOverflowMsg "none"
+ FixptConstPrecisionLossMsg "none"
+ UnderSpecifiedDataTypeMsg "none"
+ UnnecessaryDatatypeConvMsg "none"
+ VectorMatrixConversionMsg "none"
+ InvalidFcnCallConnMsg "error"
+ FcnCallInpInsideContextMsg "EnableAllAsError"
+ SignalLabelMismatchMsg "none"
+ UnconnectedInputMsg "warning"
+ UnconnectedOutputMsg "warning"
+ UnconnectedLineMsg "warning"
+ SFcnCompatibilityMsg "none"
+ FrameProcessingCompatibilityMsg "warning"
+ UniqueDataStoreMsg "none"
+ BusObjectLabelMismatch "warning"
+ RootOutportRequireBusObject "warning"
+ AssertControl "UseLocalSettings"
+ EnableOverflowDetection off
+ ModelReferenceIOMsg "none"
+ ModelReferenceMultiInstanceNormalModeStructChecksumCheck "error"
+ ModelReferenceVersionMismatchMessage "none"
+ ModelReferenceIOMismatchMessage "none"
+ ModelReferenceCSMismatchMessage "none"
+ UnknownTsInhSupMsg "warning"
+ ModelReferenceDataLoggingMessage "warning"
+ ModelReferenceSymbolNameMessage "warning"
+ ModelReferenceExtraNoncontSigs "error"
+ StateNameClashWarn "none"
+ SimStateInterfaceChecksumMismatchMsg "warning"
+ SimStateOlderReleaseMsg "error"
+ InitInArrayFormatMsg "warning"
+ StrictBusMsg "ErrorLevel1"
+ BusNameAdapt "WarnAndRepair"
+ NonBusSignalsTreatedAsBus "none"
+ LoggingUnavailableSignals "error"
+ BlockIODiagnostic "none"
+ SFUnusedDataAndEventsDiag "warning"
+ SFUnexpectedBacktrackingDiag "warning"
+ SFInvalidInputDataAccessInChartInitDiag "warning"
+ SFNoUnconditionalDefaultTransitionDiag "warning"
+ SFTransitionOutsideNaturalParentDiag "warning"
+ SFUnconditionalTransitionShadowingDiag "warning"
+ SFUndirectedBroadcastEventsDiag "warning"
+ SFTransitionActionBeforeConditionDiag "warning"
+ }
+ Simulink.HardwareCC {
+ $ObjectID 12
+ Version "1.14.2"
+ ProdBitPerChar 8
+ ProdBitPerShort 16
+ ProdBitPerInt 32
+ ProdBitPerLong 32
+ ProdBitPerLongLong 64
+ ProdBitPerFloat 32
+ ProdBitPerDouble 64
+ ProdBitPerPointer 32
+ ProdLargestAtomicInteger "Char"
+ ProdLargestAtomicFloat "None"
+ ProdIntDivRoundTo "Undefined"
+ ProdEndianess "Unspecified"
+ ProdWordSize 32
+ ProdShiftRightIntArith on
+ ProdLongLongMode off
+ ProdHWDeviceType "32-bit Generic"
+ TargetBitPerChar 8
+ TargetBitPerShort 16
+ TargetBitPerInt 32
+ TargetBitPerLong 32
+ TargetBitPerLongLong 64
+ TargetBitPerFloat 32
+ TargetBitPerDouble 64
+ TargetBitPerPointer 32
+ TargetLargestAtomicInteger "Char"
+ TargetLargestAtomicFloat "None"
+ TargetShiftRightIntArith on
+ TargetLongLongMode off
+ TargetIntDivRoundTo "Undefined"
+ TargetEndianess "Unspecified"
+ TargetWordSize 32
+ TargetTypeEmulationWarnSuppressLevel 0
+ TargetPreprocMaxBitsSint 32
+ TargetPreprocMaxBitsUint 32
+ TargetHWDeviceType "Specified"
+ TargetUnknown off
+ ProdEqTarget on
+ }
+ Simulink.ModelReferenceCC {
+ $ObjectID 13
+ Version "1.14.2"
+ UpdateModelReferenceTargets "IfOutOfDateOrStructuralChange"
+ CheckModelReferenceTargetMessage "error"
+ EnableParallelModelReferenceBuilds off
+ ParallelModelReferenceErrorOnInvalidPool on
+ ParallelModelReferenceMATLABWorkerInit "None"
+ ModelReferenceNumInstancesAllowed "Multi"
+ PropagateVarSize "Infer from blocks in model"
+ ModelReferencePassRootInputsByReference on
+ ModelReferenceMinAlgLoopOccurrences off
+ PropagateSignalLabelsOutOfModel off
+ SupportModelReferenceSimTargetCustomCode off
+ }
+ Simulink.SFSimCC {
+ $ObjectID 14
+ Version "1.14.2"
+ SFSimEnableDebug on
+ SFSimOverflowDetection on
+ SFSimEcho on
+ SimBlas on
+ SimCtrlC on
+ SimExtrinsic on
+ SimIntegrity on
+ SimUseLocalCustomCode off
+ SimParseCustomCode on
+ SimBuildMode "sf_incremental_build"
+ SimGenImportedTypeDefs off
+ }
+ Simulink.RTWCC {
+ $BackupClass "Simulink.RTWCC"
+ $ObjectID 15
+ Version "1.14.2"
+ Array {
+ Type "Cell"
+ Dimension 15
+ Cell "IncludeHyperlinkInReport"
+ Cell "GenerateTraceInfo"
+ Cell "GenerateTraceReport"
+ Cell "GenerateTraceReportSl"
+ Cell "GenerateTraceReportSf"
+ Cell "GenerateTraceReportEml"
+ Cell "PortableWordSizes"
+ Cell "GenerateWebview"
+ Cell "GenerateCodeMetricsReport"
+ Cell "GenerateCodeReplacementReport"
+ Cell "GenerateErtSFunction"
+ Cell "CreateSILPILBlock"
+ Cell "CodeExecutionProfiling"
+ Cell "CodeProfilingSaveOptions"
+ Cell "CodeProfilingInstrumentation"
+ PropName "DisabledProps"
+ }
+ SystemTargetFile "grt.tlc"
+ TLCOptions ""
+ GenCodeOnly off
+ MakeCommand "make_rtw"
+ GenerateMakefile on
+ PackageGeneratedCodeAndArtifacts off
+ PackageName ""
+ TemplateMakefile "grt_default_tmf"
+ PostCodeGenCommand ""
+ Description ""
+ GenerateReport off
+ SaveLog off
+ RTWVerbose on
+ RetainRTWFile off
+ ProfileTLC off
+ TLCDebug off
+ TLCCoverage off
+ TLCAssert off
+ ProcessScriptMode "Default"
+ ConfigurationMode "Optimized"
+ ProcessScript ""
+ ConfigurationScript ""
+ ConfigAtBuild off
+ RTWUseLocalCustomCode off
+ RTWUseSimCustomCode off
+ CustomSourceCode ""
+ CustomHeaderCode ""
+ CustomInclude ""
+ CustomSource ""
+ CustomLibrary ""
+ CustomInitializer ""
+ CustomTerminator ""
+ Toolchain "Automatically locate an installed toolchain"
+ BuildConfiguration "Faster Builds"
+ IncludeHyperlinkInReport off
+ LaunchReport off
+ PortableWordSizes off
+ CreateSILPILBlock "None"
+ CodeExecutionProfiling off
+ CodeExecutionProfileVariable "executionProfile"
+ CodeProfilingSaveOptions "SummaryOnly"
+ CodeProfilingInstrumentation off
+ SILDebugging off
+ TargetLang "C"
+ IncludeBusHierarchyInRTWFileBlockHierarchyMap off
+ IncludeERTFirstTime off
+ GenerateTraceInfo off
+ GenerateTraceReport off
+ GenerateTraceReportSl off
+ GenerateTraceReportSf off
+ GenerateTraceReportEml off
+ GenerateCodeInfo off
+ GenerateWebview off
+ GenerateCodeMetricsReport off
+ GenerateCodeReplacementReport off
+ RTWCompilerOptimization "Off"
+ RTWCustomCompilerOptimizations ""
+ CheckMdlBeforeBuild "Off"
+ CustomRebuildMode "OnUpdate"
+ DataInitializer ""
+ SharedConstantsCachingThreshold 1024
+ Array {
+ Type "Handle"
+ Dimension 2
+ Simulink.CodeAppCC {
+ $ObjectID 16
+ Version "1.14.2"
+ Array {
+ Type "Cell"
+ Dimension 23
+ Cell "IgnoreCustomStorageClasses"
+ Cell "IgnoreTestpoints"
+ Cell "InsertBlockDesc"
+ Cell "InsertPolySpaceComments"
+ Cell "SFDataObjDesc"
+ Cell "MATLABFcnDesc"
+ Cell "SimulinkDataObjDesc"
+ Cell "DefineNamingRule"
+ Cell "SignalNamingRule"
+ Cell "ParamNamingRule"
+ Cell "InternalIdentifier"
+ Cell "InlinedPrmAccess"
+ Cell "CustomSymbolStr"
+ Cell "CustomSymbolStrGlobalVar"
+ Cell "CustomSymbolStrType"
+ Cell "CustomSymbolStrField"
+ Cell "CustomSymbolStrFcn"
+ Cell "CustomSymbolStrFcnArg"
+ Cell "CustomSymbolStrBlkIO"
+ Cell "CustomSymbolStrTmpVar"
+ Cell "CustomSymbolStrMacro"
+ Cell "CustomSymbolStrUtil"
+ Cell "ReqsInCode"
+ PropName "DisabledProps"
+ }
+ ForceParamTrailComments off
+ GenerateComments on
+ CommentStyle "Auto"
+ IgnoreCustomStorageClasses on
+ IgnoreTestpoints off
+ IncHierarchyInIds off
+ MaxIdLength 31
+ PreserveName off
+ PreserveNameWithParent off
+ ShowEliminatedStatement off
+ OperatorAnnotations off
+ IncAutoGenComments off
+ SimulinkDataObjDesc off
+ SFDataObjDesc off
+ MATLABFcnDesc off
+ IncDataTypeInIds off
+ MangleLength 1
+ CustomSymbolStrGlobalVar "$R$N$M"
+ CustomSymbolStrType "$N$R$M_T"
+ CustomSymbolStrField "$N$M"
+ CustomSymbolStrFcn "$R$N$M$F"
+ CustomSymbolStrFcnArg "rt$I$N$M"
+ CustomSymbolStrBlkIO "rtb_$N$M"
+ CustomSymbolStrTmpVar "$N$M"
+ CustomSymbolStrMacro "$R$N$M"
+ CustomSymbolStrUtil "$N$C"
+ DefineNamingRule "None"
+ ParamNamingRule "None"
+ SignalNamingRule "None"
+ InsertBlockDesc off
+ InsertPolySpaceComments off
+ SimulinkBlockComments on
+ MATLABSourceComments off
+ EnableCustomComments off
+ InternalIdentifier "Shortened"
+ InlinedPrmAccess "Literals"
+ ReqsInCode off
+ UseSimReservedNames off
+ }
+ Simulink.GRTTargetCC {
+ $BackupClass "Simulink.TargetCC"
+ $ObjectID 17
+ Version "1.14.2"
+ Array {
+ Type "Cell"
+ Dimension 14
+ Cell "GeneratePreprocessorConditionals"
+ Cell "IncludeMdlTerminateFcn"
+ Cell "CombineOutputUpdateFcns"
+ Cell "SuppressErrorStatus"
+ Cell "ERTCustomFileBanners"
+ Cell "GenerateSampleERTMain"
+ Cell "GenerateTestInterfaces"
+ Cell "ModelStepFunctionPrototypeControlCompliant"
+ Cell "GenerateAllocFcn"
+ Cell "PurelyIntegerCode"
+ Cell "SupportComplex"
+ Cell "SupportAbsoluteTime"
+ Cell "SupportContinuousTime"
+ Cell "SupportNonInlinedSFcns"
+ PropName "DisabledProps"
+ }
+ TargetFcnLib "ansi_tfl_table_tmw.mat"
+ TargetLibSuffix ""
+ TargetPreCompLibLocation ""
+ GenFloatMathFcnCalls "NOT IN USE"
+ TargetLangStandard "C89/C90 (ANSI)"
+ CodeReplacementLibrary "None"
+ UtilityFuncGeneration "Auto"
+ ERTMultiwordTypeDef "System defined"
+ ERTMultiwordLength 256
+ MultiwordLength 2048
+ GenerateFullHeader on
+ GenerateSampleERTMain off
+ GenerateTestInterfaces off
+ ModelReferenceCompliant on
+ ParMdlRefBuildCompliant on
+ CompOptLevelCompliant on
+ ConcurrentExecutionCompliant on
+ IncludeMdlTerminateFcn on
+ GeneratePreprocessorConditionals "Disable all"
+ CombineOutputUpdateFcns on
+ CombineSignalStateStructs off
+ SuppressErrorStatus off
+ ERTFirstTimeCompliant off
+ IncludeFileDelimiter "Auto"
+ ERTCustomFileBanners off
+ SupportAbsoluteTime on
+ LogVarNameModifier "rt_"
+ MatFileLogging on
+ MultiInstanceERTCode off
+ CodeInterfacePackaging "Nonreusable function"
+ SupportNonFinite on
+ SupportComplex on
+ PurelyIntegerCode off
+ SupportContinuousTime on
+ SupportNonInlinedSFcns on
+ SupportVariableSizeSignals off
+ EnableShiftOperators on
+ ParenthesesLevel "Nominal"
+ MATLABClassNameForMDSCustomization "Simulink.SoftwareTarget.GRTCustomization"
+ ModelStepFunctionPrototypeControlCompliant off
+ CPPClassGenCompliant on
+ AutosarCompliant off
+ GRTInterface off
+ GenerateAllocFcn off
+ UseMalloc off
+ ExtMode off
+ ExtModeStaticAlloc off
+ ExtModeTesting off
+ ExtModeStaticAllocSize 1000000
+ ExtModeTransport 0
+ ExtModeMexFile "ext_comm"
+ ExtModeIntrfLevel "Level1"
+ RTWCAPISignals off
+ RTWCAPIParams off
+ RTWCAPIStates off
+ RTWCAPIRootIO off
+ GenerateASAP2 off
+ MultiInstanceErrorCode "Error"
+ }
+ PropName "Components"
+ }
+ }
+ hdlcoderui.hdlcc {
+ $ObjectID 18
+ Version "1.14.2"
+ Description "HDL Coder custom configuration component"
+ Name "HDL Coder"
+ Array {
+ Type "Cell"
+ Dimension 1
+ Cell " "
+ PropName "HDLConfigFile"
+ }
+ HDLCActiveTab "0"
+ }
+ PropName "Components"
+ }
+ Name "Configuration"
+ CurrentDlgPage "Solver"
+ ConfigPrmDlgPosition [ 420, 220, 1500, 860 ]
+ }
+ PropName "ConfigurationSets"
+ }
+ Simulink.ConfigSet {
+ $PropName "ActiveConfigurationSet"
+ $ObjectID 7
+ }
+ Object {
+ $PropName "DataTransfer"
+ $ObjectID 19
+ $ClassName "Simulink.GlobalDataTransfer"
+ DefaultTransitionBetweenSyncTasks "Ensure deterministic transfer (maximum delay)"
+ DefaultTransitionBetweenAsyncTasks "Ensure data integrity only"
+ DefaultTransitionBetweenContTasks "Ensure deterministic transfer (minimum delay)"
+ DefaultExtrapolationMethodBetweenContTasks "None"
+ AutoInsertRateTranBlk [0]
+ }
+ ExplicitPartitioning off
+ BlockDefaults {
+ ForegroundColor "black"
+ BackgroundColor "white"
+ DropShadow off
+ NamePlacement "normal"
+ FontName "Helvetica"
+ FontSize 10
+ FontWeight "normal"
+ FontAngle "normal"
+ ShowName on
+ BlockRotation 0
+ BlockMirror off
+ }
+ AnnotationDefaults {
+ HorizontalAlignment "center"
+ VerticalAlignment "middle"
+ ForegroundColor "black"
+ BackgroundColor "white"
+ DropShadow off
+ FontName "Helvetica"
+ FontSize 10
+ FontWeight "normal"
+ FontAngle "normal"
+ UseDisplayTextAsClickCallback off
+ }
+ LineDefaults {
+ FontName "Helvetica"
+ FontSize 9
+ FontWeight "normal"
+ FontAngle "normal"
+ }
+ MaskDefaults {
+ SelfModifiable "off"
+ IconFrame "on"
+ IconOpaque "on"
+ RunInitForIconRedraw "off"
+ IconRotate "none"
+ PortRotate "default"
+ IconUnits "autoscale"
+ }
+ MaskParameterDefaults {
+ Evaluate "on"
+ Tunable "on"
+ NeverSave "off"
+ Internal "off"
+ ReadOnly "off"
+ Enabled "on"
+ Visible "on"
+ ToolTip "on"
+ }
+ BlockParameterDefaults {
+ Block {
+ BlockType Inport
+ Port "1"
+ OutputFunctionCall off
+ OutMin "[]"
+ OutMax "[]"
+ OutDataTypeStr "Inherit: auto"
+ LockScale off
+ BusOutputAsStruct off
+ PortDimensions "-1"
+ VarSizeSig "Inherit"
+ SampleTime "-1"
+ SignalType "auto"
+ SamplingMode "auto"
+ LatchByDelayingOutsideSignal off
+ LatchInputForFeedbackSignals off
+ Interpolate on
+ }
+ Block {
+ BlockType Outport
+ Port "1"
+ OutMin "[]"
+ OutMax "[]"
+ OutDataTypeStr "Inherit: auto"
+ LockScale off
+ BusOutputAsStruct off
+ PortDimensions "-1"
+ VarSizeSig "Inherit"
+ SampleTime "-1"
+ SignalType "auto"
+ SamplingMode "auto"
+ SourceOfInitialOutputValue "Dialog"
+ OutputWhenDisabled "held"
+ InitialOutput "[]"
+ }
+ Block {
+ BlockType S-Function
+ FunctionName "system"
+ SFunctionModules "''"
+ PortCounts "[]"
+ SFunctionDeploymentMode off
+ }
+ Block {
+ BlockType SubSystem
+ ShowPortLabels "FromPortIcon"
+ Permissions "ReadWrite"
+ PermitHierarchicalResolution "All"
+ TreatAsAtomicUnit off
+ MinAlgLoopOccurrences off
+ PropExecContextOutsideSubsystem off
+ CheckFcnCallInpInsideContextMsg off
+ SystemSampleTime "-1"
+ RTWSystemCode "Auto"
+ RTWFcnNameOpts "Auto"
+ RTWFileNameOpts "Auto"
+ FunctionInterfaceSpec "void_void"
+ FunctionWithSeparateData off
+ RTWMemSecFuncInitTerm "Inherit from model"
+ RTWMemSecFuncExecute "Inherit from model"
+ RTWMemSecDataConstants "Inherit from model"
+ RTWMemSecDataInternal "Inherit from model"
+ RTWMemSecDataParameters "Inherit from model"
+ SimViewingDevice off
+ DataTypeOverride "UseLocalSettings"
+ DataTypeOverrideAppliesTo "AllNumericTypes"
+ MinMaxOverflowLogging "UseLocalSettings"
+ Opaque off
+ MaskHideContents off
+ SFBlockType "NONE"
+ Variant off
+ GeneratePreprocessorConditionals off
+ ContentPreviewEnabled off
+ }
+ }
+ System {
+ Name "OpenDiscon_block"
+ Location [750, 130, 1550, 843]
+ Open on
+ ModelBrowserVisibility off
+ ModelBrowserWidth 200
+ ScreenColor "white"
+ PaperOrientation "landscape"
+ PaperPositionMode "auto"
+ PaperType "A4"
+ PaperUnits "centimeters"
+ TiledPaperMargins [1.270000, 1.270000, 1.270000, 1.270000]
+ TiledPageScale 1
+ ShowPageBoundaries off
+ ZoomFactor "100"
+ ReportName "simulink-default.rpt"
+ SIDHighWatermark "17"
+ Block {
+ BlockType SubSystem
+ Name "OpenDiscon"
+ SID "2"
+ Ports [11, 4]
+ Position [105, 101, 440, 499]
+ ZOrder 2
+ RequestExecContextInheritance off
+ System {
+ Name "OpenDiscon"
+ Location [750, 130, 1550, 843]
+ Open off
+ ModelBrowserVisibility off
+ ModelBrowserWidth 200
+ ScreenColor "white"
+ PaperOrientation "landscape"
+ PaperPositionMode "auto"
+ PaperType "A4"
+ PaperUnits "centimeters"
+ TiledPaperMargins [1.270000, 1.270000, 1.270000, 1.270000]
+ TiledPageScale 1
+ ShowPageBoundaries off
+ ZoomFactor "100"
+ Block {
+ BlockType Inport
+ Name "derating ratio [-]"
+ SID "3"
+ Position [20, 38, 50, 52]
+ ZOrder 2
+ IconDisplay "Port number"
+ }
+ Block {
+ BlockType Inport
+ Name "generator speed [rad/s]"
+ SID "4"
+ Position [20, 68, 50, 82]
+ ZOrder 3
+ Port "2"
+ IconDisplay "Port number"
+ }
+ Block {
+ BlockType Inport
+ Name "rotor speed [rad/s]"
+ SID "17"
+ Position [20, 338, 50, 352]
+ ZOrder 16
+ Port "3"
+ IconDisplay "Port number"
+ }
+ Block {
+ BlockType Inport
+ Name "azimuth [deg]"
+ SID "5"
+ Position [20, 98, 50, 112]
+ ZOrder 4
+ Port "4"
+ IconDisplay "Port number"
+ }
+ Block {
+ BlockType Inport
+ Name "yaw error [deg]"
+ SID "6"
+ Position [20, 128, 50, 142]
+ ZOrder 5
+ Port "5"
+ IconDisplay "Port number"
+ }
+ Block {
+ BlockType Inport
+ Name "blade 1 root Mx [kNm]"
+ SID "7"
+ Position [20, 158, 50, 172]
+ ZOrder 6
+ Port "6"
+ IconDisplay "Port number"
+ }
+ Block {
+ BlockType Inport
+ Name "blade 1 root My [kNm]"
+ SID "8"
+ Position [20, 188, 50, 202]
+ ZOrder 7
+ Port "7"
+ IconDisplay "Port number"
+ }
+ Block {
+ BlockType Inport
+ Name "blade 2 root Mx [kNm]"
+ SID "9"
+ Position [20, 218, 50, 232]
+ ZOrder 8
+ Port "8"
+ IconDisplay "Port number"
+ }
+ Block {
+ BlockType Inport
+ Name "blade 2 root My [kNm]"
+ SID "10"
+ Position [20, 248, 50, 262]
+ ZOrder 9
+ Port "9"
+ IconDisplay "Port number"
+ }
+ Block {
+ BlockType Inport
+ Name "blade 3 root Mx [kNm]"
+ SID "11"
+ Position [20, 278, 50, 292]
+ ZOrder 10
+ Port "10"
+ IconDisplay "Port number"
+ }
+ Block {
+ BlockType Inport
+ Name "blade 3 root My [kNm]"
+ SID "12"
+ Position [20, 308, 50, 322]
+ ZOrder 11
+ Port "11"
+ IconDisplay "Port number"
+ }
+ Block {
+ BlockType S-Function
+ Name "S-Function"
+ SID "1"
+ Ports [11, 4]
+ Position [165, 20, 305, 370]
+ ZOrder 1
+ FunctionName "OpenDiscon"
+ EnableBusSupport off
+ }
+ Block {
+ BlockType Outport
+ Name "generator torque demand [kNm]"
+ SID "13"
+ Position [395, 63, 425, 77]
+ ZOrder 12
+ IconDisplay "Port number"
+ }
+ Block {
+ BlockType Outport
+ Name "blade 1 pitch demand [deg]"
+ SID "14"
+ Position [395, 148, 425, 162]
+ ZOrder 13
+ Port "2"
+ IconDisplay "Port number"
+ }
+ Block {
+ BlockType Outport
+ Name "blade 2 pitch demand [deg]"
+ SID "15"
+ Position [395, 233, 425, 247]
+ ZOrder 14
+ Port "3"
+ IconDisplay "Port number"
+ }
+ Block {
+ BlockType Outport
+ Name "blade 3 pitch demand [deg]"
+ SID "16"
+ Position [395, 318, 425, 332]
+ ZOrder 15
+ Port "4"
+ IconDisplay "Port number"
+ }
+ Line {
+ ZOrder 15
+ SrcBlock "derating ratio [-]"
+ SrcPort 1
+ Points [95, 0]
+ DstBlock "S-Function"
+ DstPort 1
+ }
+ Line {
+ ZOrder 17
+ SrcBlock "azimuth [deg]"
+ SrcPort 1
+ Points [95, 0]
+ DstBlock "S-Function"
+ DstPort 3
+ }
+ Line {
+ ZOrder 22
+ SrcBlock "blade 2 root My [kNm]"
+ SrcPort 1
+ Points [95, 0]
+ DstBlock "S-Function"
+ DstPort 8
+ }
+ Line {
+ ZOrder 23
+ SrcBlock "blade 3 root Mx [kNm]"
+ SrcPort 1
+ DstBlock "S-Function"
+ DstPort 9
+ }
+ Line {
+ ZOrder 18
+ SrcBlock "yaw error [deg]"
+ SrcPort 1
+ Points [95, 0]
+ DstBlock "S-Function"
+ DstPort 4
+ }
+ Line {
+ ZOrder 19
+ SrcBlock "blade 1 root Mx [kNm]"
+ SrcPort 1
+ Points [95, 0]
+ DstBlock "S-Function"
+ DstPort 5
+ }
+ Line {
+ ZOrder 20
+ SrcBlock "blade 1 root My [kNm]"
+ SrcPort 1
+ Points [95, 0]
+ DstBlock "S-Function"
+ DstPort 6
+ }
+ Line {
+ ZOrder 21
+ SrcBlock "blade 2 root Mx [kNm]"
+ SrcPort 1
+ Points [95, 0]
+ DstBlock "S-Function"
+ DstPort 7
+ }
+ Line {
+ ZOrder 16
+ SrcBlock "generator speed [rad/s]"
+ SrcPort 1
+ Points [95, 0]
+ DstBlock "S-Function"
+ DstPort 2
+ }
+ Line {
+ ZOrder 28
+ SrcBlock "S-Function"
+ SrcPort 4
+ DstBlock "blade 3 pitch demand [deg]"
+ DstPort 1
+ }
+ Line {
+ ZOrder 27
+ SrcBlock "S-Function"
+ SrcPort 3
+ DstBlock "blade 2 pitch demand [deg]"
+ DstPort 1
+ }
+ Line {
+ ZOrder 26
+ SrcBlock "S-Function"
+ SrcPort 2
+ DstBlock "blade 1 pitch demand [deg]"
+ DstPort 1
+ }
+ Line {
+ ZOrder 29
+ SrcBlock "S-Function"
+ SrcPort 1
+ DstBlock "generator torque demand [kNm]"
+ DstPort 1
+ }
+ Line {
+ ZOrder 35
+ SrcBlock "blade 3 root My [kNm]"
+ SrcPort 1
+ DstBlock "S-Function"
+ DstPort 10
+ }
+ Line {
+ ZOrder 36
+ SrcBlock "rotor speed [rad/s]"
+ SrcPort 1
+ DstBlock "S-Function"
+ DstPort 11
+ }
+ }
+ }
+ }
+}
diff --git a/CONFIGURATION/CL-Windcon/src/sfunc/makeOpenDiscon.m b/CONFIGURATION/CL-Windcon/src/sfunc/makeOpenDiscon.m
new file mode 100644
index 0000000..15c87bc
--- /dev/null
+++ b/CONFIGURATION/CL-Windcon/src/sfunc/makeOpenDiscon.m
@@ -0,0 +1,3 @@
+function makeOpenDiscon
+
+mex -output OpenDiscon -I${OPENWITCON_INCLUDE_DIRS} -I${OPENDISCON_INCLUDE_DIRS} ${OPENWITCON_SOURCES} ${OPENDISCON_SOURCES}
diff --git a/CONFIGURATION/CL-Windcon/src/sfunc/sfunc.c b/CONFIGURATION/CL-Windcon/src/sfunc/sfunc.c
new file mode 100644
index 0000000..67969c9
--- /dev/null
+++ b/CONFIGURATION/CL-Windcon/src/sfunc/sfunc.c
@@ -0,0 +1,1612 @@
+/*
+Copyright (C) 2015-2017 IK4-IKERLAN
+
+This file is part of OpenDiscon.
+
+OpenDiscon is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+OpenDiscon is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with OpenDiscon. If not, see .
+*/
+
+/*
+ * This file is based on the following template:
+ * File: sfuntmpl_doc.c
+ * Abstract:
+ * A 'C' template for a level 2 S-function.
+ *
+ * See sfuntmpl_basic.c
+ * for a basic C-MEX template file that uses the
+ * most common methods.
+ *
+ * Copyright 1990-2013 The MathWorks, Inc.
+ */
+
+
+/*
+ * You must specify the S_FUNCTION_NAME as the name of your S-function.
+ */
+
+#define S_FUNCTION_NAME OpenDiscon
+#define S_FUNCTION_LEVEL 2
+
+#include "ikClwindconWTConfig.h"
+
+/*
+ * Need to include simstruc.h for the definition of the SimStruct and
+ * its associated macro definitions.
+ *
+ * The following headers are included by matlabroot/simulink/include/simstruc.h
+ * when compiling as a MEX file:
+ *
+ * matlabroot/extern/include/tmwtypes.h - General types, e.g. real_T
+ * matlabroot/extern/include/mex.h - MATLAB MEX file API routines
+ * matlabroot/extern/include/matrix.h - MATLAB MEX file API routines
+ *
+ * The following headers are included by matlabroot/simulink/include/simstruc.h
+ * when compiling your S-function with RTW:
+ *
+ * matlabroot/extern/include/tmwtypes.h - General types, e.g. real_T
+ * matlabroot/rtw/c/libsrc/rt_matrx.h - Macros for MATLAB API routines
+ *
+ */
+#include "simstruc.h"
+
+
+/* Error handling
+ * --------------
+ *
+ * You should use the following technique to report errors encountered within
+ * an S-function:
+ *
+ * ssSetErrorStatus(S,"error encountered due to ...");
+ * return;
+ *
+ * Note that the 2nd argument to ssSetErrorStatus must be persistent memory.
+ * It cannot be a local variable in your procedure. For example the following
+ * will cause unpredictable errors:
+ *
+ * mdlOutputs()
+ * {
+ * char msg[256]; {ILLEGAL: to fix use "static char msg[256];"}
+ * sprintf(msg,"Error due to %s", string);
+ * ssSetErrorStatus(S,msg);
+ * return;
+ * }
+ *
+ * The ssSetErrorStatus error handling approach is the suggested alternative
+ * to using the mexErrMsgTxt function. MexErrMsgTxt uses "exception handling"
+ * to immediately terminate S-function execution and return control to
+ * Simulink. In order to support exception handling inside of S-functions,
+ * Simulink must setup exception handlers prior to each S-function invocation.
+ * This introduces overhead into simulation.
+ *
+ * If you do not call mexErrMsgTxt or any other routines that cause exceptions,
+ * then you should use SS_OPTION_EXCEPTION_FREE_CODE S-function option. This
+ * is done by issuing the following command in the mdlInitializeSizes function:
+ *
+ * ssSetOptions(S, SS_OPTION_EXCEPTION_FREE_CODE);
+ *
+ * Setting this option, will increase the performance of your S-function by
+ * allowing Simulink to bypass the exception handling setup that is usually
+ * performed prior to each S-function invocation. Extreme care must be taken
+ * to verify that your code is exception free when using the
+ * SS_OPTION_EXCEPTION_FREE_CODE option. If your S-function generates
+ * an exception when this option is set, unpredictable results will occur.
+ *
+ * Exception free code refers to code which never "long jumps". Your S-function
+ * is not exception free if it contains any routine which when called has
+ * the potential of long jumping. For example mexErrMsgTxt throws an exception
+ * (i.e. long jumps) when called, thus ending execution of your S-function.
+ * Use of mxCalloc may cause unpredictable problems in the event of a memory
+ * allocation error since mxCalloc will long jump. If memory allocation is
+ * needed, you should use the stdlib.h calloc routine directly and perform
+ * your own error handling.
+ *
+ * All mex* routines have the potential of long jumping (i.e. throwing an
+ * exception). In addition several mx* routines have the potential of
+ * long jumping. To avoid any difficulties, only the routines which get
+ * a pointer or determine the size of parameters should be used. For example
+ * the following will never throw an exception: mxGetPr, mxGetData,
+ * mxGetNumberOfDimensions, mxGetM, mxGetN, mxGetNumberOfElements.
+ *
+ * If all of your "run-time" methods within your S-function are exception
+ * free, then you can use the option:
+ * ssSetOptions(S, SS_OPTION_RUNTIME_EXCEPTION_FREE_CODE);
+ * The other methods in your S-function need not be exception free. The
+ * run-time methods include any of the following:
+ * mdlGetTimeOfNextVarHit, mdlOutputs, mdlUpdate, and mdlDerivatives
+ *
+ * Warnings & Printf's
+ * -------------------
+ * You can use ssWarning(S,msg) to display a warning.
+ * - When the S-function is compiled via mex for use with Simulink,
+ * ssWarning equates to mexWarnMsgTxt.
+ * - When the S-function is used with Real-Time Workshop,
+ * ssWarning(S,msg) equates to
+ * printf("Warning: in block '%s', '%s'\n", ssGetPath(S),msg);
+ * if the target has stdio facilities, otherwise it becomes a comment and
+ * is disabled.
+ *
+ * You can use ssPrintf(fmt, ...) to print a message.
+ * - When the S-function is compiled via mex for use with Simulink,
+ * ssPrintf equates to mexPrintf.
+ * - When the S-function is used with Real-Time Workshop,
+ * ssPrintf equates to printf, if the target has stdio facilities,
+ * otherwise it becomes a call to a empty function (rtPrintfNoOp).
+ * - In the case of Real-Time Workshop which may or may not have stdio
+ * facilities, to generate the most efficient code use:
+ * #if defined(SS_STDIO_AVAILABLE)
+ * ssPrintf("my message ...");
+ * #endif
+ * - You can also use this technique to do other standard I/O related items,
+ * such as:
+ * #if defined(SS_STDIO_AVAILABLE)
+ * if ((fp=fopen(file,"w")) == NULL) {
+ * ssSetErrorStatus(S,"open failed");
+ * return;
+ * }
+ * ...
+ * #endif
+ */
+
+/*====================*
+ * S-function methods *
+ *====================*/
+
+/*
+ * Level 2 S-function methods
+ * --------------------------
+ * Notation: "=>" indicates method is required.
+ * [method] indicates method is optional.
+ *
+ * Note, many of the methods below are only available for use in level 2
+ * C-MEX S-functions.
+ *
+ * Model Initialization in Simulink
+ * --------------------------------
+ *=> mdlInitializeSizes - Initialize SimStruct sizes array
+ *
+ * [mdlSetInputPortFrameData] - Optional method. Check and set input and
+ * output port frame data attributes.
+ *
+ * NOTE: An S-function cannot use mdlSetInput(Output)PortWidth and
+ * mdlSetInput(Output)PortDimensionInfo at the same time. It can use
+ * either a width or dimension method, but not both.
+ *
+ * [mdlSetInputPortWidth] - Optional method. Check and set input and
+ * optionally other port widths.
+ * [mdlSetOutputPortWidth] - Optional method. Check and set output
+ * and optionally other port widths.
+ *
+ * [mdlSetInputPortDimensionInfo]
+ * - Optional method. Check and set input and
+ * optionally other port dimensions.
+ * [mdlSetOutputPortDimensionInfo]
+ * - Optional method. Check and set output
+ * and optionally other port dimensions.
+ * [mdlSetDefaultPortDimensionInfo]
+ * - Optional method. Set dimensions of all
+ * input and output ports that have unknown
+ * dimensions.
+ *
+ * [mdlSetInputPortSampleTime] - Optional method. Check and set input
+ * port sample time and optionally other port
+ * sample times.
+ * [mdlSetOutputPortSampleTime]- Optional method. Check and set output
+ * port sample time and optionally other port
+ * sample times.
+ *=> mdlInitializeSampleTimes - Initialize sample times and optionally
+ * function-call connections.
+ *
+ * [mdlSetInputPortDataType] - Optional method. Check and set input port
+ * data type. See SS_DOUBLE to SS_BOOLEAN in
+ * simstruc_types.h for built-in data types.
+ * [mdlSetOutputPortDataType] - Optional method. Check and set output port
+ * data type. See SS_DOUBLE to SS_BOOLEAN in
+ * simstruc_types.h for built-in data types.
+ * [mdlSetDefaultPortDataTypes] - Optional method. Set data types of all
+ * dynamically typed input and output ports.
+ *
+ * [mdlInputPortComplexSignal] - Optional method. Check and set input
+ * port complexity attribute (COMPLEX_YES,
+ * COMPLEX_NO).
+ * [mdlOutputPortComplexSignal] - Optional method. Check and set output
+ * port complexity attribute (COMPLEX_YES,
+ * COMPLEX_NO).
+ * [mdlSetDefaultPortComplexSignals]
+ * - Optional method. Set complex signal flags
+ * of all input and output ports who
+ * have their complex signals set to
+ * COMPLEX_INHERITED (dynamic complexity).
+ *
+ * [mdlSetWorkWidths] - Optional method. Set the state, iwork,
+ * rwork, pwork, dwork, etc sizes.
+ *
+ * [mdlStart] - Optional method. Perform actions such
+ * as allocating memory and attaching to pwork
+ * elements.
+ *
+ * [mdlInitializeConditions] - Initialize model parameters (usually
+ * states). Will not be called if your
+ * S-function does not have an initialize
+ * conditions method.
+ *
+ * ['constant' mdlOutputs] - Execute blocks with constant sample
+ * times. These are only executed once
+ * here.
+ *
+ * [mdlSetSimState] - Optional method. Load the complete simulation
+ * state for this block, which is called when
+ * starting the simulation from an initial
+ * simulation state and this s-function has set
+ * its ssSetSimStateCompliance to
+ * USE_CUSTOM_SIM_STATE. See also mdlGetSimState
+ *
+ * Model simulation loop in Simulink
+ * ---------------------------------
+ * [mdlCheckParameters] - Optional method. Will be called at
+ * any time during the simulation loop when
+ * parameters change.
+ * SimulationLoop:
+ * [mdlProcessParameters] - Optional method. Called during
+ * simulation after parameters have been
+ * changed and verified to be okay by
+ * mdlCheckParameters. The processing is
+ * done at the "top" of the simulation loop
+ * when it is safe to process the changed
+ * parameters.
+ * [mdlGetTimeOfNextVarHit] - Optional method. If your S-function
+ * has a variable step sample time, then
+ * this method will be called.
+ * [mdlInitializeConditions]- Optional method. Only called if your
+ * S-function resides in an enabled
+ * subsystem configured to reset states,
+ * and the subsystem has just enabled.
+ * => mdlOutputs - Major output call (usually updates
+ * output signals).
+ * [mdlUpdate] - Update the discrete states, etc.
+ *
+ * Integration (Minor time step)
+ * [mdlDerivatives] - Compute the derivatives.
+ * Do
+ * [mdlOutputs]
+ * [mdlDerivatives]
+ * EndDo - number of iterations depends on solver
+ * Do
+ * [mdlOutputs]
+ * [mdlZeroCrossings]
+ * EndDo - number of iterations depends on zero crossings signals
+ * EndIntegration
+ *
+ * EndSimulationLoop
+ *
+ * [mdlGetSimState] - Optional method. Called to get the complete simulation
+ * state for this block if the model is configured to
+ * save its final simulation state and this
+ * S-Function has set its ssSetSimStateCompliance to
+ * USE_CUSTOM_SIM_STATE. See also mdlSetSimState
+ *
+ * => mdlTerminate - End of model housekeeping - free memory, etc.
+ *
+ * Model initialization for code generation (rtwgen)
+ * -------------------------------------------------
+ *
+ *
+ * [mdlRTW] - Optional method. Only called when
+ * generating code to add information to the
+ * model.rtw file which is used by the
+ * Real-Time Workshop.
+ *
+ * mdlTerminate - End of model housekeeping - free memory,
+ * etc.
+ *
+ * Noninlined S-function execution in Real-Time Workshop
+ * -----------------------------------------------------
+ * 1) The results of most initialization methods are 'compiled' into
+ * the generated code and many methods are not called.
+ * 2) Noninlined S-functions are limited in several ways, for example
+ * parameter must be real (non-complex) double vectors or strings. More
+ * capability is provided via the Target Language Compiler. See the
+ * Target Language Compiler Reference Guide.
+ *
+ * => mdlInitializeSizes - Initialize SimStruct sizes array
+ * => mdlInitializeSampleTimes - Initialize sample times and optionally
+ * function-call connections.
+ * [mdlInitializeConditions] - Initialize model parameters (usually
+ * states). Will not be called if your
+ * S-function does not have an initialize
+ * conditions method.
+ * [mdlStart] - Optional method. Perform actions such
+ * as allocating memory and attaching to pwork
+ * elements.
+ * ExecutionLoop:
+ * => mdlOutputs - Major output call (usually updates
+ * output signals).
+ * [mdlUpdate] - Update the discrete states, etc.
+ *
+ * Integration (Minor time step)
+ * [mdlDerivatives] - Compute the derivatives.
+ * Do
+ * [mdlOutputs]
+ * [mdlDerivatives]
+ * EndDo - number of iterations depends on solver
+ * Do
+ * [mdlOutputs]
+ * [mdlZeroCrossings]
+ * EndDo - number of iterations depends on zero crossings signals
+ * EndExecutionLoop
+ * mdlTerminate - End of model housekeeping - free memory,
+ * etc.
+ */
+
+
+/*====================================================================*
+ * Parameter handling methods. These methods are not supported by RTW *
+ *====================================================================*/
+
+#define MDL_CHECK_PARAMETERS /* Change to #undef to remove function */
+#if defined(MDL_CHECK_PARAMETERS) && defined(MATLAB_MEX_FILE)
+ /* Function: mdlCheckParameters =============================================
+ * Abstract:
+ * mdlCheckParameters verifies new parameter settings whenever parameter
+ * change or are re-evaluated during a simulation. When a simulation is
+ * running, changes to S-function parameters can occur at any time during
+ * the simulation loop.
+ *
+ * This method can be called at any point after mdlInitializeSizes.
+ * You should add a call to this method from mdlInitalizeSizes
+ * to check the parameters. After setting the number of parameters
+ * you expect in your S-function via ssSetNumSFcnParams(S,n), you should:
+ * #if defined(MATLAB_MEX_FILE)
+ * if (ssGetNumSFcnParams(S) == ssGetSFcnParamsCount(S)) {
+ * mdlCheckParameters(S);
+ * if (ssGetErrorStatus(S) != NULL) return;
+ * } else {
+ * return; Simulink will report a parameter mismatch error
+ * }
+ * #endif
+ *
+ * When a Simulation is running, changes to S-function parameters can
+ * occur either at the start of a simulation step, or during a
+ * simulation step. When changes to S-function parameters occur during
+ * a simulation step, this method is called twice, for the same
+ * parameter changes. The first call during the simulation step is
+ * used to verify that the parameters are correct. After verifying the
+ * new parameters, the simulation continues using the original
+ * parameter values until the next simulation step at which time the
+ * new parameter values will be used. Redundant calls are needed to
+ * maintain simulation consistency. Note that you cannot access the
+ * work, state, input, output, etc. vectors in this method. This
+ * method should only be used to validate the parameters. Processing
+ * of the parameters should be done in mdlProcessParameters.
+ *
+ * See matlabroot/simulink/src/sfun_errhdl.c for an example.
+ */
+ static void mdlCheckParameters(SimStruct *S)
+ {
+ }
+#endif /* MDL_CHECK_PARAMETERS */
+
+
+#define MDL_PROCESS_PARAMETERS /* Change to #undef to remove function */
+#if defined(MDL_PROCESS_PARAMETERS) && defined(MATLAB_MEX_FILE)
+ /* Function: mdlProcessParameters ===========================================
+ * Abstract:
+ * This method will be called after mdlCheckParameters, whenever
+ * parameters change or get re-evaluated. The purpose of this method is
+ * to process the newly changed parameters. For example "caching" the
+ * parameter changes in the work vectors. Note this method is not
+ * called when it is used with the Real-Time Workshop. Therefore,
+ * if you use this method in an S-function which is being used with the
+ * Real-Time Workshop, you must write your S-function such that it doesn't
+ * rely on this method. This can be done by inlining your S-function
+ * via the Target Language Compiler.
+ */
+ static void mdlProcessParameters(SimStruct *S)
+ {
+ }
+#endif /* MDL_PROCESS_PARAMETERS */
+
+
+
+/*=====================================*
+ * Configuration and execution methods *
+ *=====================================*/
+
+/* Function: mdlInitializeSizes ===============================================
+ * Abstract:
+ * The sizes information is used by Simulink to determine the S-function
+ * block's characteristics (number of inputs, outputs, states, etc.).
+ *
+ * Direct Feedthough:
+ * The direct feedthrough flag can be either 1=yes or 0=no. It should be
+ * set to 1 if the input, "u", is used in the mdlOutput or
+ * mdlGetTimeOfNextVarHit() function. Setting this to 0 is akin to making
+ * a promise that "u" will not be used in the mdlOutput or
+ * mdlGetTimeOfNextVarHit() function. If you break the promise, then
+ * unpredictable results will occur.
+ *
+ * It is very common for S-function authors to write incorrect S-functions
+ * when configuring the S-function direct feedthrough flag. We often find
+ * that S-function authors are confused about what the correct setting for
+ * the direct feedthrough flag should be. Part of the confusion is because
+ * the term direct feedthrough is misleading. To reduce the confusion, you
+ * can think of the direct feedthrough setting as a 'needs input'
+ * setting. Specifically, if the S-function access an input signal in
+ * either mdlOutputs() or mdlGetTimeOfNextVarHit(), then the direct
+ * feedthrough flag must be set to 1 (true).
+ *
+ * For example, if a level 2 C-MEX S-function uses:
+ * ssGetInputPortSignal(S,inputPortIndex)
+ * in its mdlOutputs() or mdlGetTimeOfNextVarHit() methods, then the
+ * S-function is required to set the direct feedthrough flag to true in
+ * its mdlInitializeSizes() method:
+ * ssSetInputPortDirectFeedThrough(S, inputPortIdx, 1);
+ *
+ * If your S-Function uses ssGetInputPortSignal() in mdlOutputs() or
+ * mdlGetTimeOfNextVarHit() and fails to specify
+ * the direct feedthrough, or specifes it wrongly using
+ * ssSetInputPortDirectFeedThrough(S, inputPortIdx, 0);
+ * then the S-Function is incorreclty written and Simulink will not
+ * operate correctly and may crash.
+ *
+ * When you compile your S-function with debugging, e.g.,
+ * mex -g sfunction_name.c
+ * your S-function will be instrumented such that an incorrect access to
+ * an input signal will generate a diagnostic message.
+ *
+ * The NumContStates, NumDiscStates, NumInputs, NumOutputs, NumRWork,
+ * NumIWork, NumPWork NumModes, and NumNonsampledZCs widths can be set to:
+ * DYNAMICALLY_SIZED - In this case, they will be set to the actual
+ * input width, unless you have a mdlSetWorkWidths
+ * to set the widths.
+ * 0 or positive number - This explicitly sets item to the specified
+ * value.
+ */
+static void mdlInitializeSizes(SimStruct *S)
+{
+ /*
+ * inputs are:
+ * 0 - derating ratio [-]
+ * 1 - generator speed [rad/s]
+ * 2 - azimuth [deg]
+ * 3 - yaw error [deg]
+ * 4 - blade 1 root Mx [kNm]
+ * 5 - blade 1 root My [kNm]
+ * 6 - blade 2 root Mx [kNm]
+ * 7 - blade 2 root My [kNm]
+ * 8 - blade 3 root Mx [kNm]
+ * 9 - blade 3 root My [kNm]
+ * 10 - rotor speed [rad/s]
+ *
+ * outputs are:
+ * 0 - generator torque demand [kNm]
+ * 1 - blade 1 pitch demand [deg]
+ * 2 - blade 2 pitch demand [deg]
+ * 3 - blade 3 pitch demand [deg]
+ */
+ int_T nInputPorts = 11; /* number of input ports */
+ int_T nOutputPorts = 4; /* number of output ports */
+ int_T needsInput = 1; /* direct feed through */
+
+ int_T inputPortIdx = 0;
+ int_T outputPortIdx = 0;
+
+
+ ssSetNumSFcnParams(S, 0); /* Number of expected parameters */
+ if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) {
+ /*
+ * If the the number of expected input parameters is not equal
+ * to the number of parameters entered in the dialog box return.
+ * Simulink will generate an error indicating that there is a
+ * parameter mismatch.
+ */
+ return;
+ }
+
+ /*
+ * Configure tunability of parameters. By default, all parameters are
+ * tunable (changeable) during simulation. If there are parameters that
+ * cannot change during simulation, such as any parameters that would change
+ * the number of ports on the block, the sample time of the block, or the
+ * data type of a signal, mark these as non-tunable using a call like this:
+ *
+ * ssSetSFcnParamTunable(S, 0, 0);
+ *
+ * which sets parameter 0 to be non-tunable (0).
+ *
+ */
+
+
+ /* Register the number and type of states the S-Function uses */
+
+ ssSetNumContStates( S, 0); /* number of continuous states */
+ ssSetNumDiscStates( S, 0); /* number of discrete states */
+
+
+ /*
+ * Configure the input ports. First set the number of input ports.
+ */
+ if (!ssSetNumInputPorts(S, nInputPorts)) return;
+ /*
+ * Set input port dimensions for each input port index starting at 0.
+ * The following options summarize different ways for setting the input
+ * port dimensions.
+ *
+ * (1) If the input port dimensions are unknown, use
+ * ssSetInputPortDimensionInfo(S, inputPortIdx, DYNAMIC_DIMENSION))
+ *
+ * (2) If the input signal is an unoriented vector, and the input port
+ * width is w, use
+ * ssSetInputPortVectorDimension(S, inputPortIdx, w)
+ * w (or width) can be DYNAMICALLY_SIZED or greater than 0.
+ * This is equivalent to ssSetInputPortWidth(S, inputPortIdx, w).
+ *
+ * (3) If the input signal is a matrix of dimension mxn, use
+ * ssSetInputPortMatrixDimensions(S, inputPortIdx, m, n)
+ * m and n can be DYNAMICALLY_SIZED or greater than zero.
+ *
+ * (4) Otherwise use:
+ * ssSetInputPortDimensionInfo(S, inputPortIdx, dimsInfo)
+ * This function can be used to fully or partially initialize the port
+ * dimensions. dimsInfo is a structure containing width, number of
+ * dimensions, and dimensions of the port.
+ */
+ for (inputPortIdx = 0; inputPortIdx < nInputPorts; inputPortIdx++)
+ if(!ssSetInputPortVectorDimension(S, inputPortIdx, 1)) return;
+ /*
+ * Set direct feedthrough flag (1=yes, 0=no).
+ * A port has direct feedthrough if the input is used in either
+ * the mdlOutputs or mdlGetTimeOfNextVarHit functions.
+ * See sfuntmpl_directfeed.txt.
+ */
+ for (inputPortIdx = 0; inputPortIdx < nInputPorts; inputPortIdx++)
+ ssSetInputPortDirectFeedThrough(S, inputPortIdx, needsInput);
+
+ /*
+ * Configure the output ports. First set the number of output ports.
+ */
+ if (!ssSetNumOutputPorts(S, nOutputPorts)) return;
+
+ /*
+ * Set output port dimensions for each output port index starting at 0.
+ * See comments for setting input port dimensions.
+ */
+ for(outputPortIdx = 0; outputPortIdx < nOutputPorts; outputPortIdx++)
+ if(!ssSetOutputPortVectorDimension(S,outputPortIdx,1)) return;
+
+ /*
+ * Set the number of sample times. This must be a positive, nonzero
+ * integer indicating the number of sample times or it can be
+ * PORT_BASED_SAMPLE_TIMES. For multi-rate S-functions, the
+ * suggested approach to setting sample times is via the port
+ * based sample times method. When you create a multirate
+ * S-function, care needs to be taking to verify that when
+ * slower tasks are preempted that your S-function correctly
+ * manages data as to avoid race conditions. When port based
+ * sample times are specified, the block cannot inherit a constant
+ * sample time at any port.
+ */
+ ssSetNumSampleTimes( S, 1); /* number of sample times */
+
+ /*
+ * Set size of the work vectors.
+ */
+ ssSetNumRWork( S, 0); /* number of real work vector elements */
+ ssSetNumIWork( S, 0); /* number of integer work vector elements*/
+ ssSetNumPWork( S, 1); /* number of pointer work vector elements*/
+ ssSetNumModes( S, 0); /* number of mode work vector elements */
+ ssSetNumNonsampledZCs( S, 0); /* number of nonsampled zero crossings */
+
+ /* Specify the sim state compliance to be same as a built-in block */
+ /* see sfun_simstate.c for example of other possible settings */
+ ssSetSimStateCompliance(S, USE_DEFAULT_SIM_STATE);
+
+ /*
+ * All options have the form SS_OPTION_ and are documented in
+ * matlabroot/simulink/include/simstruc.h. The options should be
+ * bitwise or'd together as in
+ * ssSetOptions(S, (SS_OPTION_name1 | SS_OPTION_name2))
+ */
+
+ ssSetOptions( S, 0); /* general options (SS_OPTION_xx) */
+
+} /* end mdlInitializeSizes */
+
+
+#define MDL_SET_INPUT_PORT_FRAME_DATA /* Change to #undef to remove function */
+#if defined(MDL_SET_INPUT_PORT_FRAME_DATA) && defined(MATLAB_MEX_FILE)
+ /* Function: mdlSetInputPortFrameData ========================================
+ * Abstract:
+ * This method is called with the candidate frame setting (FRAME_YES, or
+ * FRAME_NO) for an input port. If the proposed setting is acceptable,
+ * the method should go ahead and set the actual frame data setting using
+ * ssSetInputPortFrameData(S,portIndex,frameData). If
+ * the setting is unacceptable an error should be generated via
+ * ssSetErrorStatus. Note that any other dynamic frame input or
+ * output ports whose frame data setting are implicitly defined by virtue
+ * of knowing the frame data setting of the given port can also have their
+ * frame data settings set via calls to ssSetInputPortFrameData and
+ * ssSetOutputPortFrameData.
+ */
+ static void mdlSetInputPortFrameData(SimStruct *S,
+ int portIndex,
+ Frame_T frameData)
+ {
+ } /* end mdlSetInputPortFrameData */
+#endif /* MDL_SET_INPUT_PORT_FRAME_DATA */
+
+
+#define MDL_SET_INPUT_PORT_WIDTH /* Change to #undef to remove function */
+#if defined(MDL_SET_INPUT_PORT_WIDTH) && defined(MATLAB_MEX_FILE)
+ /* Function: mdlSetInputPortWidth ===========================================
+ * Abstract:
+ * This method is called with the candidate width for a dynamically
+ * sized port. If the proposed width is acceptable, the method should
+ * go ahead and set the actual port width using ssSetInputPortWidth. If
+ * the size is unacceptable an error should generated via
+ * ssSetErrorStatus. Note that any other dynamically sized input or
+ * output ports whose widths are implicitly defined by virtue of knowing
+ * the width of the given port can also have their widths set via calls
+ * to ssSetInputPortWidth or ssSetOutputPortWidth.
+ */
+ static void mdlSetInputPortWidth(SimStruct *S, int portIndex, int width)
+ {
+ } /* end mdlSetInputPortWidth */
+#endif /* MDL_SET_INPUT_PORT_WIDTH */
+
+
+#define MDL_SET_OUTPUT_PORT_WIDTH /* Change to #undef to remove function */
+#if defined(MDL_SET_OUTPUT_PORT_WIDTH) && defined(MATLAB_MEX_FILE)
+ /* Function: mdlSetOutputPortWidth ==========================================
+ * Abstract:
+ * This method is called with the candidate width for a dynamically
+ * sized port. If the proposed width is acceptable, the method should
+ * go ahead and set the actual port width using ssSetOutputPortWidth. If
+ * the size is unacceptable an error should generated via
+ * ssSetErrorStatus. Note that any other dynamically sized input or
+ * output ports whose widths are implicitly defined by virtue of knowing
+ * the width of the given port can also have their widths set via calls
+ * to ssSetInputPortWidth or ssSetOutputPortWidth.
+ */
+ static void mdlSetOutputPortWidth(SimStruct *S, int portIndex, int width)
+ {
+ } /* end mdlSetOutputPortWidth */
+#endif /* MDL_SET_OUTPUT_PORT_WIDTH */
+
+
+#undef MDL_SET_INPUT_PORT_DIMENSION_INFO /* Change to #define to add function */
+#if defined(MDL_SET_INPUT_PORT_DIMENSION_INFO) && defined(MATLAB_MEX_FILE)
+ /* Function: mdlSetInputPortDimensionInfo ====================================
+ * Abstract:
+ * This method is called with the candidate dimensions for an input port
+ * with unknown dimensions. If the proposed dimensions are acceptable, the
+ * method should go ahead and set the actual port dimensions.
+ * If they are unacceptable an error should be generated via
+ * ssSetErrorStatus.
+ * Note that any other input or output ports whose dimensions are
+ * implicitly defined by virtue of knowing the dimensions of the given
+ * port can also have their dimensions set.
+ *
+ * See matlabroot/simulink/src/sfun_matadd.c for an example.
+ */
+ static void mdlSetInputPortDimensionInfo(SimStruct *S,
+ int_T portIndex,
+ const DimsInfo_T *dimsInfo)
+ {
+ } /* mdlSetInputPortDimensionInfo */
+#endif /* MDL_SET_INPUT_PORT_DIMENSION_INFO */
+
+
+#undef MDL_SET_OUTPUT_PORT_DIMENSION_INFO /* Change to #define to add function*/
+#if defined(MDL_SET_OUTPUT_PORT_DIMENSION_INFO) && defined(MATLAB_MEX_FILE)
+ /* Function: mdlSetOutputPortDimensionInfo ===================================
+ * Abstract:
+ * This method is called with the candidate dimensions for an output port
+ * with unknown dimensions. If the proposed dimensions are acceptable, the
+ * method should go ahead and set the actual port dimensions.
+ * If they are unacceptable an error should be generated via
+ * ssSetErrorStatus.
+ * Note that any other input or output ports whose dimensions are
+ * implicitly defined by virtue of knowing the dimensions of the given
+ * port can also have their dimensions set.
+ *
+ * See matlabroot/simulink/src/sfun_matadd.c for an example.
+ */
+ static void mdlSetOutputPortDimensionInfo(SimStruct *S,
+ int_T portIndex,
+ const DimsInfo_T *dimsInfo)
+ {
+ } /* mdlSetOutputPortDimensionInfo */
+#endif /* MDL_SET_OUTPUT_PORT_DIMENSION_INFO */
+
+
+#undef MDL_SET_DEFAULT_PORT_DIMENSION_INFO /* Change to #define to add fcn */
+#if defined(MDL_SET_DEFAULT_PORT_DIMENSION_INFO) && defined(MATLAB_MEX_FILE)
+ /* Function: mdlSetDefaultPortDimensionInfo ==================================
+ * Abstract:
+ * This method is called when there is not enough information in your
+ * model to uniquely determine the port dimensionality of signals
+ * entering or leaving your block. When this occurs, Simulink's
+ * dimension propagation engine calls this method to ask you to set
+ * your S-functions default dimensions for any input and output ports
+ * that are dynamically sized.
+ *
+ * If you do not provide this method and you have dynamically sized ports
+ * where Simulink does not have enough information to propagate the
+ * dimensionality to your S-function, then Simulink will set these unknown
+ * ports to the 'block width' which is determined by examining any known
+ * ports. If there are no known ports, the width will be set to 1.
+ *
+ * See matlabroot/simulink/src/sfun_matadd.c for an example.
+ */
+ static void mdlSetDefaultPortDimensionInfo(SimStruct *S)
+ {
+ } /* mdlSetDefaultPortDimensionInfo */
+#endif /* MDL_SET_DEFAULT_PORT_DIMENSION_INFO */
+
+
+#define MDL_SET_INPUT_PORT_SAMPLE_TIME
+#if defined(MDL_SET_INPUT_PORT_SAMPLE_TIME) && defined(MATLAB_MEX_FILE)
+ /* Function: mdlSetInputPortSampleTime =======================================
+ * Abstract:
+ * This method is called with the candidate sample time for an inherited
+ * sample time input port. If the proposed sample time is acceptable, the
+ * method should go ahead and set the actual port sample time using
+ * ssSetInputPortSampleTime. If the sample time is unacceptable an error
+ * should generated via ssSetErrorStatus. Note that any other inherited
+ * input or output ports whose sample times are implicitly defined by
+ * virtue of knowing the sample time of the given port can also have
+ * their sample times set via calls to ssSetInputPortSampleTime or
+ * ssSetOutputPortSampleTime.
+ *
+ * When inherited port based sample times are specified, we are guaranteed
+ * that the sample time will be one of the following:
+ * [sampleTime, offsetTime]
+ * continuous [0.0 , 0.0 ]
+ * discrete [period , offset ] where 0.0 < period < inf
+ * 0.0 <= offset < period
+ * Constant, triggered, and variable step sample times will not be
+ * propagated to S-functions with port based sample times.
+ *
+ * Generally the mdlSetInputPortSampleTime or mdlSetOutputPortSampleTime
+ * is called once with the input port sample time. However, there can be
+ * cases where this function will be called more than once. This happens
+ * when the simulation engine is converting continuous sample times to
+ * continuous but fixed in minor steps sample times. When this occurs, the
+ * original values of the sample times specified in mdlInitializeSizes
+ * will be restored before calling this method again.
+ *
+ * The final sample time specified at the port may be different (but
+ * equivalent to) from what was specified in this method. This occurs
+ * when:
+ * o) Using a fixed step solver and the port has a continuous but fixed
+ * in minor step sample time. In this case the sample time will
+ * be converted to the fundamental sample time for the model.
+ * o) We are adjusting sample times for numerical correctness. For
+ * example [0.2499999999999, 0] is converted to [0.25, 0].
+ * S-functions are not explicitly notified of "converted" sample times.
+ * They can examine the final sample times in mdlInitializeSampleTimes.
+ */
+ static void mdlSetInputPortSampleTime(SimStruct *S,
+ int_T portIdx,
+ real_T sampleTime,
+ real_T offsetTime)
+ {
+ } /* end mdlSetInputPortSampleTime */
+#endif /* MDL_SET_INPUT_PORT_SAMPLE_TIME */
+
+
+#define MDL_SET_OUTPUT_PORT_SAMPLE_TIME
+#if defined(MDL_SET_OUTPUT_PORT_SAMPLE_TIME) && defined(MATLAB_MEX_FILE)
+ /* Function: mdlSetOutputPortSampleTime ======================================
+ * Abstract:
+ * This method is called with the candidate sample time for an inherited
+ * sample time output port. If the proposed sample time is acceptable, the
+ * method should go ahead and set the actual port sample time using
+ * ssSetOutputPortSampleTime. If the sample time is unacceptable an error
+ * should generated via ssSetErrorStatus. Note that any other inherited
+ * input or output ports whose sample times are implicitly defined by
+ * virtue of knowing the sample time of the given port can also have
+ * their sample times set via calls to ssSetInputPortSampleTime or
+ * ssSetOutputPortSampleTime.
+ *
+ * Normally, sample times are propagated forwards, however if sources
+ * feeding this block have an inherited sample time, then Simulink
+ * may choose to back propagate known sample times to this block.
+ * When back propagating sample times, we call this method in succession
+ * for all inherited output port signals.
+ *
+ * See mdlSetInputPortSampleTimes for more information about when this
+ * method is called.
+ */
+ static void mdlSetOutputPortSampleTime(SimStruct *S,
+ int_T portIdx,
+ real_T sampleTime,
+ real_T offsetTime)
+ {
+ } /* end mdlSetOutputPortSampleTime */
+#endif /* MDL_SET_OUTPUT_PORT_SAMPLE_TIME */
+
+
+/* Function: mdlInitializeSampleTimes =========================================
+ * Abstract:
+ *
+ * This function is used to specify the sample time(s) for your S-function.
+ * You must register the same number of sample times as specified in
+ * ssSetNumSampleTimes. If you specify that you have no sample times, then
+ * the S-function is assumed to have one inherited sample time.
+ *
+ * The sample times are specified as pairs "[sample_time, offset_time]"
+ * via the following macros:
+ * ssSetSampleTime(S, sampleTimePairIndex, sample_time)
+ * ssSetOffsetTime(S, offsetTimePairIndex, offset_time)
+ * Where sampleTimePairIndex starts at 0.
+ *
+ * The valid sample time pairs are (upper case values are macros defined
+ * in simstruc.h):
+ *
+ * [CONTINUOUS_SAMPLE_TIME, 0.0 ]
+ * [CONTINUOUS_SAMPLE_TIME, FIXED_IN_MINOR_STEP_OFFSET]
+ * [discrete_sample_period, offset ]
+ * [VARIABLE_SAMPLE_TIME , 0.0 ]
+ *
+ * Alternatively, you can specify that the sample time is inherited from the
+ * driving block in which case the S-function can have only one sample time
+ * pair:
+ *
+ * [INHERITED_SAMPLE_TIME, 0.0 ]
+ * or
+ * [INHERITED_SAMPLE_TIME, FIXED_IN_MINOR_STEP_OFFSET]
+ *
+ * The following guidelines may help aid in specifying sample times:
+ *
+ * o A continuous function that changes during minor integration steps
+ * should register the [CONTINUOUS_SAMPLE_TIME, 0.0] sample time.
+ * o A continuous function that does not change during minor integration
+ * steps should register the
+ * [CONTINUOUS_SAMPLE_TIME, FIXED_IN_MINOR_STEP_OFFSET]
+ * sample time.
+ * o A discrete function that changes at a specified rate should register
+ * the discrete sample time pair
+ * [discrete_sample_period, offset]
+ * where
+ * discrete_sample_period > 0.0 and
+ * 0.0 <= offset < discrete_sample_period
+ * o A discrete function that changes at a variable rate should
+ * register the variable step discrete [VARIABLE_SAMPLE_TIME, 0.0]
+ * sample time. The mdlGetTimeOfNextVarHit function is called to get
+ * the time of the next sample hit for the variable step discrete task.
+ * Note, the VARIABLE_SAMPLE_TIME can be used with variable step
+ * solvers only.
+ * o Discrete blocks which can operate in triggered subsystems. For your
+ * block to operate correctly in a triggered subsystem or a periodic
+ * system it must register [INHERITED_SAMPLE_TIME, 0.0]. In a triggered
+ * subsystem after sample times have been propagated throughout the
+ * block diagram, the assigned sample time to the block will be
+ * [INHERITED_SAMPLE_TIME, INHERITED_SAMPLE_TIME]. Typically discrete
+ * blocks which can be periodic or reside within triggered subsystems
+ * need to register the inherited sample time and the option
+ * SS_OPTION_DISALLOW_CONSTANT_SAMPLE_TIME. Then in mdlSetWorkWidths, they
+ * need to verify that they were assigned a discrete or triggered
+ * sample time. To do this:
+ * mdlSetWorkWidths:
+ * if (ssGetSampleTime(S, 0) == CONTINUOUS_SAMPLE_TIME) {
+ * ssSetErrorStatus(S, "This block cannot be assigned a "
+ * "continuous sample time");
+ * }
+ *
+ * If your function has no intrinsic sample time, then you should indicate
+ * that your sample time is inherited according to the following guidelines:
+ *
+ * o A function that changes as its input changes, even during minor
+ * integration steps should register the [INHERITED_SAMPLE_TIME, 0.0]
+ * sample time.
+ * o A function that changes as its input changes, but doesn't change
+ * during minor integration steps (i.e., held during minor steps) should
+ * register the [INHERITED_SAMPLE_TIME, FIXED_IN_MINOR_STEP_OFFSET]
+ * sample time.
+ *
+ * To check for a sample hit during execution (in mdlOutputs or mdlUpdate),
+ * you should use the ssIsSampleHit or ssIsContinuousTask macros.
+ * For example, if your first sample time is continuous, then you
+ * used the following code-fragment to check for a sample hit. Note,
+ * you would get incorrect results if you used ssIsSampleHit(S,0,tid).
+ * if (ssIsContinuousTask(S,tid)) {
+ * }
+ * If say, you wanted to determine if the third (discrete) task has a hit,
+ * then you would use the following code-fragment:
+ * if (ssIsSampleHit(S,2,tid) {
+ * }
+ *
+ */
+static void mdlInitializeSampleTimes(SimStruct *S)
+{
+ /* Register one pair for each sample time */
+ ssSetSampleTime(S, 0, INHERITED_SAMPLE_TIME);
+ ssSetOffsetTime(S, 0, 0.0);
+
+} /* end mdlInitializeSampleTimes */
+
+
+#define MDL_SET_INPUT_PORT_DATA_TYPE /* Change to #undef to remove function */
+#if defined(MDL_SET_INPUT_PORT_DATA_TYPE) && defined(MATLAB_MEX_FILE)
+ /* Function: mdlSetInputPortDataType =========================================
+ * Abstract:
+ * This method is called with the candidate data type id for a dynamically
+ * typed input port. If the proposed data type is acceptable, the method
+ * should go ahead and set the actual port data type using
+ * ssSetInputPortDataType. If the data type is unacceptable an error
+ * should generated via ssSetErrorStatus. Note that any other dynamically
+ * typed input or output ports whose data types are implicitly defined by
+ * virtue of knowing the data type of the given port can also have their
+ * data types set via calls to ssSetInputPortDataType or
+ * ssSetOutputPortDataType.
+ *
+ * See matlabroot/simulink/include/simstruc_types.h for built-in
+ * type defines: SS_DOUBLE, SS_BOOLEAN, etc.
+ *
+ * See matlabroot/simulink/src/sfun_dtype_io.c for an example.
+ */
+ static void mdlSetInputPortDataType(SimStruct *S, int portIndex,DTypeId dType)
+ {
+ } /* mdlSetInputPortDataType */
+#endif /* MDL_SET_INPUT_PORT_DATA_TYPE */
+
+
+#define MDL_SET_OUTPUT_PORT_DATA_TYPE /* Change to #undef to remove function */
+#if defined(MDL_SET_OUTPUT_PORT_DATA_TYPE) && defined(MATLAB_MEX_FILE)
+ /* Function: mdlSetOutputPortDataType ========================================
+ * Abstract:
+ * This method is called with the candidate data type id for a dynamically
+ * typed output port. If the proposed data type is acceptable, the method
+ * should go ahead and set the actual port data type using
+ * ssSetOutputPortDataType. If the data type is unacceptable an error
+ * should generated via ssSetErrorStatus. Note that any other dynamically
+ * typed input or output ports whose data types are implicitly defined by
+ * virtue of knowing the data type of the given port can also have their
+ * data types set via calls to ssSetInputPortDataType or
+ * ssSetOutputPortDataType.
+ *
+ * See matlabroot/simulink/src/sfun_dtype_io.c for an example.
+ */
+ static void mdlSetOutputPortDataType(SimStruct *S,int portIndex,DTypeId dType)
+ {
+ } /* mdlSetOutputPortDataType */
+#endif /* MDL_SET_OUTPUT_PORT_DATA_TYPE */
+
+
+#define MDL_SET_DEFAULT_PORT_DATA_TYPES /* Change to #undef to remove function*/
+#if defined(MDL_SET_DEFAULT_PORT_DATA_TYPES) && defined(MATLAB_MEX_FILE)
+ /* Function: mdlSetDefaultPortDataTypes =====================================
+ * Abstract:
+ * This method is called when there is not enough information in your
+ * model to uniquely determine the input and output data types
+ * for your block. When this occurs, Simulink's data type propagation
+ * engine calls this method to ask you to set your S-function default
+ * data type for any dynamically typed input and output ports.
+ *
+ * If you do not provide this method and you have dynamically typed
+ * ports where Simulink does not have enough information to propagate
+ * data types to your S-function, then Simulink will assign the
+ * data type to the largest known port data type of your S-function.
+ * If there are no known data types, then Simulink will set the
+ * data type to double.
+ *
+ * See matlabroot/simulink/src/sfun_dtype_io.c for an example.
+ */
+ static void mdlSetDefaultPortDataTypes(SimStruct *S)
+ {
+ } /* mdlSetDefaultPortDataTypes */
+#endif /* MDL_SET_DEFAULT_PORT_DATA_TYPES */
+
+
+#define MDL_SET_INPUT_PORT_COMPLEX_SIGNAL /* Change to #undef to remove */
+#if defined(MDL_SET_INPUT_PORT_COMPLEX_SIGNAL) && defined(MATLAB_MEX_FILE)
+ /* Function: mdlSetInputPortComplexSignal ====================================
+ * Abstract:
+ * This method is called with the candidate complexity signal setting
+ * (COMPLEX_YES or COMPLEX_NO) for an input port whos complex signal
+ * attribute is set to COMPLEX_INHERITED. If the proposed complexity is
+ * acceptable, the method should go ahead and set the actual complexity
+ * using ssSetInputPortComplexSignal. If the complex setting is
+ * unacceptable an error should generated via ssSetErrorStatus. Note that
+ * any other unknown ports whose complexity is implicitly defined by virtue
+ * of knowing the complexity of the given port can also have their
+ * complexity set via calls to ssSetInputPortComplexSignal or
+ * ssSetOutputPortComplexSignal.
+ *
+ * See matlabroot/simulink/src/sfun_cplx.c for an example.
+ */
+ static void mdlSetInputPortComplexSignal(SimStruct *S,
+ int portIndex,
+ CSignal_T cSignalSetting)
+ {
+ } /* mdlSetInputPortComplexSignal */
+#endif /* MDL_SET_INPUT_PORT_COMPLEX_SIGNAL */
+
+
+#define MDL_SET_OUTPUT_PORT_COMPLEX_SIGNAL /* Change to #undef to remove */
+#if defined(MDL_SET_OUTPUT_PORT_COMPLEX_SIGNAL) && defined(MATLAB_MEX_FILE)
+ /* Function: mdlSetOutputPortComplexSignal ===================================
+ * Abstract:
+ * This method is called with the candidate complexity signal setting
+ * (COMPLEX_YES or COMPLEX_NO) for an output port whos complex signal
+ * attribute is set to COMPLEX_INHERITED. If the proposed complexity is
+ * acceptable, the method should go ahead and set the actual complexity
+ * using ssSetOutputPortComplexSignal. If the complex setting is
+ * unacceptable an error should generated via ssSetErrorStatus. Note that
+ * any other unknown ports whose complexity is implicitly defined by virtue
+ * of knowing the complexity of the given port can also have their
+ * complexity set via calls to ssSetInputPortComplexSignal or
+ * ssSetOutputPortComplexSignal.
+ *
+ * See matlabroot/simulink/src/sfun_cplx.c for an example.
+ */
+ static void mdlSetOutputPortComplexSignal(SimStruct *S,
+ int portIndex,
+ CSignal_T cSignalSetting)
+ {
+ } /* mdlSetOutputPortComplexSignal */
+#endif /* MDL_SET_OUTPUT_PORT_COMPLEX_SIGNAL */
+
+
+#define MDL_SET_DEFAULT_PORT_COMPLEX_SIGNALS /* Change to #undef to remove */
+#if defined(MDL_SET_DEFAULT_PORT_COMPLEX_SIGNALS) && defined(MATLAB_MEX_FILE)
+ /* Function: mdlSetDefaultPortComplexSignals ================================
+ * Abstract:
+ * This method is called when there is not enough information in your
+ * model to uniquely determine the complexity (COMPLEX_NO, COMPLEX_YES)
+ * of signals entering your block. When this occurs, Simulink's
+ * complex signal propagation engine calls this method to ask you to set
+ * your S-function default complexity type for any input and output ports
+ * who's complex signal attribute is set to COMPLEX_INHERITED.
+ *
+ * If you do not provide this method and you have COMPLEX_INHERITED
+ * ports where Simulink does not have enough information to propagate
+ * the complexity to your S-function, then Simulink will set
+ * these unkown ports to COMPLEX_YES if any of your S-function
+ * ports are currently set to COMPLEX_YES, otherwise the unknown
+ * ports will be set to COMPLEX_NO.
+ *
+ * See matlabroot/simulink/src/sfun_cplx.c for an example.
+ */
+ static void mdlSetDefaultPortComplexSignals(SimStruct *S)
+ {
+ } /* mdlSetDefaultPortComplexSignals */
+#endif /* MDL_SET_DEFAULT_PORT_COMPLEX_SIGNALS */
+
+
+#define MDL_SET_WORK_WIDTHS /* Change to #undef to remove function */
+#if defined(MDL_SET_WORK_WIDTHS) && defined(MATLAB_MEX_FILE)
+ /* Function: mdlSetWorkWidths ===============================================
+ * Abstract:
+ * The optional method, mdlSetWorkWidths is called after input port
+ * width, output port width, and sample times of the S-function have
+ * been determined to set any state and work vector sizes which are
+ * a function of the input, output, and/or sample times. This method
+ * is used to specify the nonzero work vector widths via the macros
+ * ssNumContStates, ssSetNumDiscStates, ssSetNumRWork, ssSetNumIWork,
+ * ssSetNumPWork, ssSetNumModes, and ssSetNumNonsampledZCs.
+ *
+ * Run-time parameters are registered in this method using methods
+ * ssSetNumRunTimeParams, ssSetRunTimeParamInfo, and related methods.
+ *
+ * If you are using mdlSetWorkWidths, then any work vectors you are
+ * using in your S-function should be set to DYNAMICALLY_SIZED in
+ * mdlInitializeSizes, even if the exact value is known at that point.
+ * The actual size to be used by the S-function should then be specified
+ * in mdlSetWorkWidths.
+ */
+ static void mdlSetWorkWidths(SimStruct *S)
+ {
+ }
+#endif /* MDL_SET_WORK_WIDTHS */
+
+
+#define MDL_INITIALIZE_CONDITIONS /* Change to #undef to remove function */
+#if defined(MDL_INITIALIZE_CONDITIONS)
+ /* Function: mdlInitializeConditions ========================================
+ * Abstract:
+ * In this function, you should initialize the continuous and discrete
+ * states for your S-function block. The initial states are placed
+ * in the state vector, ssGetContStates(S) or ssGetDiscStates(S).
+ * You can also perform any other initialization activities that your
+ * S-function may require. Note, this method will be called at the
+ * start of simulation and if it is present in an enabled subsystem
+ * configured to reset states, it will be call when the enabled subsystem
+ * restarts execution to reset the states.
+ *
+ * You can use the ssIsFirstInitCond(S) macro to determine if this is
+ * is the first time mdlInitializeConditions is being called.
+ */
+ static void mdlInitializeConditions(SimStruct *S)
+ {
+ ikClwindconWTCon *con = (ikClwindconWTCon*) ssGetPWorkValue(S, 0);
+ /* Initialise controller */
+ ikClwindconWTConParams param;
+ ikClwindconWTCon_initParams(¶m);
+ setParams(¶m);
+ ikClwindconWTCon_init(con, ¶m);
+ }
+#endif /* MDL_INITIALIZE_CONDITIONS */
+
+
+#define MDL_START /* Change to #undef to remove function */
+#if defined(MDL_START)
+ /* Function: mdlStart =======================================================
+ * Abstract:
+ * This function is called once at start of model execution. If you
+ * have states that should be initialized once, this is the place
+ * to do it.
+ */
+ static void mdlStart(SimStruct *S)
+ {
+ /* Allocate controller */
+ void *ptr = calloc(1, sizeof(ikClwindconWTCon));
+ if (ptr == NULL) {
+ /* report memory allocation error */
+ ssSetErrorStatus(S, "Memory allocation error");
+ return;
+ }
+ ssSetPWorkValue(S, 0, ptr);
+ }
+#endif /* MDL_START */
+
+
+/* Define to indicate that this S-Function has the mdlG[S]etSimState methods */
+#define MDL_SIM_STATE /* Change to #undef to remove this function */
+#if defined(MDL_SIM_STATE)
+ /* Function: mdlGetSimState ===========================================
+ * Abstract:
+ * Package complete simulation state (this includes all the run-time data
+ * that can change *after* mdlStart) as a MATLAB data structure and return
+ * it.
+ */
+ static mxArray* mdlGetSimState(SimStruct* S)
+ {
+ }
+
+ /* Function: mdlSetSimState ===========================================
+ * Abstract:
+ * Unack inSimState MATLAB data structure which contains the complete
+ * simulation state (this includes all the run-time data that can change
+ * *after* mdlStart) into the appropriate locations.
+ */
+ static void mdlSetSimState(SimStruct* S, const mxArray* inSimState)
+ {
+ }
+#endif /* MDL_SIM_STATE */
+
+
+#define MDL_GET_TIME_OF_NEXT_VAR_HIT /* Change to #undef to remove function */
+#if defined(MDL_GET_TIME_OF_NEXT_VAR_HIT) && (defined(MATLAB_MEX_FILE) || \
+ defined(NRT))
+ /* Function: mdlGetTimeOfNextVarHit =========================================
+ * Abstract:
+ * This function is called to get the time of the next variable sample
+ * time hit. This function is called once for every major integration time
+ * step. It must return time of next hit by using ssSetTNext. The time of
+ * the next hit must be greater than ssGetT(S).
+ *
+ * Note, the time of next hit can be a function of the input signal(s).
+ */
+
+ static void mdlGetTimeOfNextVarHit(SimStruct *S)
+ {
+ time_T timeOfNextHit = ssGetT(S) /* + offset */ ;
+ ssSetTNext(S, timeOfNextHit);
+ }
+#endif /* MDL_GET_TIME_OF_NEXT_VAR_HIT */
+
+
+#define MDL_ZERO_CROSSINGS /* Change to #undef to remove function */
+#if defined(MDL_ZERO_CROSSINGS) && (defined(MATLAB_MEX_FILE) || defined(NRT))
+ /* Function: mdlZeroCrossings ===============================================
+ * Abstract:
+ * If your S-function has registered CONTINUOUS_SAMPLE_TIME and there
+ * are signals entering the S-function or internally generated signals
+ * which have discontinuities, you can use this method to locate the
+ * discontinuities. When called, this method must update the
+ * ssGetNonsampleZCs(S) vector.
+ */
+ static void mdlZeroCrossings(SimStruct *S)
+ {
+ }
+#endif /* MDL_ZERO_CROSSINGS */
+
+
+/* Function: mdlOutputs =======================================================
+ * Abstract:
+ * In this function, you compute the outputs of your S-function
+ * block. Generally outputs are placed in the output vector(s),
+ * ssGetOutputPortSignal.
+ */
+static void mdlOutputs(SimStruct *S, int_T tid)
+{
+} /* end mdlOutputs */
+
+
+#define MDL_UPDATE /* Change to #undef to remove function */
+#if defined(MDL_UPDATE)
+ /* Function: mdlUpdate ======================================================
+ * Abstract:
+ * This function is called once for every major integration time step.
+ * Discrete states are typically updated here, but this function is useful
+ * for performing any tasks that should only take place once per
+ * integration step.
+ */
+ static void mdlUpdate(SimStruct *S, int_T tid)
+ {
+ ikClwindconWTCon *con = (ikClwindconWTCon*) ssGetPWorkValue(S, 0);
+
+ con->in.deratingRatio = **(ssGetInputPortRealSignalPtrs(S,0));
+ con->in.externalMaximumTorque = 230.0; /* kNm */
+ con->in.externalMinimumTorque = 0.0; /* kNm */
+ con->in.externalMaximumPitch = 90.0; /* deg */
+ con->in.externalMinimumPitch = 0.0; /* deg */
+ con->in.generatorSpeed = **(ssGetInputPortRealSignalPtrs(S,1)); /* rad/s */
+ con->in.rotorSpeed = **(ssGetInputPortRealSignalPtrs(S,10)); /* rad/s */
+ con->in.maximumSpeed = 480.0/30*3.1416; /* rpm to rad/s */
+ con->in.azimuth = **(ssGetInputPortRealSignalPtrs(S,2)); /* deg */
+ con->in.maximumIndividualPitch = 10.0; /* deg */
+ con->in.yawErrorReference = 0.0; /* deg */
+ con->in.yawError = **(ssGetInputPortRealSignalPtrs(S,3)); /* deg */
+ con->in.bladeRootMoments[0].c[0] = **(ssGetInputPortRealSignalPtrs(S,4)); /* kNm */
+ con->in.bladeRootMoments[0].c[1] = **(ssGetInputPortRealSignalPtrs(S,5)); /* kNm */
+ con->in.bladeRootMoments[0].c[2] = 0.0; /* kNm */
+ con->in.bladeRootMoments[1].c[0] = **(ssGetInputPortRealSignalPtrs(S,6)); /* kNm */
+ con->in.bladeRootMoments[1].c[1] = **(ssGetInputPortRealSignalPtrs(S,7)); /* kNm */
+ con->in.bladeRootMoments[1].c[2] = 0.0; /* kNm */
+ con->in.bladeRootMoments[2].c[0] = **(ssGetInputPortRealSignalPtrs(S,8)); /* kNm */
+ con->in.bladeRootMoments[2].c[1] = **(ssGetInputPortRealSignalPtrs(S,9)); /* kNm */
+ con->in.bladeRootMoments[2].c[2] = 0.0; /* kNm */
+
+ ikClwindconWTCon_step(con);
+
+ *(ssGetOutputPortRealSignal(S,0)) = con->out.torqueDemand; /* kNm */
+ *(ssGetOutputPortRealSignal(S,1)) = con->out.pitchDemandBlade1; /* deg */
+ *(ssGetOutputPortRealSignal(S,2)) = con->out.pitchDemandBlade2; /* deg */
+ *(ssGetOutputPortRealSignal(S,3)) = con->out.pitchDemandBlade3; /* deg */
+ }
+#endif /* MDL_UPDATE */
+
+
+#define MDL_DERIVATIVES /* Change to #undef to remove function */
+#if defined(MDL_DERIVATIVES)
+ /* Function: mdlDerivatives =================================================
+ * Abstract:
+ * In this function, you compute the S-function block's derivatives.
+ * The derivatives are placed in the derivative vector, ssGetdX(S).
+ */
+ static void mdlDerivatives(SimStruct *S)
+ {
+ }
+#endif /* MDL_DERIVATIVES */
+
+
+/* Function: mdlTerminate =====================================================
+ * Abstract:
+ * In this function, you should perform any actions that are necessary
+ * at the termination of a simulation. For example, if memory was allocated
+ * in mdlStart, this is the place to free it.
+ *
+ * Suppose your S-function allocates a few few chunks of memory in mdlStart
+ * and saves them in PWork. The following code fragment would free this
+ * memory.
+ * {
+ * int i;
+ * for (i = 0; i(S)
+ * Recall that you would have to set ssSetNum(S)
+ * in one of the initialization functions (mdlInitializeSizes
+ * or mdlSetWorkVectorWidths).
+ *
+ * See simulink/include/simulink.c for the definition (implementation)
+ * of this function, and ... no example yet :(
+ *
+ * 4) Finally the following functions/macros give you the ability to write
+ * arbitrary strings and [name, value] pairs directly into the .rtw
+ * file.
+ *
+ * if (!ssWriteRTWStr(S, const_char_*_string)) {
+ * return;
+ * }
+ *
+ * if (!ssWriteRTWStrParam(S, const_char_*_name, const_char_*_value)) {
+ * return;
+ * }
+ *
+ * if (!ssWriteRTWScalarParam(S, const_char_*_name,
+ * const_void_*_value,
+ * DTypeId_dtypeId)) {
+ * return;
+ * }
+ *
+ * if (!ssWriteRTWStrVectParam(S, const_char_*_name,
+ * const_char_*_value,
+ * int_num_items)) {
+ * return;
+ * }
+ *
+ * if (!ssWriteRTWVectParam(S, const_char_*_name, const_void_*_value,
+ * int_data_type_of_value, int_vect_len)){
+ * return;
+ * }
+ *
+ * if (!ssWriteRTW2dMatParam(S, const_char_*_name, const_void_*_value,
+ * int_data_type_of_value, int_nrows, int_ncols)){
+ * return;
+ * }
+ *
+ * The 'data_type_of_value' input argument for the above two macros is
+ * obtained using
+ * DTINFO(dTypeId, isComplex),
+ * where
+ * dTypeId: can be any one of the enum values in BuitlInDTypeID
+ * (SS_DOUBLE, SS_SINGLE, SS_INT8, SS_UINT8, SS_INT16,
+ * SS_UINT16, SS_INT32, SS_UINT32, SS_BOOLEAN defined
+ * in simstuc_types.h)
+ * isComplex: is either 0 or 1, as explained in Note-2 for
+ * ssWriteRTWParameters.
+ *
+ * For example DTINFO(SS_INT32,0) is a non-complex 32-bit signed
+ * integer.
+ *
+ * If isComplex==1, then it is assumed that 'const_void_*_value' array
+ * has the real and imaginary parts arranged in an interleaved manner
+ * (i.e., Simulink Format).
+ *
+ * If you prefer to pass the real and imaginary parts as two seperate
+ * arrays, you should use the follwing macros:
+ *
+ * if (!ssWriteRTWMxVectParam(S, const_char_*_name,
+ * const_void_*_rvalue, const_void_*_ivalue,
+ * int_data_type_of_value, int_vect_len)){
+ * return;
+ * }
+ *
+ * if (!ssWriteRTWMx2dMatParam(S, const_char_*_name,
+ * const_void_*_rvalue, const_void_*_ivalue,
+ * int_data_type_of_value,
+ * int_nrows, int_ncols)){
+ * return;
+ * }
+ *
+ * See simulink/include/simulink.c and simstruc.h for the definition
+ * (implementation) of these functions and simulink/src/ml2rtw.c for
+ * examples of using these functions.
+ *
+ */
+ static void mdlRTW(SimStruct *S)
+ {
+ }
+#endif /* MDL_RTW */
+
+
+/*=============================*
+ * Required S-function trailer *
+ *=============================*/
+
+#ifdef MATLAB_MEX_FILE /* Is this file being compiled as a MEX-file? */
+#include "simulink.c" /* MEX-file interface mechanism */
+#else
+#include "cg_sfun.h" /* Code generation registration function */
+#endif
diff --git a/OpenWitcon b/OpenWitcon
index 5b3537a..c9e5f02 160000
--- a/OpenWitcon
+++ b/OpenWitcon
@@ -1 +1 @@
-Subproject commit 5b3537a935cde8f88c80a1d012c4136a2657384e
+Subproject commit c9e5f024663cbe8f3ddafb7da4d8086991fe9ccb
diff --git a/README.md b/README.md
index 03d6685..deb0b14 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,15 @@
# OpenDiscon
-Open source implementation of the legacy GHBladed external controller interface.
+Open source implementation of popular wind turbine controller interfaces.
-This code is for the production of a shared library implementing the DISCON interface for the DTU 10MW model.
+Currently available distributions are for:
+- The legacy GHBladed external controller interface (typically called DISCON, hence the name OpenDiscon).
+- Level-2 MATLAB S-Function for Simulink.
-The source code is at ./src. The main implementation file is discon.c.
-It uses IK4-IKERLAN's library OpenWitcon, included as a submodule.
+Currently available configurations are for:
+- CL-Windcon (DTU 10MW model).
+
+This uses [IK4-IKERLAN](http://www.ikerlan.es/en/)'s library OpenWitcon, included as a submodule.
Documentation is provided in Doxygen format. To generate it, run Doxygen on ./doc/Doxyfile.
For compilation, run cmake here.
-This will generate the VS solution or makefiles for straightforward compilation, depending on your toolchain.
+This will generate the VS solution, makefiles or MATLAB function for straightforward compilation, depending on your toolchain.
diff --git a/doc/CL-Windcon.dox b/doc/CL-Windcon.dox
index 5a905b8..83983ac 100644
--- a/doc/CL-Windcon.dox
+++ b/doc/CL-Windcon.dox
@@ -34,11 +34,18 @@ along with OpenDiscon. If not, see .
* OpenDiscon caters to the needs of H2020 project CL-Windcon, by providing a controller specifically
* tuned for compatibility with the Innwind 10 MW reference wind turbine model.
*
-* @section basic Basic controller
+* @section intro Introduction
*
-* The basic controller provided by OpenDiscon for CL-Windcon is an instance of @link ikClwindconWTCon @endlink,
+* The controller provided by OpenDiscon for CL-Windcon is an instance of @link ikClwindconWTCon @endlink,
* with the control loop parameters given by @link ikClwindconWTConfig.c @endlink.
*
+* @subsection samplinginterval Sampling interval
+*
+* The controller is a discrete-time implementation, with a sampling interval given in @link ikClwindconWTConfig.c @endlink, conveniently commented as follows:
+* @snippet ikClwindconWTConfig.c Sampling interval
+*
+* @section basic Basic controller
+*
* @subsection dtdamper Drivetrain damper
*
* The drivetrain damper is an implementation of the following transfer function from [1]:
@@ -47,13 +54,14 @@ along with OpenDiscon. If not, see .
* @f]
*
* The parameters are in @link ikClwindconWTConfig.c @endlink, conveniently commented as follows:
-* @snippet ikClwindconWTConfig.c CL-Windcon drivetrain damper
+* @snippet ikClwindconWTConfig.c Drivetrain damper
*
* @subsection torquecon Torque control
*
* @subsubsection torquepi PI
*
-* The torque controller is a PI, with its parameters given in @link ikClwindconWTConfig.c @endlink, conveniently commented as follows:
+* The torque controller forces the generator torque against the optimum torque curve and regulates the generator speed when the minimum speed is reached.
+* It is a PI, with its parameters given in @link ikClwindconWTConfig.c @endlink, conveniently commented as follows:
* @snippet ikClwindconWTConfig.c Torque PI
* Note the negative gains, which are necessary to make the torque increase when the speed error (setpoint minus measurement) is negative, and viceversa.
*
@@ -77,17 +85,12 @@ along with OpenDiscon. If not, see .
* The parameters are in @link ikClwindconWTConfig.c @endlink, conveniently commented as follows:
* @snippet ikClwindconWTConfig.c 1st side-side tower mode filter
*
-* @subsubsection kopt Optimum torque curve
-*
-* Below rated wind speed, the torque controller uses a quadratic speed-torque curve, along the lines of that described by [1].
-* The parameters are in @link ikClwindconWTConfig.c @endlink, conveniently commented as follows:
-* @snippet ikClwindconWTConfig.c Optimum torque
-*
* @subsection pitchcon Pitch control
*
* @subsubsection pitchpi PI
*
-* The pitch controller is a PI, with its parameters given in @link ikClwindconWTConfig.c @endlink, conveniently commented as follows:
+* The pitch controller forces the collective blade pitch against the minimum pitch and regulates the generator speed when the maximum speed is reached.
+* It is a PI, with its parameters given in @link ikClwindconWTConfig.c @endlink, conveniently commented as follows:
* @snippet ikClwindconWTConfig.c Pitch PI
* Note the negative gains, which are necessary to make the pitch angle increase when the speed error (setpoint minus measurement) is negative, and viceversa.
*
@@ -118,13 +121,69 @@ along with OpenDiscon. If not, see .
* The parameters are in @link ikClwindconWTConfig.c @endlink, conveniently commented as follows:
* @snippet ikClwindconWTConfig.c Gain schedule
*
-* @subsubsection minpitch Minimum pitch
+* @section derating Derating
+*
+* @subsection minpitch Minimum pitch
*
* The minimum pitch is altered depending on the derating ratio. This is implemented as a look-up table.
*
* The parameters are in @link ikClwindconWTConfig.c @endlink, conveniently commented as follows:
* @snippet ikClwindconWTConfig.c Minimum pitch
*
+* @subsection kopt Optimum torque curve
+*
+* Below rated wind speed, the torque controller uses a quadratic speed-torque curve, along the lines of that described by [1].
+* The gain of said curve varies depending on the derating ratio. This is implemented as a look-up table.
+*
+* The parameters are in @link ikClwindconWTConfig.c @endlink, conveniently commented as follows:
+* @snippet ikClwindconWTConfig.c Optimum torque
+*
+* @section ipc Individual pitch control
+*
+* @subsection regipc Regular IPC
+* Regular individual pitch control consists of two PI controllers, for moments around axes y and z, respectively.
+* The gains are in @link ikClwindconWTConfig.c @endlink, conveniently commented as follows:
+* @snippet ikClwindconWTConfig.c IPC My PI
+* @snippet ikClwindconWTConfig.c IPC Mz PI
+*
+* Note that regular IPC gains are zero, i.e. regular IPC is disabled, in this configuration. Yaw by IPC is used instead.
+*
+* @subsection yawbyipc Yaw by IPC
+*
+* Yaw by IPC introduces a moment around axis z to make the turbine yaw. It consists of a PI controller, which regulates the yaw error.
+* Its gains are in @link ikClwindconWTConfig.c @endlink, conveniently commented as follows:
+* @snippet ikClwindconWTConfig.c Yaw by IPC PI
+*
+* The yaw error measurement is low-pass filtered with a second order filter with the following transfer function:
+* @f[
+* H(s) = \frac{\omega^2}{s^2 + 2 \xi \omega s + \omega^2}
+* @f]
+*
+* The parameters are in @link ikClwindconWTConfig.c @endlink, conveniently commented as follows:
+* @snippet ikClwindconWTConfig.c Yaw by IPC lowpass filter
+*
+* @section ftc Fault tolerance
+*
+* @subsection spdman Generator speed sensor redundancy
+*
+* The controller uses three different generator speed measurements:
+* - generator speed
+* - rotor speed (approx. generator speed divided by gearbox ratio)
+* - azimuth (approx. integral of rotor speed)
+*
+* If all three measurements are similar, the generator speed is used.
+* Dissimilarities are used for sensor failure diagnosis and, if the generator speed sensor is found to have failed, the rotor speed is used instead.
+*
+* The parameters dictating when the measurements are dissimilar are in @link ikClwindconWTConfig.c @endlink, conveniently commented as follows:
+* @snippet ikClwindconWTConfig.c Speed sensor manager
+*
+* @subsection faults Sensor faults
+*
+* [Only for DISTRIBUTION = DISCON] A simple generator speed sensor fault introduction facility is provided.
+*
+* The parameters governing this fault are in @link ikClwindconInputMod.c @endlink, conveniently commented as follows:
+* @snippet ikClwindconInputMod.c Speed sensor fault
+*
* @section references References
*
* [1] Tony Burton, Nick Jenkins, David Sharpe, Ervin Bossanyi, Wind Energy Handbook , ISBN: 978-0-470-69975-1.
diff --git a/doc/Doxyfile b/doc/Doxyfile
index 0b4589a..cbb2306 100644
--- a/doc/Doxyfile
+++ b/doc/Doxyfile
@@ -790,9 +790,9 @@ WARN_LOGFILE =
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
-INPUT = ../src \
- ../OpenWitcon/src \
- ./
+INPUT = ../OpenWitcon/src \
+ ./ \
+ ../CONFIGURATION/CL-Windcon/src
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
@@ -906,7 +906,7 @@ EXCLUDE_SYMBOLS =
# that contain example code fragments that are included (see the \include
# command).
-EXAMPLE_PATH = ../src
+EXAMPLE_PATH = ../CONFIGURATION/CL-Windcon/src
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
diff --git a/doc/OpenDiscon.dox b/doc/OpenDiscon.dox
index 107e101..51717c9 100644
--- a/doc/OpenDiscon.dox
+++ b/doc/OpenDiscon.dox
@@ -19,18 +19,22 @@ along with OpenDiscon. If not, see .
/** @mainpage
*
-* OpenDiscon is Ikerlan's open source implementation of the legacy GHBladed DISCON interface,
-* which is also used by other wind turbine simulation software packages such as FAST.
-* It is based on Ikerlan's open source wind turbine control software library @ref openwitcon.
+* OpenDiscon is Ikerlan's open source implementation of popular wind turbine controller interfaces.
+* based on Ikerlan's open source wind turbine control software library @ref openwitcon.
*
* OpenDiscon is publicly available under a rather permissive @subpage license "license", so
* it may be used in many ways, possibly some of which have not been imagined by the authors.
-* However, it provides out-of-the-box implementations for the following uses:
-* - @ref clwindcon
+* However, it provides some out-of-the-box implementations. Using them requires compilation and linking.
+* CMake files are provided for easy production of the project files, makefiles or MATLAB functions suitable for the
+* user's toolchain and options.
*
-* Using OpenDiscon's out-of-the-box implementations starts with their compilation and linking.
-* CMake files are provided for easy production of the project or makefiles suitable for the
-* user's toolchain. Simply run CMake on the OpenDiscon directory.
+* To make the above happen, run CMake on the OpenDiscon directory.
+* Two options are available:
+* - CONFIGURATION
+* - CL-Windcon: a controller for @ref clwindcon
+* - DISTRIBUTION
+* - DISCON: an implementation of the legacy GHBladed DISCON interface, which is also used by other wind turbine simulation software packages such as FAST.
+* - S-Function: a Simulink block implementation.
*
*/
@@ -54,7 +58,7 @@ along with OpenDiscon. If not, see .
/** @page openwitcon OpenWitcon
*
-* OpenWitcon is Ikerlan's open source wind turbine controller software library. It is publicly available
+* OpenWitcon is Ikerlan's open source wind turbine controller software library. It is publicly available
* here.
*
* OpenDiscon makes heavy use of OpenWitcon, and the OpenDiscon repository has the OpenWitcon repository
diff --git a/doc/svg/ikClwindconWTCon_block_diagram.svg b/doc/svg/ikClwindconWTCon_block_diagram.svg
index 743aa47..1b93350 100644
--- a/doc/svg/ikClwindconWTCon_block_diagram.svg
+++ b/doc/svg/ikClwindconWTCon_block_diagram.svg
@@ -9,9 +9,9 @@
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="570.57776mm"
- height="322.54263mm"
- viewBox="0 0 2021.732 1142.8675"
+ width="857.19366mm"
+ height="440.59653mm"
+ viewBox="0 0 3037.3 1561.1687"
id="svg2"
version="1.1"
inkscape:version="0.92.1 r15371"
@@ -807,38 +807,6 @@
transform="matrix(-0.8,0,0,-0.8,-10,0)"
inkscape:connector-curvature="0" />
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ image/svg+xml
-
+
@@ -1702,7 +2006,7 @@
inkscape:label="Capa 1"
inkscape:groupmode="layer"
id="layer1"
- transform="translate(-118.09022,-48.801925)">
+ transform="translate(492.13748,-48.801925)">
ikTpman
-
- pitch demand for blade 1pitch demand for blade 2pitch demand for blade 3
- generator speed
-
+
+ individual pitch control
+ ikIpc
+ 0
+ blade root moments
+ azimuth
+ 0
+ 0
+ maximum individual pitch
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ yaw by ipc
+ ikConLoop
+
+
+ yaw error reference
+ yaw error
+ individual pitch for yaw
+
+ -1
+
+
+
+
+
+ generator speed
+
+ speed sensor manager
+ ikSpdman
+ rotor speed
+ azimuth
+ generator speed equivalent
+
+
+
diff --git a/doc/svg/ikClwindconWTCon_unit_block.svg b/doc/svg/ikClwindconWTCon_unit_block.svg
index 1f3c89e..78e9f37 100644
--- a/doc/svg/ikClwindconWTCon_unit_block.svg
+++ b/doc/svg/ikClwindconWTCon_unit_block.svg
@@ -9,9 +9,9 @@
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="197.91646mm"
- height="132.59679mm"
- viewBox="0 0 701.2788 469.83109"
+ width="207.45264mm"
+ height="182.10945mm"
+ viewBox="0 0 735.06841 645.26965"
id="svg2"
version="1.1"
inkscape:version="0.92.1 r15371"
@@ -31,8 +31,8 @@
inkscape:stockid="Arrow1Lend">
@@ -47,8 +47,8 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ transform="translate(62.20234,-256.24311)">
external minimum torqueexternal maximum pitchikClwindconWTCongenerator speedexternal maximum torquemaximum speedexternal minimum pitchderating ratio
+
+
+
+
+
+ blade root moments
+ maximum individual pitch
+ yaw error reference
+ yaw error
+ azimuth
+
+ rotor speed
diff --git a/doc/svg/ikSpdman_block_diagram.svg b/doc/svg/ikSpdman_block_diagram.svg
new file mode 100644
index 0000000..43661b8
--- /dev/null
+++ b/doc/svg/ikSpdman_block_diagram.svg
@@ -0,0 +1,2194 @@
+
+
+
+
diff --git a/doc/svg/ikSpdman_unit_block.svg b/doc/svg/ikSpdman_unit_block.svg
new file mode 100644
index 0000000..865d71e
--- /dev/null
+++ b/doc/svg/ikSpdman_unit_block.svg
@@ -0,0 +1,1622 @@
+
+
+
+
diff --git a/src/discon/discon.c b/src/discon/discon.c
deleted file mode 100644
index 3f6c221..0000000
--- a/src/discon/discon.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
-Copyright (C) 2017 IK4-IKERLAN
-
-This file is part of OpenDiscon.
-
-OpenDiscon is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-OpenDiscon is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with OpenDiscon. If not, see .
-*/
-
-#define NINT(a) ((a) >= 0.0 ? (int) ((a)+0.5) : ((a)-0.5))
-
-#include "ikClwindconWTConfig.h"
-#include "OpenDiscon_EXPORT.h"
-#include
-
-void OpenDiscon_EXPORT DISCON(float *DATA, int FLAG, const char *INFILE, const char *OUTNAME, char *MESSAGE) {
- int err;
- static ikClwindconWTCon con;
- double output = -12.0;
- static FILE *f = NULL;
- const double deratingRatio = 0.2; /* later to be got via the supercontroller interface */
-
- if (NINT(DATA[0]) == 0) {
- ikClwindconWTConParams param;
- ikClwindconWTCon_initParams(¶m);
- setParams(¶m);
- ikClwindconWTCon_init(&con, ¶m);
- f = fopen("log.bin", "wb");
- }
-//TODO lower maximum torque according to maximum power with derating (it may be time to bring the power manager back)
- con.in.deratingRatio = deratingRatio;
- con.in.externalMaximumTorque = 230.0; /* kNm */
- con.in.externalMinimumTorque = 0.0; /* kNm */
- con.in.externalMaximumPitch = 90.0; /* deg */
- con.in.externalMinimumPitch = 0.0; /* deg */
- con.in.generatorSpeed = (double) DATA[19]; /* rad/s */
- con.in.maximumSpeed = 480.0/30*3.1416; /* rpm to rad/s */
-
- ikClwindconWTCon_step(&con);
-
- DATA[46] = (float) (con.out.torqueDemand*1.0e3); /* kNm to Nm */
- DATA[41] = (float) (con.out.pitchDemandBlade1/180.0*3.1416); /* deg to rad */
- DATA[42] = (float) (con.out.pitchDemandBlade2/180.0*3.1416); /* deg to rad */
- DATA[43] = (float) (con.out.pitchDemandBlade3/180.0*3.1416); /* deg to rad */
- DATA[44] = (float) (con.out.pitchDemandBlade1/180.0*3.1416); /* deg to rad (collective pitch angle) */
-
- err = ikClwindconWTCon_getOutput(&con, &output, "maximum torque");
- fwrite(&(output), 1, sizeof(output), f);
-}