Setup and functions of the ParameterID#

This page details the steps to setup the ParameterID in the UltraZohm software project.

Setup#

Listing 108 Example to initialize the ParameterID. The ParameterID must be initialized before the Javascope is initialized.#
 1#include "uz/uz_ParameterID/uz_ParameterID.h"
 2#include "uz/uz_math_constants.h"
 3
 4//ParameterID Code
 5uz_ParameterID_t* ParameterID = NULL;
 6uz_ParameterID_Data_t ParaID_Data = { 0 };
 7//Objects below are only needed, if the uz_FOC is used as the controller
 8uz_CurrentControl_t* CC_instance = NULL;
 9uz_SpeedControl_t* SC_instance = NULL;
10uz_SetPoint_t* SP_instance = NULL;
11
12int main(void) {
13    ParameterID = uz_ParameterID_init(&ParaID_Data);
14   //Code below is only needed if the uz_FOC is used as the controller
15   struct uz_PI_Controller_config config_id = {
16        .Kp = ParaID_Data.GlobalConfig.Kp_id,
17        .Ki = ParaID_Data.GlobalConfig.Ki_id,
18        .samplingTime_sec = 0.0001f,
19        .upper_limit = 15.0f,
20        .lower_limit = -15.0f };
21   struct uz_PI_Controller_config config_iq = {
22        .Kp = ParaID_Data.GlobalConfig.Kp_iq,
23        .Ki = ParaID_Data.GlobalConfig.Ki_iq,
24        .samplingTime_sec = 0.0001f,
25        .upper_limit = 15.0f,
26        .lower_limit = -15.0f };
27   struct uz_SpeedControl_config config_SC = {
28        .config_controller.Kp = ParaID_Data.GlobalConfig.Kp_n,
29        .config_controller.Ki = ParaID_Data.GlobalConfig.Ki_n,
30        .config_controller.samplingTime_sec = 0.0001f,
31        .config_controller.upper_limit = 10.0f,
32        .config_controller.lower_limit = -10.0f };
33   struct uz_CurrentControl_config config_CC = {
34        .config_PMSM = ParaID_Data.GlobalConfig.PMSM_config,
35        .config_id = config_id,
36        .config_iq = config_iq,
37        .max_modulation_index = 1.0f/sqrtf(3.0f) }; //for SpaceVectorModulation
38   struct uz_SetPoint_config config_SP = {
39      .config_PMSM = ParaID_Data.GlobalConfig.PMSM_config,
40      .control_type = FOC,
41      .id_ref_Ampere = 0.0f,
42      .is_field_weakening_enabled = false,
43      .motor_type = SMPMSM };
44   CC_instance = uz_CurrentControl_init(config_CC);
45   SC_instance = uz_SpeedControl_init(config_SC);
46   SP_instance = uz_SetPoint_init(config_SP);
47   //Initialize the code above before the JavaScope is initialized
48   //....
49   JavaScope_initialize(&Global_Data);
50}

In the uz_ParameterID_init function, the struct of the type uz_ParameterID_Data_t is also initialized. This struct carries, among other things, the configuration values of the ParameterID. To ease the setup of the ParameterID, this struct is initialized with default values. To configure the ParameterID to your needs, change the values inside the uz_ParameterID_initialize_data_structs function. Especially the configuration of the motor-related parameters is important. If they are not known, they can be left at 0.0f. In this case, however, these parameters have to be identified first by using the ElectricalID state. The ID-state-specific configuration values can later be configured via the uz_GUI.

Listing 109 Code to initialize uz_ParameterID_Data_t. Important parts are highlighted.#
 1	uz_assert_not_NULL(self);
 2	uz_assert_not_NULL(Data);
 3	//Initialize Global-Config
 4	Data->GlobalConfig.ACCEPT = false;
 5	Data->GlobalConfig.Reset = false;
 6	Data->GlobalConfig.enableParameterID = false;
 7	Data->GlobalConfig.ElectricalID = false;
 8	Data->GlobalConfig.FluxMapID = false;
 9	Data->GlobalConfig.FrictionID = false;
10	Data->GlobalConfig.TwoMassID = false;
11	Data->GlobalConfig.OnlineID = false;
12	Data->GlobalConfig.sampleTimeISR = 100.0e-06f;
13
14	//Initialize motor-related parameters inside Global-Config
15	Data->GlobalConfig.Ki_id = 158.8f;
16	Data->GlobalConfig.Ki_iq = 158.8f;
17	Data->GlobalConfig.Ki_n = 0.8f;
18	Data->GlobalConfig.Kp_id = 0.25;
19	Data->GlobalConfig.Kp_iq = 0.25f;
20	Data->GlobalConfig.Kp_n = 0.04f;
21	Data->GlobalConfig.PMSM_config.Ld_Henry = 2.90e-04f;
22	Data->GlobalConfig.PMSM_config.Lq_Henry = 3.00e-04f;
23	Data->GlobalConfig.PMSM_config.R_ph_Ohm = 0.105f;
24	Data->GlobalConfig.PMSM_config.Psi_PM_Vs = 0.0075f;
25	Data->GlobalConfig.PMSM_config.polePairs = 4.0f;
26	Data->GlobalConfig.PMSM_config.J_kg_m_squared = 3.24e-05f;
27	Data->GlobalConfig.PMSM_config.I_max_Ampere = 15.0f;
28	Data->GlobalConfig.ratCurrent = 8.0f;
29	Data->GlobalConfig.ratTorque = 0.29f;
30	Data->GlobalConfig.ratSpeed = 3000.0f;
31
32	//Initialize ElectricalID-Config
33	Data->ElectricalID_Config.goertzlFreq = 0.0f;
34	Data->ElectricalID_Config.dutyCyc = 0.0f;
35	Data->ElectricalID_Config.goertzlTorque= 0.0f;
36	Data->ElectricalID_Config.identLq = false;
37	Data->ElectricalID_Config.min_n_ratio = 0.015f;
38	Data->ElectricalID_Config.n_ref_measurement = 0.0f;
39
40	//Initialize FluxMapID-Config
41	Data->FluxMapID_Config.AMMsampleTime = 2.0f;
42	Data->FluxMapID_Config.IDstart = 0.0f;
43	Data->FluxMapID_Config.IDstepsize = 0.0f;
44	Data->FluxMapID_Config.IDstop = 0.0f;
45	Data->FluxMapID_Config.IQstart = 0.0f;
46	Data->FluxMapID_Config.IQstepsize = 0.0f;
47	Data->FluxMapID_Config.IQstop = 0.0f;
48	Data->FluxMapID_Config.R_s_ref = 0.0f;
49	Data->FluxMapID_Config.Temp_ref = 0.0f;
50	Data->FluxMapID_Config.identR = false;
51	Data->FluxMapID_Config.identRAmp = 0.0f;
52	Data->FluxMapID_Config.start_FM_ID = false;
53
54	//Initialize FrictionID-Config
55	Data->FrictionID_Config.BrkCount = 0.0f;
56	Data->FrictionID_Config.N_Brk = 0.0f;
57	Data->FrictionID_Config.N_Visco = 0.0f;
58	Data->FrictionID_Config.StepScale = 0.0f;
59	Data->FrictionID_Config.eta = 0.0f;
60	Data->FrictionID_Config.maxCurrent = 10.0f;
61	Data->FrictionID_Config.n_eva_max = 0.0f;
62
63	//Initialize OnlineID-Config
64	Data->OnlineID_Config.AverageTransParams = true;
65	Data->OnlineID_Config.OnlineID_Reset = false;
66	Data->OnlineID_Config.Rs_time = 0.0f;
67	Data->OnlineID_Config.Temp_ref = 0.0f;
68	Data->OnlineID_Config.allowPsiCalcOutside = false;
69	Data->OnlineID_Config.dev_curr = 0.05f;
70	Data->OnlineID_Config.dev_omega = 0.05f;
71	Data->OnlineID_Config.identRAmp = 2.0f;
72	Data->OnlineID_Config.max_n_ratio = 0.0f;
73	Data->OnlineID_Config.min_n_ratio = 0.0f;
74	Data->OnlineID_Config.nom_factor = 0.0f;
75	Data->OnlineID_Config.array_cleaned = false;
76
77	//Initialize Output data structs
78	Data->ElectricalID_Output = uz_ElectricalID_get_output(self->ElectricalID);
79	Data->FrictionID_Output = uz_FrictionID_get_output(self->FrictionID);
80	Data->FluxMapID_Output = uz_FluxMapID_get_output(self->FluxMapID);
81	Data->TwoMassID_Output = uz_TwoMassID_get_output(self->TwoMassID);
82	Data->OnlineID_Output = uz_OnlineID_get_output(self->OnlineID);
83	Data->ControlFlags = uz_ControlState_get_ControlFlags(self->ControlState);
84	Data->FluxMap_Data = uz_OnlineID_get_InterpMeshGrid_FluxMapData(self->OnlineID);
85
86	Data->calculate_flux_maps = false;
87	Data->FluxMap_counter = 0.0f;
88	Data->Psi_D_pointer = 0.0f;
89	Data->Psi_Q_pointer = 0.0f;
90	Data->ParaID_Control_Selection = No_Control;
91}
92

If the FluxMaps identification of the OnlineID state will be used, the following code has to be implemented inside the infinite_loop case of the switch case in the main.c. These functions are to compute heavy to be executed in the ISR.

Listing 110 Code to calculate FluxMaps inside the infinite_loop case of the switch case in the main.c .#
 1//....
 2case infinite_loop:
 3   ultrazohm_state_machine_step();
 4   if (ParaID_Data.OnlineID_Output->clean_array || ParaID_Data.OnlineID_reset_was_pressed) {
 5        uz_ParameterID_CleanPsiArray(ParameterID, &ParaID_Data);
 6        ParaID_Data.OnlineID_reset_was_pressed = false;
 7   }
 8   if (ParaID_Data.calculate_flux_maps) {
 9        uz_ParameterID_CalcFluxMaps(ParameterID, &ParaID_Data);
10        ParaID_Data.calculate_flux_maps = false;
11   }
12   break;
13//....

In the isr.c the members of the Actual values struct struct inside the Global ParameterID Data struct have to be assigned with the measurement values needed for the identification. Furthermore, the uz_ParameterID_step function needs to be called as well. Two functions, uz_ParameterID_Controller and uz_ParameterID_generate_DutyCycle, are also used in the code below. These exemplary functions are included in the ParameterID-library to ease its use. They include the uz_FOC and a function to generate the DutyCycles for the half-bridges. They are technically not required for the ParameterID and can be replaced by your own control algorithm.

Listing 111 Changes in the isr.c#
 1extern uz_ParameterID_Data_t ParaID_Data;
 2extern uz_ParameterID_t* ParameterID;
 3//Next lines only needed, if the uz_FOC is used as the controller
 4extern uz_CurrentControl_t* CC_instance;
 5extern uz_SpeedControl_t* SC_instance;
 6extern uz_SetPoint_t* SP_instance;
 7uz_3ph_dq_t ParaID_v_dq = { 0 };
 8struct uz_DutyCycle_t ParaID_DutyCycle = { 0 };
 9
10void ISR_Control(void *data) {
11   ParaID_Data.ActualValues.I_abc.a = ....;
12   ParaID_Data.ActualValues.I_abc.b = ....;
13   ParaID_Data.ActualValues.I_abc.c = ....;
14   ParaID_Data.ActualValues.V_DC = ....;
15   ParaID_Data.ActualValues.V_abc.a = ....;
16   ParaID_Data.ActualValues.V_abc.b = ....;
17   ParaID_Data.ActualValues.V_abc.c = ....;
18
19   ParaID_Data.ActualValues.omega_m = ....;
20   ParaID_Data.ActualValues.omega_el = ....;
21   ParaID_Data.ActualValues.theta_el = ....;
22
23   //Calculate missing ActualValues
24   ParaID_Data.ActualValues.i_dq = uz_transformation_3ph_abc_to_dq(ParaID_Data.ActualValues.I_abc, ParaID_Data.ActualValues.theta_el);
25   ParaID_Data.ActualValues.v_dq = uz_transformation_3ph_abc_to_dq(ParaID_Data.ActualValues.V_abc, ParaID_Data.ActualValues.theta_el);
26   ParaID_Data.ActualValues.theta_m = ....;
27
28   if (ultrazohm_state_machine_get_state() == control_state) {
29        uz_ParameterID_step(ParameterID, &ParaID_Data);
30        //Next lines only needed, if the uz_FOC is used as the controller
31        ParaID_v_dq = uz_ParameterID_Controller(&ParaID_Data, CC_instance, SC_instance, SP_instance);
32        //If Gate-output is on the first 6 DIG-IO Pins. Otherwise use different PWM object
33        ParaID_DutyCycle = uz_ParameterID_generate_DutyCycle(&ParaID_Data, ParaID_v_dq, Global_Data.objects.pwm_d1_pin_0_to_5);
34        Global_Data.rasv.halfBridge1DutyCycle = ParaID_DutyCycle.DutyCycle_A;
35        Global_Data.rasv.halfBridge2DutyCycle = ParaID_DutyCycle.DutyCycle_B;
36        Global_Data.rasv.halfBridge3DutyCycle = ParaID_DutyCycle.DutyCycle_C;
37   } else {
38        Global_Data.rasv.halfBridge1DutyCycle = 0.0f;
39        Global_Data.rasv.halfBridge2DutyCycle = 0.0f;
40        Global_Data.rasv.halfBridge3DutyCycle = 0.0f;
41   }
42  }

In the javascope.c the measurement values from ActualValues struct should be assigned to the js_ch_observable array.

Listing 112 changes to javascope.c#
 1extern uz_ParameterID_Data_t ParaID_Data;
 2
 3int JavaScope_initalize(DS_Data* data) {
 4   ....
 5   js_ch_observable[JSO_Speed_rpm]         = &data->av.mechanicalRotorSpeed;
 6   js_ch_observable[JSO_ia] = &ParaID_Data.ActualValues.I_abc.a;
 7   js_ch_observable[JSO_ib] = &ParaID_Data.ActualValues.I_abc.b;
 8   js_ch_observable[JSO_ic] = &ParaID_Data.ActualValues.I_abc.c;
 9   js_ch_observable[JSO_ua] = &ParaID_Data.ActualValues.V_abc.a;
10   js_ch_observable[JSO_ub] = &ParaID_Data.ActualValues.V_abc.b;
11   js_ch_observable[JSO_uc] = &ParaID_Data.ActualValues.V_abc.c;
12   js_ch_observable[JSO_iq] = &ParaID_Data.ActualValues.i_dq.q;
13   js_ch_observable[JSO_id] = &ParaID_Data.ActualValues.i_dq.d;
14   js_ch_observable[JSO_Theta_el] = &ParaID_Data.ActualValues.theta_el;
15   js_ch_observable[JSO_theta_mech] = &ParaID_Data.ActualValues.theta_m;
16   js_ch_observable[JSO_ud] = &ParaID_Data.ActualValues.v_dq.d;
17   js_ch_observable[JSO_uq] = &ParaID_Data.ActualValues.v_dq.q;
18   ....
19   }

The ParameterID is now setup and can be controlled via the debugger window. Since this is not recommended and potentially dangerous, the JavaScope has a separate panel to control the ParmaeterID. The additional setup steps are detailed in Setup.

Functions#

uz_ParameterID_t *uz_ParameterID_init(uz_ParameterID_Data_t *Data)#

Initializes the uz_ParameterID_t object and its sub-objects.

Parameters:
  • Data – pointer to uz_ParameterID_Data_t struct

Returns:

uz_ParameterID_t* pointer to uz_ParameterID_t object

This function inits the ParameterID itself and all subsequent states. Even though not all states my be used by the user, they will be initialized anyway. This is done to ensure data integrity and to guarantee, that every member of the Global ParameterID Data struct is declared. Furthermore the Global ParameterID Data struct itself is initialized here as well.

void uz_ParameterID_step(uz_ParameterID_t *self, uz_ParameterID_Data_t *Data)#

steps the ParameterID once and updates the output values of the ID-states

Parameters:
  • self – pointer to uz_ParameterID_t object

  • Data – pointer to uz_ParameterID_Data_t struct

This function steps the ParameterID once per cycle. It implements everything necessary shown in the blue block in Fig. 287. To eliminate unnecessary function calls and improve the execution time of this function, only the ControlState will always be stepped. Every other ID-state is guarded behind if-statements. Furthermore, it determines which Controller parameters struct will be written to the output.

struct uz_DutyCycle_t uz_ParameterID_generate_DutyCycle(uz_ParameterID_Data_t *Data, uz_3ph_dq_t v_dq_Volts, uz_PWM_SS_2L_t *PWM_Module)#

Generates a DutyCycle corresponding to the commands from the uz_ParameterID_step function. To calculate the reference voltages of the uz_ParameterID_Controller function into DutyCycles for the inverter, the Space Vector Modulation is used. This is meant as an example function, to ease the initial setup of the ParameterID. This function is however not essential to the ParamterID itself and can be replaced at will.

Parameters:
  • Data – pointer to uz_ParameterID_Data_t struct

  • v_dq_Volts – reference voltage from control algorithm

  • PWM_Module – pointer to uz_PWM_SS_2L_t object

Returns:

struct uz_DutyCycle_t DutyCycles for the inverter

uz_3ph_dq_t uz_ParameterID_Controller(uz_ParameterID_Data_t *Data, struct uz_ParameterID_controller objects)#

Exemplary control algorithm (FOC) for the use of the ParameterID. It uses the SpeedControl, SetPoint and CurrentControl module. This is meant as an example function, to ease the initial setup of the ParameterID. This function is however not essential to the ParamterID itself and can be replaced at will.

Parameters:
  • Data – pointer to uz_ParameterID_Data_t struct

  • CC_instance – pointer to uz_CurrentControl_t object

  • SC_instance – pointer to uz_SpeedControl_t object

  • SP_instance – pointer to uz_SetPoint_t object

Returns:

struct uz_3ph_dq_t reference voltages of controller

void uz_ParameterID_CleanPsiArray(uz_ParameterID_t *self, uz_ParameterID_Data_t *Data)#

This function is cleaning the array storing the measurement values, which always consists of a d-q-current combination, a winding temperature and a speed value such as a d-q-flux combination The function is searching for measuring pairs which are closer than “eta_c” to their neighbors. In this case it is averaging these similar pairs to avoid measuring values containing the same information.

Parameters:
  • self – pointer to uz_ParameterID_t object

  • Data – pointer to uz_ParameterID_Data_t struct

void uz_ParameterID_CalcFluxMaps(uz_ParameterID_t *self, uz_ParameterID_Data_t *Data)#

This function is calculating the regular flux maps out of the irregular scatter data array. The outputs is written onto the member FluxMap_Data of the uz_ParameterID_Data_t struct.

Parameters:
  • self – pointer to uz_ParameterID_t object

  • Data – pointer to uz_ParameterID_Data_t struct

void uz_ParameterID_update_transmit_values(uz_ParameterID_Data_t *Data, float *activeState, float *FluxMapCounter, float *ArrayCounter)#

updates transmit values/Converts some int-values from the ParameterID to float and helps to sync the array transmission

Parameters:
  • Data – pointer to uz_ParameterID_Data_t struct

  • activeState – pointer to float variable of activeState

  • FluxMapCounter – pointer to float variable of FluxMapCounter

  • ArrayCounter – pointer to float variable of ArrayCounter

References#

typedef struct uz_ParameterID_t uz_ParameterID_t#

Object definition for uz_ParameterID_t.

typedef float real32_T#
typedef unsigned char boolean_T#
typedef unsigned short uint16_T#
typedef unsigned int uint32_T#