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 with two_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 unique activeState value. Each ID-state follows the naming scheme of Yxx, where Y is the decimal for the state, and xx 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#

  1. Open the ParameterID model and insert a new chart.

  2. Add the necessary inputs. These most likely include Global config struct, Control flags struct and Actual values struct.

  3. If applicable, add the Controller parameters struct bus as output with the name.

  4. Select the appropriate bus types for the inputs and outputs. I.e., for the ControlFlags bus.

    ../../../../_images/assign_bus.png
  5. Add acknowledgement flags as outputs of the state.

    • If the state is designed as an OfflineID-state, add two outputs with the names enteredStateID and finishedStateID.

    • If it is designed as an OnlineID-state, the output enteredStateID is sufficient.

  6. Give the state an appropriate name in the scheme of StateID i.e. ElectricalID. It should look like this:

    ../../../../_images/chart_first_look.png
  7. 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 necessary uint32. Do not use double, 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 new boolean member with the name StateID.

    • Open the uz_ParaID_ControlFlags_t bus and add a new boolean member with the name startStateID. If it is an Online-state, add enableStateID.

      ../../../../_images/Bus_editor.png
    • Save the file by exporting it and overwriting the old one.

  8. Add the uz_ParaID_StateIDConfig_t bus with the name StateIDConfig as input to the new Stateflow.

  9. Add the uz_ParaID_StateID_output_t bus with the name StateID_state_output as output to the new Stateflow.

  10. Give the new subsystem the name StateID_subsystem .

  11. To clean up the signal flow, Go-to and From 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 name stateID_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.

      ../../../../_images/inputs_outputs2.png
    • 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 the GlobalConfig Buscreator.

      ../../../../_images/config_buscreator.png
    • Add the Go-to block subsystem to the appropriate output of the subsystem to connect to the already existing From block.

    • Add the corresponding From blocks for enteredStateID and finishedStateID to the ControlState as input and adjust the colors.

      ../../../../_images/ControlState_changes.png
  12. Inside the ControlState, create a new variable called finishedStateID_loc.

  13. Initialize it in the InitParams function, similar to the other variables.

  14. 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.

        ../../../../_images/ControlState_changes2.png
      • Open the decideIDstates function and adjust the code appropriately.

      Listing 122 Addition to the decideIDstates function#
       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

      Listing 123 Addition to the decideIDstates function#
      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
      
  15. Add a superstate to the new Stateflow.

  16. Add an empty state next to the super state. This will work as the idle state.

  17. Copy the transitions between the idle state and the super state from a different ID-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.

  18. Copy the initParams and the reset_FOC_output (if the struct Controller parameters struct is used) and adjust them accordingly.

  19. Now you can create substates in the super state and fill them with functionality/code.

    ../../../../_images/stateID.png
  20. If the Controller parameters struct is used, add its corresponding From block to the FOC subsystem and adjust the code inside the function Busselector accordingly.

  21. 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.

  22. It should look similar to this.

    ../../../../_images/inputs_outputs3.png
  23. 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.

  1. Create a new subfolder in the Baremetal/src/uz/uz_ParameterID folder with the appropriate name.

  2. Copy the code generated .h and .c file into this folder and rename them to StateID_codegen.c/h.

  3. Add the following changes to the .h file.

    Listing 124 Changes made to the code generated header file#
    1#include "../uz_ParameterID_data.h"
    2#include "../rtwtypes.h"
    3
    4//generated code
    
  4. Copy the individual structs (uz_ParaID_StateIDConfig_t and uz_ParaID_StateID_output_t) from the codegenerated header file StateID_codegen.h.

  5. Paste them into the uz_ParameterID_data.h file, add doxygen comments and remove them from StateID_codegen.h.

  6. 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 to uz_ParameterID_data.h.

  7. Remove the declaration of these global structs in the StateID_codegen.h file.

  8. Add the following changes to the .c file

    Listing 125 Changes made to the code generated source 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
    
  9. Add a new .h and .c file with the names uz_ParaID_StateID.c/h.

  10. Add the license header to the files.

  11. Add the following code to the .h and .c file and adjust the names accordingly.

    Listing 126 Code for the new .h file#
     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);
    
    Listing 127 Code for the new .c file#
     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
    
  12. Include the uz_ParaID_StateID.h file to the uz_ParameterID.h file.

  13. Add the new uz_ParaID_StateIDConfig_t and uz_ParaID_StateID_output_t to the Global ParameterID Data struct in the uz_ParameterID_data.h file. Add the output struct as a pointer, similar to the other output structs.

  14. 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.

  15. Add the new state to the uz_ParameterID_t declaration and uz_ParameterID_init function.

  16. Add new get and set functions for all necessary in- and outputs to the uz_ParaID_StateID.c/.h files (similar to the other ID-States ). For example, a set function for the GlobalConfig.

    Listing 128 Template code for static step function#
    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}
    
  17. Add a new static step function to the uz_ParameterID.c file, which wraps the assignment of inputs & outputs and step-function call.

    Listing 129 Template code for static step function#
     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}
    
  18. 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.

      Listing 130 Code for uz_ParameterID_step function for Offline-state.#
       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:

      Listing 131 Code for uz_ParameterID_step function for Online-state.#
      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}
      
  19. All necessary changes are now done. Depending on your setup, respectively the purpose of the new ID-state, it may be feasible to adjust the uz_ParameterID_Controller and uz_ParameterID_generate_DutyCycle functions. Otherwise, write new functions for this.