Encoder Offset Estimation
General
This software module addresses the challenges with determining encoder offset of PMSMs as described in How to set encoder offset. The method according to Flux-based (without test-bench machine) is implemented. This method (Flux-based (without test-bench machine)) has proven to deliver significantly better results than the basic method of applying a space vector to phase a (Constant current in the a-phase). The results from two different test-benches are listed in the following table. Herein, the basic and the advanced methods were used ten times. The medium values show quite similar results. However, the standard deviation of the advanced method is significantly lower.
\(\theta_\textrm{el}\) |
\(\mu(\theta_\textrm{el})\) (rad) |
\(\sigma(\theta_\textrm{el})\) (rad) |
|---|---|---|
Testbench 1 |
||
\(\theta_\textrm{el;inital}\) |
5.4823 |
0.0987 |
\(\theta_\textrm{el;precise}\) |
5.4843 |
0.02394 |
Testbench 2 |
||
\(\theta_\textrm{el;inital}\) |
5.5447 |
0.1080 |
\(\theta_\textrm{el;precise}\) |
5.5778 |
0.0045 |
Workflow
First, an initial offset angle must be determined to use this function.
The basic method for that is recommended, meaning a space vector is applied to the \(\alpha\)-axis, and the resulting rotor angle can be used.
Afterward, the code shown below can be implemented.
Using this code, 40 points will be measured around the given initial offset angle.
The final offset angle is saved in the specified uz_encoder_offset_estimation_t object.
With uz_encoder_offset_estimation_get_status, the progress is output, as well as the diagnose of the process.
It is recommended to observe the output of this function in the GUI slowdata.
The numeric values for the different diagnose enums are shown in the table below.
Int Value |
Meaning |
enum |
|---|---|---|
0 |
No specific diagnose message active. |
encoderoffset_no_error |
1 |
The min_omega_el could not be reached with the given setpoint_current and the statemachine is stuck. |
encoderoffset_speed_not_reached |
2 |
The process is finished and the resulting offset angle is saved in ptr_offset_angle. |
encoderoffset_finished |
3 |
The process is finished and the resulting offset angle equals the smallest angle tested. Check that all inputs are correct or redo measurement with different range. |
encoderoffset_lower_limit |
4 |
The process is finished and the resulting offset angle equals the largest angle tested. Check that all inputs are correct or redo measurement with different range. |
encoderoffset_upper_limit |
Example Code
It is important to use the global data struct at least for the measured theta electric, theta offset, omega electric and \(u_q\).
// above loop
#include "uz/uz_encoder_offset_estimation/uz_encoder_offset_estimation.h"
struct uz_encoder_offset_estimation_config encoder_offset_cfg = { // config struct
.ptr_measured_rotor_angle = &Global_Data.av.theta_elec, // pointer to the measured electric rotor angle (raw, not offset corrected)
.ptr_offset_angle = &Global_Data.av.theta_offset, // pointer to global variable holding the offset angle
.ptr_actual_omega_el = &Global_Data.av.omega_el, // pointer to actual electric rotor angular speed
.ptr_actual_u_q_V = &Global_Data.av.U_q, // pointer to q-setpoint voltage
.min_omega_el = 400.0f, // target electric rotor angular speed (USE OWN)
.setpoint_current = 4.0f}; // current setpoint to reach speed (USE OWN)
uz_encoder_offset_estimation_t* encoder_offset_obj = NULL; // object pointer
..
// in loop
Global_Data.av.theta_offset = 5.4f; // inital offset (USE OWN)
encoder_offset_obj = uz_encoder_offset_estimation_init(encoder_offset_cfg); // init function
..
// aboce loop
#include "../uz/uz_encoder_offset_estimation/uz_encoder_offset_estimation.h"
uz_6ph_dq_t transformed_voltage = {0};
uz_3ph_dq_t setpoint_current = {0};
uz_3ph_dq_t ref_voltage_3ph;
float theta_el = 0.0f;
extern uz_encoder_offset_estimation_t* encoder_offset_obj;
struct uz_encoder_offset_estimation_status status;
..
//in loop
Global_Data.av.U_q = cc_3ph_out.q; // write controller output ref voltage to global data
theta_el = Global_Data.av.theta_elec - Global_Data.av.theta_offset; // calculate resulting theta
actual_i_dq = uz_transformation_3ph_abc_to_dq(abc_current, theta_el); // transform measured abc currents to dq with corrected angle
status = uz_encoder_offset_estimation_get_status(encoder_offset_obj); // get encode offset status and progress
if (current_state==control_state) // in control state
{
if(!uz_encoder_offset_estimation_get_finished(encoder_offset_obj)){ // if not finished
setpoint_current = uz_encoder_offset_estimation_step(encoder_offset_obj);//receive current controller setpoint current from stepping function
}else{
setpoint_current.d = 0.0f; // else: it is finished, setpoints are 0
setpoint_current.q = 0.0f;
}
// control function, use your own
ref_voltage_3ph = uz_CurrentControl_sample(CC_instance, setpoint_current, actual_i_dq, actual_UDC, actual_omega_el);
ref_voltage_3ph_abc = invPark(ref_voltage_3ph, theta);
//write duty-cycles
..
}
Example Result
The following figure shows what the measurement results look like. The black line indicates the determined offset angle. The initial angle was 5.4 rad.
Fig. 100 Measurement Result
Known Problems
The function will stop if the rotor does not move or reach the necessary speed in time.
The variable diagnose inside the status struct will indicate this error with the status encoderoffset_speed_not_reached.
To fix this, increase the setpoint current in the config struct.
After finishing the offset estimation, the diagnose will also indicate this.
If the resulting angle equals the lowest or highest tested angle, a specific feedback will given and the process should be redone with a different range.
Furthermore, even if a voltage measurement is available on the test-bench setup, the results are more reliable when the controller reference voltage is used for calculation.
Therefore it is not recommended to use a measured voltage.
Functions
-
typedef struct uz_encoder_offset_estimation_t uz_encoder_offset_estimation_t
Object definition for generating encoder offset estimation instance.
-
enum uz_encoder_offset_estimation_diagnose
enum with error/status messages. See Table under Workflow for numeric expressions.
Values:
-
enumerator encoderoffset_no_error
Equals 0: No specific diagnose message active.
-
enumerator encoderoffset_speed_not_reached
Equals 1: The min_omega_el could not be reached with the given setpoint_current and the statemachine is stuck.
-
enumerator encoderoffset_finished
Equals 2: The process is finished and the resulting offset angle is saved in ptr_offset_angle.
-
enumerator encoderoffset_lower_limit
Equals 3: The process is finished and the resulting offset angle equals the smallest angle tested. Check that all inputs are correct or redo measurement with different range.
-
enumerator encoderoffset_upper_limit
Equals 4: The process is finished and the resulting offset angle equals the largest angle tested. Check that all inputs are correct or redo measurement with different range.
-
enumerator encoderoffset_no_error
-
struct uz_encoder_offset_estimation_config
Configuration struct for the encoder offset estimation instance.
Public Members
-
float *ptr_measured_rotor_angle
Pointer to rotor angle measurement
-
float *ptr_offset_angle
Pointer to offset variable
-
float *ptr_actual_omega_el
Pointer to actual omega electric in rad/s
-
float *ptr_actual_u_q_V
Pointer to actual q-axis voltage in V
-
float setpoint_current
Setpoint current for tests
-
float min_omega_el
Target omega electric (rad/s) to reach for flux linkage measurement
-
float *ptr_measured_rotor_angle
-
struct uz_encoder_offset_estimation_status
Feedback struct for user.
Public Members
-
float progress
Progress of estimation from 0-1
-
enum uz_encoder_offset_estimation_diagnose diagnose
Diagnose and status
-
float progress
-
uz_encoder_offset_estimation_t *uz_encoder_offset_estimation_init(struct uz_encoder_offset_estimation_config config)
Initialize an instance.
- Parameters
config – Config struct
- Returns
uz_encoder_offset_estimation_t* Pointer to an initialized instance
-
uz_3ph_dq_t uz_encoder_offset_estimation_step(uz_encoder_offset_estimation_t *self)
Step the function.
- Parameters
self – Pointer to instance
- Returns
setpoint for current controller
-
bool uz_encoder_offset_estimation_get_finished(uz_encoder_offset_estimation_t *self)
Get finished flag.
- Parameters
self – Pointer to instance
- Returns
finished flag
-
void uz_encoder_offset_estimation_set_setpoint_current(uz_encoder_offset_estimation_t *self, float setpoint_current)
Set (new) setpoint_current to object.
- Parameters
self – Pointer to instance
float – setpoint_current
-
void uz_encoder_offset_estimation_reset_states(uz_encoder_offset_estimation_t *self)
Reset states for new usage.
- Parameters
self – Pointer to instance
-
struct uz_encoder_offset_estimation_status uz_encoder_offset_estimation_get_status(uz_encoder_offset_estimation_t *self)
Get status.
- Parameters
self – Pointer to instance
- Returns
status struct