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