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
==20000create 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-statehas a uniqueactiveStatevalue. EachID-statefollows the naming scheme ofYxx, whereYis the decimal for the state, andxxis 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
enteredStateIDandfinishedStateID.If it is designed as an OnlineID-state, the output
enteredStateIDis sufficient.
Give the state an appropriate name in the scheme of
StateIDi.e.ElectricalID. It should look like this:
The ParameterID is shipped with a
.matfile 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_tand add all config values to this bus.Add a new bus for the state-specific output/identification values
uz_ParaID_StateID_output_tand add all necessary values.Open the
uz_ParaID_GlobalConfig_tbus and add a newbooleanmember with the nameStateID.Open the
uz_ParaID_ControlFlags_tbus and add a newbooleanmember 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_tbus with the nameStateIDConfigas input to the new Stateflow.Add the
uz_ParaID_StateID_output_tbus with the nameStateID_state_outputas output to the new Stateflow.Give the new subsystem the name
StateID_subsystem.To clean up the signal flow,
Go-toandFromblocks are used.Copy the three appropriate input
From-blocks (GlobalConfig, ActualValues, ControlFlags) from another state and connect them.Copy the output
Go-toblock 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-toblocks from another state and adjust the names and colors.Add the
Fromblock 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
configat the top of the ParameterID. Don’t forget to add the new entry to theGlobalConfigBuscreator.
Add the
Go-toblock subsystem to the appropriate output of the subsystem to connect to the already existingFromblock.Add the corresponding
Fromblocks forenteredStateIDandfinishedStateIDto the ControlState as input and adjust the colors.
Inside the ControlState, create a new variable called
finishedStateID_loc.Initialize it in the
InitParamsfunction, 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-stateand adjust the variables.
Open the
decideIDstatesfunction 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 stateand thesuper statefrom a differentID-stateand 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
initParamsand thereset_FOC_output(if the struct Controller parameters struct is used) and adjust them accordingly.Now you can create substates in the
super stateand fill them with functionality/code.
If the Controller parameters struct is used, add its corresponding
Fromblock to the FOC subsystem and adjust the code inside the functionBusselectoraccordingly.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
../Subsystemfolder and give it an appropriate name (i.e. StateID_ref.slx). The_refappendix 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_ParameterIDfolder 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_tanduz_ParaID_StateID_output_t) from the codegenerated header fileStateID_codegen.h.Paste them into the
uz_ParameterID_data.hfile, 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.hfile and add the missing struct members touz_ParameterID_data.h.Remove the declaration of these global structs in the
StateID_codegen.hfile.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.hfile to theuz_ParameterID.hfile.Add the new
uz_ParaID_StateIDConfig_tanduz_ParaID_StateID_output_tto the Global ParameterID Data struct in theuz_ParameterID_data.hfile. 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_structsfunction (like for the other states). Assign the address of the output struct here as well.Add the new state to the
uz_ParameterID_tdeclaration anduz_ParameterID_initfunction.Add new
getandsetfunctions for all necessary in- and outputs to theuz_ParaID_StateID.c/.hfiles (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.cfile, 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_stepfunction and change the names accordingly.If it is designed as an Offline-state, use the following template. Adjust the transition number
xaccordingly. 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_Controlleranduz_ParameterID_generate_DutyCyclefunctions. Otherwise, write new functions for this.