Guide to create a new ID-state#
The current ID-states
carry a wide range of identification methods.
However, if a new identification method is supposed to be implemented, this guide will assist in creating a new ID-state
.
Before starting the procedure of creating a new state, it is advised to read up about the general concept and layout of the ParmeterID in ParameterID, Setup and functions of the ParameterID, Structs for ParameterID_Data and Change control algorithm for ParameterID.
General information#
To ensure proper independence of the Stateflow from the sampleTime, try to make if-statements with a counter value in relation to the sampleTime. (instead of
==20000
create a variable in the init-functions of the stateflow withtwo_seconds_counter==uint32(2/GlobalConfig.sampleTimeISR)
).Avoid i.e.
after(1.0,sec)
state transition conditions. Create custom counter values for, i.e., 1-second delays. Otherwise, the transition won’t scale with different sample times.A three-phase testbench setup with a PMSM, inverter, load machine, and physical couplings is included in the subsystem
Hardware
. This can be used to test the new Stateflow.To signal which state is currently active, each state in one
ID-state
has a uniqueactiveState
value. EachID-state
follows the naming scheme ofYxx
, whereY
is the decimal for the state, andxx
is the decimal for the sub-states (i.e., 621).The simulink model resides in the ParameterID docs folder
docs/source/mpsoc/software_framework/ParameterID/simulink_model
.The ParameterID simulink model uses subsystem references to include the various ID-States. This has the advantage that
ID-States
, which work even for different ParameterID configurations (i.e., 3ph, 6ph, 9ph, etc.), can be referenced. This ensures that less code duplication is needed.
Changes in the simulation model#
Open the ParameterID model and insert a new chart.
Add the necessary inputs. These most likely include Global config struct, Control flags struct and Actual values struct.
If applicable, add the Controller parameters struct bus as output with the name.
Select the appropriate bus types for the inputs and outputs. I.e., for the ControlFlags bus.
Add acknowledgement flags as outputs of the state.
If the state is designed as an OfflineID-state, add two outputs with the names
enteredStateID
andfinishedStateID
.If it is designed as an OnlineID-state, the output
enteredStateID
is sufficient.
Give the state an appropriate name in the scheme of
StateID
i.e.ElectricalID
. It should look like this:The ParameterID is shipped with a
.mat
file which includes all necessary busses. Open it with the bus editor.Note
Stick to the data types
boolean
,single
, and if necessaryuint32
. Do not usedouble
, since the UltraZohm PS has no dedicated hardware for FP64 calculations.Add a new bus for the state-specific configuration values
uz_ParaID_StateIDConfig_t
and add all config values to this bus.Add a new bus for the state-specific output/identification values
uz_ParaID_StateID_output_t
and add all necessary values.Open the
uz_ParaID_GlobalConfig_t
bus and add a newboolean
member with the nameStateID
.Open the
uz_ParaID_ControlFlags_t
bus and add a newboolean
member with the namestartStateID
. If it is an Online-state, addenableStateID
.Save the file by exporting it and overwriting the old one.
Add the
uz_ParaID_StateIDConfig_t
bus with the nameStateIDConfig
as input to the new Stateflow.Add the
uz_ParaID_StateID_output_t
bus with the nameStateID_state_output
as output to the new Stateflow.Give the new subsystem the name
StateID_subsystem
.To clean up the signal flow,
Go-to
andFrom
blocks are used.Copy the three appropriate input
From
-blocks (GlobalConfig, ActualValues, ControlFlags) from another state and connect them.Copy the output
Go-to
block from another state, change its name to the state namestateID_FOC_output
, and adjust its color accordingly. This type of output block has different shades of blue.Copy the appropriate entered/finishedStateID
Go-to
blocks from another state and adjust the names and colors.Add the
From
block for the individual config bus in the appropriate color.Add the config setup, similar to the other states, for this state in the subsystem called
config
at the top of the ParameterID. Don’t forget to add the new entry to theGlobalConfig
Buscreator.Add the
Go-to
block subsystem to the appropriate output of the subsystem to connect to the already existingFrom
block.Add the corresponding
From
blocks forenteredStateID
andfinishedStateID
to the ControlState as input and adjust the colors.
Inside the ControlState, create a new variable called
finishedStateID_loc
.Initialize it in the
InitParams
function, similar to the other variables.Add the passthrough of the
StateID
-member of the GlobalConfig at the entry of the Superstate.For OfflineID states
Copy the three substates from another
ID-state
and adjust the variables.Open the
decideIDstates
function and adjust the code appropriately.
1if(GlobalConfig_in.StateID==0) 2 finishedStateID_loc=uint16(1); 3elseif(finishedStateID==1) 4 finishedStateID_loc=uint16(2); 5end 6%Determine path through the StateID-Stateflows 7if(GlobalConfig_in.StateID==1 && enteredStateID==0 && finishedElectricalID_loc~=0.... 8 && finishedTwoMassID_loc~=0 && finishedFrictionID_loc~=0 && finished FluxMapID_loc~=0 && finishedStateID_loc~=2 && finishedStateID==0) 9 ControlFlags.transNr=uint16(5); 10 finishedStateID_loc = uint16(0); 11end 12//Add the new stateID to the latest if-statement 13if(finishedElectricalID_loc~=0 && finishedTwoMassID_loc~=0 && .... 14 finishedFrictionID_loc~=0 && finishedFluxMapID_loc~=0 && finishedStateID_loc ~=0) 15 ControlFlags.finished_all_Offline_states = boolean(1); 16end
For OnlineID state
If its an OnlineID state, just add another if-else statement to the decideMotorID state
1if(ControlFlags.finished_all_Offline_states == 1 && GlobalConfig_in.StateID==1 && enteredStateID==0) 2 ControlFlags.enableStateID=boolean(1); 3elseif (ControlFlags.finished_all_Offline_states == 1 && GlobalConfig_in.StateID==0 && enteredStateID==1) 4 ControlFlags.enableStateID=boolean(0); 5end
Add a superstate to the new Stateflow.
Add an empty state next to the
super state
. This will work as theidle state
.Copy the transitions between the
idle state
and thesuper state
from a differentID-state
and adjust them according to the new state name. OfflineID and OnlineID states do have different transition conditions, so be wary of which state you copy these.Copy the
initParams
and thereset_FOC_output
(if the struct Controller parameters struct is used) and adjust them accordingly.Now you can create substates in the
super state
and fill them with functionality/code.If the Controller parameters struct is used, add its corresponding
From
block to the FOC subsystem and adjust the code inside the functionBusselector
accordingly.After the in- and output signals are connected, right-click on the new Stateflow.
Go to Subsystem & Model references .
Go to Convert To .
Go to Referenced Model… .
Now save the newly created state-subsystem in the
../Subsystem
folder and give it an appropriate name (i.e. StateID_ref.slx). The_ref
appendix to the name is important; otherwise, Matlab gets confused with the names during code generation.
It should look similar to this.
Add a new switch for the new Stateflow to the already existing ones.
Changes in the UltraZohm software#
After code generation of the Stateflow, the following changes must be made in the UltraZohm software repository.
Create a new subfolder in the
Baremetal/src/uz/uz_ParameterID
folder with the appropriate name.Copy the code generated .h and .c file into this folder and rename them to
StateID_codegen.c/h
.Add the following changes to the .h file.
1#include "../uz_ParameterID_data.h" 2#include "../rtwtypes.h" 3 4//generated code
Copy the individual structs (
uz_ParaID_StateIDConfig_t
anduz_ParaID_StateID_output_t
) from the codegenerated header fileStateID_codegen.h
.Paste them into the
uz_ParameterID_data.h
file, add doxygen comments and remove them fromStateID_codegen.h
.Compare the global structs (Actual values struct , Global config struct , Control flags struct , Controller parameters struct) in the code generated header file with the ones in the
uz_ParameterID_data.h
file and add the missing struct members touz_ParameterID_data.h
.Remove the declaration of these global structs in the
StateID_codegen.h
file.Add the following changes to the .c file
1#include "StateID_codegen.h" 2#include "../../uz_global_configuration.h" 3#if UZ_PARAMETERID_MAX_INSTANCES > 0U 4#include <math.h> 5#include <string.h> 6 7//generated code 8 9#endif
Add a new .h and .c file with the names
uz_ParaID_StateID.c/h
.Add the license header to the files.
Add the following code to the .h and .c file and adjust the names accordingly.
1#ifndef UZ_PARAID_STATEID_H 2#define UZ_PARAID_STATEID_H 3 4#include "StateID_codegen.h" 5 6/** 7* @brief Object definition for uz_ParaID_StateID_t 8* 9*/ 10typedef struct uz_ParaID_StateID_t{ 11 ExtY_StateID_t output; 12 ExtU_StateID_t input; 13 DW_StateID_t rtDW; /* Observable states */ 14 RT_MODEL_StateID_t modelData; 15 RT_MODEL_StateID_t *PtrToModelData; 16} uz_ParaID_StateID_t; 17 18/** 19* @brief Initializes the uz_ParaID_StateID_t object 20* 21* @return uz_ParaID_StateID_t* pointer to object 22*/ 23uz_ParaID_StateID_t* uz_StateID_init(void); 24 25/** 26* @brief steps the StateID state once 27* 28* @param self pointer to uz_ParaID_StateID_t* object 29*/ 30void uz_StateID_step(uz_ParaID_StateID_t *self);
1#include "../../uz_global_configuration.h" 2#if UZ_PARAMETERID_MAX_INSTANCES > 0U 3#include "uz_ParaID_StateID.h" 4#include "../../uz_HAL.h" 5 6static uint32_t instances_counter_ParaID_StateID = 0; 7 8static uz_ParaID_StateID_t instances_ParaID_StateID[UZ_PARAMETERID_MAX_INSTANCES] = { 0 }; 9 10static uz_ParaID_StateID_t* uz_ParaID_StateID_allocation(void); 11 12static uz_ParaID_StateID_t* uz_ParaID_StateID_allocation(void) { 13 uz_assert(instances_counter_ParaID_StateID < UZ_PARAMETERID_MAX_INSTANCES); 14 uz_ParaID_ControlState_t* self = &instances_ParaID_StateID[instances_counter_ParaID_StateID]; 15 instances_counter_ParaID_StateID++; 16 return (self); 17} 18 19uz_ParaID_StateID_t* uz_StateID_init(void) { 20 uz_ParaID_StateID_t* self = uz_ParaID_StateID_allocation(); 21 self->PtrToModelData = &self->modelData; 22 self->PtrToModelData->dwork = &self->rtDW; 23 self->PtrToModelData->inputs = &self->input; 24 self->PtrToModelData->outputs = &self->output; 25 StateID_initialize(self->PtrToModelData); 26 return (self); 27} 28 29void uz_StateID_step(uz_ParaID_StateID_t *self) { 30 uz_assert_not_NULL(self); 31 StateID_step(self->PtrToModelData); 32} 33#endif
Include the
uz_ParaID_StateID.h
file to theuz_ParameterID.h
file.Add the new
uz_ParaID_StateIDConfig_t
anduz_ParaID_StateID_output_t
to the Global ParameterID Data struct in theuz_ParameterID_data.h
file. Add the output struct as a pointer, similar to the other output structs.Add default values for the config struct to the
uz_ParameterID_initialize_data_structs
function (like for the other states). Assign the address of the output struct here as well.Add the new state to the
uz_ParameterID_t
declaration anduz_ParameterID_init
function.Add new
get
andset
functions for all necessary in- and outputs to theuz_ParaID_StateID.c/.h
files (similar to the otherID-States
). For example, a set function for the GlobalConfig.1void uz_StateID_set_GlobalConfig(uz_ParaID_StateID_t *self, uz_ParaID_GlobalConfig_t GlobalConfig) { 2 uz_assert_not_NULL(self); 3 uz_assert(self->is_ready); 4 self->input.GlobalConfig_out = GlobalConfig; 5}
Add a new static step function to the
uz_ParameterID.c
file, which wraps the assignment of inputs & outputs and step-function call.1static void uz_ParaID_StateID_step(uz_ParameterID_t* self, uz_ParameterID_Data_t* Data) { 2 uz_assert_not_NULL(self); 3 uz_assert_not_NULL(Data); 4 //Update State-Inputs 5 uz_StateID_set_ActualValues(self->StateID, Data->ActualValues); 6 uz_StateID_set_Config(self->StateID, Data->StateID_Config); 7 uz_StateID_set_GlobalConfig(self->StateID, *uz_ControlState_get_GlobalConfig(self->ControlState)); 8 uz_StateID_set_ControlFlags(self->StateID, uz_ControlState_get_ControlFlags(self->ControlState)); 9 10 //Step the function 11 uz_StateID_step(self->StateID); 12 13 //Update Control-State-inputs 14 uz_ControlState_set_enteredStateID(self->ControlState, uz_StateID_get_enteredStateID(self->StateID)); 15 uz_ControlState_set_finishedStateID(self->ControlState, uz_StateID_get_finishedStateID(self->StateID)); 16}
Add the step function to the
uz_ParameterID_step
function and change the names accordingly.If it is designed as an Offline-state, use the following template. Adjust the transition number
x
accordingly. Add the new transition number to the switch-case accordingly.1//StateID 2if (uz_ControlState_get_ControlFlags(self->ControlState)->transNr == xU || uz_ControlState_get_GlobalConfig(self->ControlState)->Reset == true) { 3 uz_ParaID_StateID_step(self, Data); 4} else if (uz_ControlState_get_GlobalConfig(self->ControlState)->StateID == false && uz_StateID_get_enteredStateID(self->StateID) == true) { 5 uz_ParaID_StateID_step(self, Data); 6} 7 8// 9switch (uz_ControlState_get_ControlFlags(self->ControlState)->transNr) { 10 11.... 12//other cases 13.... 14case xU: 15 Data->Controller_Parameters = self->StateID->output.StateID_FOC_output; 16 break; 17.... 18//Rest of code
If it is designed as an Online-state, use the following template:
1//StateID 2if (uz_ControlState_get_ControlFlags(self->ControlState)->enableStateID == true || uz_ControlState_get_GlobalConfig(self->ControlState)->Reset == true) { 3 uz_ParaID_StateID_step(self, Data); 4}
All necessary changes are now done. Depending on your setup, respectively the purpose of the new
ID-state
, it may be feasible to adjust theuz_ParameterID_Controller
anduz_ParameterID_generate_DutyCycle
functions. Otherwise, write new functions for this.