Multi-phase PMSM Model#

Important:

  • The multi-phase PMSM IP-cores are based on the three-phase PMSM Model IP-core, where the basics (e.g. working principle of the integrations is explained)

  • There are two mulit-phase IP-cores, a six-phase and a nine-phase one

Differences to the three-phase PMSM model IP-core:

  • IP-Cores model a six-phase and nine-phase PMSM

  • Sample frequency of the integrator is \(T_s=\frac{1}{1\,MHz}\)

  • IP-Core clock frequency must be \(f_{clk}=100\,MHz\)!

  • All calculations in the IP-Core are done in double precision

  • Interfaces to PL are realized in fixedpoint, while interfaces to the PS use single precision float values

System description#

The modelling of the multi-phase machine is based on [[1]]. The general idea in this work and also the common approach to model multi-phase machines is, to transform the phase variables with the VSD and Park transformations, as shown and done in Multi-phase VSD and Park transformation IP-Core and Coordinate Transformation. Transformed voltages are used as input for this IP-core and the outputs will also be in the rotary or stationary reference frame ant not phase variables. This IP-core contains the electric differential equations and the mechanical part, where the torque is calculated. Additionally, either a torque load or a fixed speed can be set to test the machine model. While the equations are mostly similar to the ones of the three-phase PMSM Model, they will be shown here again for the sake of completeness. To obtain more details about the equations and integrators, reading PMSM Model is advised.

dq equations#

\[\begin{split}\begin{align} \psi_{d}(k+1) &= T_s \big( v_{d}(k) - R_{1} i_{d}(k) + \omega_{el} \psi_{q}(k) \big) + \psi_{d}(k)\\ \psi_{q}(k+1) &= T_s \big( v_{q}(k) - R_{1} i_{q}(k) - \omega_{el} \psi_{d}(k) \big) + \psi_{q}(k)\\ \psi_{d}(k) &= \psi_{PM} + L_{d} i_{d}(k) \\ \psi_{q}(k) &= L_{q} i_{q}(k) \label{eq:psiq_ld} \end{align}\end{split}\]

Mechanical equations#

\[\begin{split}\begin{align} M_M &= \frac{9}{2}\cdot{p}\cdot{(\Psi_{PM}\cdot{i_q}+(L_d-L_q)\cdot{i_d}\cdot{i_q})}\\ \theta_{el}(k+1) &= T_s \big(\omega_{mech}(k)\cdot{p}) + \theta_{el}(k)\\ \omega_{mech}(k+1) &= T_s \bigg( \frac{M_M(k)-M_L(k)}{J} \bigg) + \omega_{mech}(k) \end{align}\end{split}\]

Note that the integrator for \(\theta_{el}\) is limited to \(\pm \pi\) to avoid overflow (wrapping integrator).

Additional system equations#

Six-phase model#

\[\begin{split}\begin{align} \psi_{x}(k+1) &= T_s \big( v_{x}(k) - R_{1} i_{x}(k))+\psi_{x}(k)\\ \psi_{x}(k) &= L_{ls} i_{x}(k) \\ \psi_{y}(k+1) &= T_s \big( v_{y}(k) - R_{1} i_{y}(k))+\psi_{y}(k)\\ \psi_{y}(k) &= L_{ls} i_{y}(k) \\ \psi_{zi}(k+1) &= T_s \big( v_{zi}(k) - R_{1} i_{zi}(k))+\psi_{zi}(k)\\ \psi_{zi}(k) &= L_{ls} i_{zi}(k) \\ \nonumber\textrm{with } i&=1,2 \end{align}\end{split}\]

Nine-phase model#

\[\begin{split}\begin{align} \psi_{xi}(k+1) &= T_s \big( v_{xi}(k) - R_{1} i_{xi}(k))+\psi_{xi}(k)\\ \psi_{xi}(k) &= L_{ls} i_{xi}(k) \\ \psi_{yi}(k+1) &= T_s \big( v_{yi}(k) - R_{1} i_{yi}(k))+\psi_{yi}(k)\\ \psi_{yi}(k) &= L_{ls} i_{yi}(k) \\ \psi_{0}(k+1) &= T_s \big( v_{0}(k) - R_{1} i_{0}(k))+\psi_{0}(k) \\ \psi_{0}(k) &= L_{ls} i_{0}(k) \\ \nonumber\textrm{with } i&=1,2,3 \end{align}\end{split}\]

IP-core interfaces#

Table 111 Interface of nine-phase PMSM Model IP-Core#

Port Name

Port Type

Data Type

Interface

Range

Description

reset_integrators

Input

boolean

AXI 0x100

resets all integrators

use_axi_input

Input

boolean

AXI 0x104

true: use AXI voltage values as input; false: use PL voltage values as input

simulate_mechanical

Input

boolean

AXI 0x108

true: load simulation; false: fix PMSM speed

load_torque

Input

single

AXI 0x10C

load torque if simulate_mechanical is true

omega_mech

Input

single

AXI 0x110

fixed speed if simulate_mechanical is false

physical_parameters

Input

single bus (12/15)

AXI 0x114-0x170

set machine parameters; description see “uz_pmsm_model9ph_dq_config_t”/ “uz_pmsm_model9ph_dq_config_t” struct

voltage_input_dq_axi

Input

single vector (6/9)

AXI 0x180-0x1A0

input voltages as transformed values in the form of “uz_6ph_dq_t”/ “uz_9ph_dq_t” from AXI

voltage_input_dq

Input

sfix27_En16 vector (6/9)

External Signal

-1024 to 1023

input voltages as transformed values in the form of “uz_6ph_dq_t”/ “uz_9ph_dq_t” from PL

theta_el_out_axi

Output

single

AXI 0x14C

\(\pm \pi\)

actual electric rotor angle

theta_el_out

Output

sfix18_En14

External Signal

\(\pm \pi\)

actual electric rotor angle

M_Mi_out_axi

Output

single

AXI 0x174

actual machine torque

omega_mech_out_axi

Output

single

AXI 0x178

actual machine speed

omega_mech_out

Output

sfix24_En11

External Signal

-4096 to 4095

actual machine speed

currents_dq_out_axi

Output

single vector (6/9)

AXI 0x200-0x220

actual currents in the rotary or stationary reference frame to AXI in the form of “uz_6ph_dq_t”/ “uz_9ph_dq_t”

currents_dq_out

Output

sfix27_En18 vector (6/9)

External Signal

-256 to +255

actual currents in the rotary or stationary reference frame to PL in the form of “uz_6ph_dq_t”/ “uz_9ph_dq_t”

voltage_input_dq_out_axi_fb

Output

single vector (6/9)

AXI 0x280-2A0

feedback actual input voltages to AXI (available for use_axi_input true and false)

Driver reference#

The set and get functions for voltage and currents are implemented as normal and unsafe version. In addition to the regular functions, unsafe versions of the driver exist (_unsafe). These functions are considerably faster than their safe counterparts but violate the software rules outlined in Software Development Guidelines. It is strongly advised to manually test by comparing the safe and unsafe versions before using _unsafe!””

Six-phase model#

typedef struct uz_pmsm_model6ph_dq_t uz_pmsm_model6ph_dq_t#

Object data type definition of the PMSM model IP-Core driver.

struct uz_pmsm_model6ph_dq_config_t#

Configuration struct for the PMSM model IP-Core driver.

Public Members

uint32_t base_address#

Base address of the IP-Core instance to which the driver is coupled

uint32_t ip_core_frequency_Hz#

Clock frequency of IP-Core

float polepairs#

Polepairs of the PMSM

float r_1#

Stator resistance in ohm

uz_6ph_dq_t inductance#

Subsystem inductances

float psi_pm#

PM flux linkage

float friction_coefficient#

Linear coefficient of friction

float coulomb_friction_constant#

Static friction constant

float inertia#

Inertia of the PMSM

bool simulate_mechanical_system#

Determine if mechanical system is simulated or speed is an input

bool switch_pspl#

true: inputs from PS, false: inputs from PL

struct uz_pmsm_model6ph_dq_outputs_general_t#

Struct to return and read the general outputs of the PMSM Model.

Public Members

float torque#

Inner torque of PMSM in Nm

float omega_mech#

Rotational speed of PMSM in 1/s

float theta_el#

Rotor electrical angle in rad

uz_pmsm_model6ph_dq_t *uz_pmsm_model6ph_dq_init(struct uz_pmsm_model6ph_dq_config_t config)#

Initialize an instance of the driver.

Parameters:
  • config – Config struct

Returns:

uz_pmsm_model6ph_dq_t* Pointer to an initialized instance of the driver

void uz_pmsm_model6ph_trigger_voltage_input_strobe(uz_pmsm_model6ph_dq_t *self)#

Takes the values of the AXI shadow register and pass them to the actual input.

Parameters:
  • self

void uz_pmsm_model6ph_trigger_voltage_output_strobe(uz_pmsm_model6ph_dq_t *self)#

Takes the values of the shadow register and pass them to the actual AXI register.

Parameters:
  • self

void uz_pmsm_model6ph_trigger_current_output_strobe(uz_pmsm_model6ph_dq_t *self)#

Takes the values of the shadow register and pass them to the actual AXI register.

Parameters:
  • self

void uz_pmsm_model6ph_dq_set_inputs_general(uz_pmsm_model6ph_dq_t *self, float omega_mech, float load_torque)#

Set general inputs of the model and write them to the PMSM model.

Parameters:
  • self – Pointer to driver instance

  • omega_mech – value for fixed omega if uz_pmsm_model6ph_dq_config_t.simulate_mechanical_system is false

  • load_torque – value for load torque if uz_pmsm_model6ph_dq_config_t.simulate_mechanical_system is true

struct uz_pmsm_model6ph_dq_outputs_general_t uz_pmsm_model6ph_dq_get_outputs_general(uz_pmsm_model6ph_dq_t *self)#

Returns general outputs of PMSM model.

Parameters:
  • self – Pointer to driver instance

Returns:

struct uz_pmsm_model6ph_dq_outputs_general_t output values

void uz_pmsm_model6ph_dq_set_voltage(uz_pmsm_model6ph_dq_t *self, uz_6ph_dq_t voltages)#

Safe function to set the input voltages of PMSM if PS is selected as source for voltages.

Parameters:
  • self

  • voltages – struct of type uz_6ph_dq_t containing the voltages to set

void uz_pmsm_model6ph_dq_set_voltage_unsafe(uz_pmsm_model6ph_dq_t *self, uz_6ph_dq_t voltages)#

Unsafe function to set the input voltages of PMSM if PS is selected as source for voltages.

Parameters:
  • self

  • voltages – struct of type uz_6ph_dq_t containing the voltages to set

uz_6ph_dq_t uz_pmsm_model6ph_dq_get_input_voltages(uz_pmsm_model6ph_dq_t *self)#

Safe function to read out the set input voltages of PMSM. Works for voltages coming from PS and PL.

Parameters:
  • self

Returns:

struct of type uz_6ph_dq_t containing the set voltages

uz_6ph_dq_t uz_pmsm_model6ph_dq_get_input_voltages_unsafe(uz_pmsm_model6ph_dq_t *self)#

Unsafe function to read out the set input voltages of PMSM. Works for voltages coming from PS and PL.

Parameters:
  • self

Returns:

struct of type uz_6ph_dq_t containing the set voltages

uz_6ph_dq_t uz_pmsm_model6ph_dq_get_output_currents(uz_pmsm_model6ph_dq_t *self)#

Safe function to read out the actual currents of PMSM.

Parameters:
  • self

Returns:

struct of type uz_6ph_dq_t containing the actual currents

uz_6ph_dq_t uz_pmsm_model6ph_dq_get_output_currents_unsafe(uz_pmsm_model6ph_dq_t *self)#

Unsafe function to read out the actual currents of PMSM.

Parameters:
  • self

Returns:

struct of type uz_6ph_dq_t containing the actual currents

void uz_pmsm_model6ph_dq_reset(uz_pmsm_model6ph_dq_t *self)#

Resets the PMSM model by writing zero to all PS inputs and sets integrators to zero.

Parameters:
  • self – Pointer to driver instance

void uz_pmsm_model6ph_dq_set_use_axi_input(uz_pmsm_model6ph_dq_t *self, bool use_axi)#

Change input source for voltages (PL or PS) during runtime.

Parameters:
  • self – Pointer to driver instance

  • use_axi – true: voltages from PS, false: voltages from PL

Nine-phase model#

typedef struct uz_pmsm_model9ph_dq_t uz_pmsm_model9ph_dq_t#

Object data type definition of the PMSM model IP-Core driver.

struct uz_pmsm_model9ph_dq_config_t#

Configuration struct for the PMSM model IP-Core driver.

Public Members

uint32_t base_address#

Base address of the IP-Core instance to which the driver is coupled

uint32_t ip_core_frequency_Hz#

Clock frequency of IP-Core

float polepairs#

Polepairs of the PMSM

float r_1#

Stator resistance in ohm

uz_9ph_dq_t inductance#

Subsystem inductances

float psi_pm#

PM flux linkage

float friction_coefficient#

Linear coefficient of friction

float coulomb_friction_constant#

Static friction constant

float inertia#

Inertia of the PMSM

bool simulate_mechanical_system#

Determine if mechanical system is simulated or speed is an input

bool switch_pspl#

true: inputs from PS, false: inputs from PL

struct uz_pmsm_model9ph_dq_outputs_general_t#

Struct to return and read the general outputs of the PMSM Model.

Public Members

float torque#

Inner torque of PMSM in Nm

float omega_mech#

Rotational speed of PMSM in 1/s

float theta_el#

Rotor electrical angle in rad

uz_pmsm_model9ph_dq_t *uz_pmsm_model9ph_dq_init(struct uz_pmsm_model9ph_dq_config_t config)#

Initialize an instance of the driver.

Parameters:
  • config – Config struct

Returns:

uz_pmsm_model9ph_dq_t* Pointer to an initialized instance of the driver

void uz_pmsm_model9ph_trigger_voltage_input_strobe(uz_pmsm_model9ph_dq_t *self)#

Takes the values of the AXI shadow register and pass them to the actual input.

Parameters:
  • self

void uz_pmsm_model9ph_trigger_voltage_output_strobe(uz_pmsm_model9ph_dq_t *self)#

Takes the values of the shadow register and pass them to the actual AXI register.

Parameters:
  • self

void uz_pmsm_model9ph_trigger_current_output_strobe(uz_pmsm_model9ph_dq_t *self)#

Takes the values of the shadow register and pass them to the actual AXI register.

Parameters:
  • self

void uz_pmsm_model9ph_dq_set_inputs_general(uz_pmsm_model9ph_dq_t *self, float omega_mech, float load_torque)#

Set general inputs of the model and write them to the PMSM model.

Parameters:
  • self – Pointer to driver instance

  • omega_mech – value for fixed omega if uz_pmsm_model9ph_dq_config_t.simulate_mechanical_system is false

  • load_torque – value for load torque if uz_pmsm_model9ph_dq_config_t.simulate_mechanical_system is true

struct uz_pmsm_model9ph_dq_outputs_general_t uz_pmsm_model9ph_dq_get_outputs_general(uz_pmsm_model9ph_dq_t *self)#

Returns general outputs of PMSM model.

Parameters:
  • self – Pointer to driver instance

Returns:

struct uz_pmsm_model9ph_dq_outputs_general_t output values

void uz_pmsm_model9ph_dq_set_voltage(uz_pmsm_model9ph_dq_t *self, uz_9ph_dq_t voltages)#

Safe function to set the input voltages of PMSM if PS is selected as source for voltages.

Parameters:
  • self

  • voltages – struct of type uz_9ph_dq_t containing the voltages to set

void uz_pmsm_model9ph_dq_set_voltage_unsafe(uz_pmsm_model9ph_dq_t *self, uz_9ph_dq_t voltages)#

Unsafe function to set the input voltages of PMSM if PS is selected as source for voltages.

Parameters:
  • self

  • voltages – struct of type uz_9ph_dq_t containing the voltages to set

uz_9ph_dq_t uz_pmsm_model9ph_dq_get_input_voltages(uz_pmsm_model9ph_dq_t *self)#

Safe function to read out the set input voltages of PMSM. Works for voltages coming from PS and PL.

Parameters:
  • self

Returns:

struct of type uz_9ph_dq_t containing the set voltages

uz_9ph_dq_t uz_pmsm_model9ph_dq_get_input_voltages_unsafe(uz_pmsm_model9ph_dq_t *self)#

Unsafe function to read out the set input voltages of PMSM. Works for voltages coming from PS and PL.

Parameters:
  • self

Returns:

struct of type uz_9ph_dq_t containing the set voltages

uz_9ph_dq_t uz_pmsm_model9ph_dq_get_output_currents(uz_pmsm_model9ph_dq_t *self)#

Safe function to read out the actual currents of PMSM.

Parameters:
  • self

Returns:

struct of type uz_9ph_dq_t containing the actual currents

uz_9ph_dq_t uz_pmsm_model9ph_dq_get_output_currents_unsafe(uz_pmsm_model9ph_dq_t *self)#

Unsafe function to read out the actual currents of PMSM.

Parameters:
  • self

Returns:

struct of type uz_9ph_dq_t containing the actual currents

void uz_pmsm_model9ph_dq_reset(uz_pmsm_model9ph_dq_t *self)#

Resets the PMSM model by writing zero to all PS inputs and sets integrators to zero.

Parameters:
  • self – Pointer to driver instance

void uz_pmsm_model9ph_dq_set_use_axi_input(uz_pmsm_model9ph_dq_t *self, bool use_axi)#

Change input source for voltages (PL or PS) during runtime.

Parameters:
  • self – Pointer to driver instance

  • use_axi – true: voltages from PS, false: voltages from PL

Example usage (standalone)#

The IP-core has two intended use cases:

Using the IP-core in PS only is similar to the use cases shown in PMSM Model open loop example which is recreated here. The placement of the IP-core for the use from PS only is straight forward as only the default PL interfaces have to be connected. For the example the nine-phase model is used, but the same can also be applied for the six-phase model.

../../../_images/open_loop_ps.jpg

Fig. 348 Test setup for IP-core PS test in Vivado#

The following code is used in main.c (initialization) and isr.c (application):

Listing 194 initialization in main.c (R5)#
#include "IP_Cores/uz_pmsm_model_9ph_dq/uz_pmsm_model9ph_dq.h"
uz_pmsm_model9ph_dq_t *pmsm=NULL;
struct uz_pmsm_model9ph_dq_config_t pmsm_config = {   // example config values
  .base_address=XPAR_UZ_PMSM_MODEL_0_BASEADDR,
  .ip_core_frequency_Hz = 100000000U,
  .polepairs = 3.0f,
  .r_1 = 31.3f,
  .inductance.d = 0.46f,
  .inductance.q = 0.46f,
  .inductance.x1 = 0.08f,
  .inductance.y1 = 0.08f,
  .inductance.x2 = 0.08f,
  .inductance.y2 = 0.08f,
  .inductance.x3 = 0.08f,
  .inductance.y3 = 0.08f,
  .inductance.zero = 0.08f,
  .psi_pm = 0.072f,
  .friction_coefficient = 0.001f,
  .coulomb_friction_constant = 0.001f,
  .inertia = 0.001f,
  .simulate_mechanical_system = false,
  .switch_pspl = true};

// .. rest of the code in main.c before loop
int main(void)
// ..
  case init_ip_cores: // default line from main.c
    pmsm = uz_pmsm_model9ph_dq_init(pmsm_config);
Listing 195 usage in isr.c#
#include "../IP_Cores/uz_pmsm_model_9ph_dq/uz_pmsm_model9ph_dq.h"
extern uz_pmsm_model9ph_dq_t *pmsm;                               // pointer to PMSM object
struct uz_pmsm_model9ph_dq_outputs_general_t out_general = {0};   // stores general outputs
uz_9ph_dq_t in_voltages = {                                       // stores input voltages (set random voltages for testing)
              .d = 1.0f,
              .q = 2.0f,
              .x1 = 3.0f,
              .y1 = 4.0f,
              .x2 = 5.0f,
              .y2 = 6.0f,
              .x3 = 7.0f,
              .y3 = 8.0f,
              .zero = 9.0f};
uz_9ph_dq_t out_currents = {0};                                   // stores output currents
float omega_mech = 10.0f;                                         // fixed speed can be set from Expressions with this variable
int reset = 0;                                                    // use reset variable to reset integrators from Expressions

// .. rest of the code in isr.c before loop
void ISR_Control(void *data)
// ..
  update_speed_and_position_of_encoder_on_D5(&Global_Data);       // default line from isr.c

  if(reset)
    uz_pmsm_model9ph_dq_reset(pmsm);                              // use reset variable to reset integrators from Expressions

  uz_pmsm_model9ph_dq_set_inputs_general(pmsm,omega_mech,0.0f);   // set fixed speed, because load simulation is disabled by pmsm_config.simulate_mechanical_system
  uz_pmsm_model9ph_dq_set_voltage(pmsm,in_voltages);              // set input voltage
  out_general = uz_pmsm_model9ph_dq_get_outputs_general(pmsm);    // read out resulting general outputs
  out_currents = uz_pmsm_model9ph_dq_get_output_currents(pmsm);   // read out actual currents

To prove functionality, the output currents of the shown example are evaluated. The resulting machine torque is \(-0.01562337\,Nm\) an the resulting currents are shown in the following equation. The results were recreated with the Simulink model.

\[\begin{split}\begin{align} out-currents = \begin{bmatrix} i_{d} \\ i_{q} \\ i_{x_1} \\ i_{y_1} \\ i_{x_2} \\ i_{y_2} \\ i_{x_3} \\ i_{y_3} \\ i_{zero} \end{bmatrix} = \begin{bmatrix} 0.03166196\\ -0.006507777 \\ 0.09584665 \\ 0.1277955 \\ 0.1597444 \\ 0.1916933 \\ 0.2236422 \\ 0.2555911 \\ 0.2875399 \end{bmatrix} \end{align}\end{split}\]

Sources#