2. 电机参数辨识
任务目标
本案例通过向电机绕组注入直流与高频测试信号,测量并计算无感FOC控制所需的三个关键电气参数:定子电阻Rs、定子电感Ls(相电感)和反电动势常数Ke。最终输出可直接用于电流环PI参数整定和速度估算的电机参数表。
测量原理与实现方案
采用静态测量法,无需转动电机轴:
- 电阻测量:向任意两相(如A-B)注入直流电压,稳态后采样电流,由欧姆定律计算相电阻Rph = Udc / (2·Idc),定子电阻Rs = Rph。
- 电感测量:在同一相间注入高频PWM方波电压,采样电流纹波峰峰值ΔI,由U = L·di/dt计算相电感Lph = Udc·D·Tsw / ΔI,定子电感Ls = Lph。
- 反电动势常数:用外部设备以已知转速ωmech匀速拖动电机转子,测量两相间反电动势峰值Epp,计算Ke = Epp / (2·ωelec),其中ωelec = ωmech·P/2(P为极对数)。
关键完整代码
// motor_params_identify.c - 电机参数辨识实现(基于STM32 HAL库)
#include <math.h>
// 配置参数
#define V_DC 24.0f // 母线电压(V)
#define PWM_FREQ 20000.0f // PWM频率(Hz)
#define T_SW (1.0f/PWM_FREQ)
#define R_MEAS_DUTY 0.1f // 电阻测量占空比(10%)
#define L_MEAS_DUTY 0.5f // 电感测量占空比(50%)
#define SAMPLE_NUM 100 // 采样次数
#define POLE_PAIRS 4 // 电机极对数
// 全局变量
static float Rs, Ls, Ke;
// 读取ADC电压(V)
static float read_adc_voltage(void) {
// 实际项目中替换为HAL_ADC_GetValue()并换算为电压
return 0.0f;
}
// 读取相电流(A)
static float read_phase_current(void) {
// 实际项目中替换为电流传感器ADC读数
return 0.0f;
}
// 步骤1: 测量定子电阻
float measure_resistance(void) {
float v_meas, i_meas, r_ph;
float v_sum = 0, i_sum = 0;
// 设置A-B相PWM占空比为R_MEAS_DUTY
set_pwm_duty(PWM_A_HIGH, R_MEAS_DUTY);
set_pwm_duty(PWM_B_LOW, 0.0f);
set_pwm_duty(PWM_C_HIGH, 0.0f);
HAL_Delay(50); // 等待电流稳定
for (int i = 0; i < SAMPLE_NUM; i++) {
v_sum += read_adc_voltage();
i_sum += read_phase_current();
HAL_Delay(1);
}
v_meas = v_sum / SAMPLE_NUM;
i_meas = i_sum / SAMPLE_NUM;
// 相电阻 = 施加电压 / (2 * 相电流)
r_ph = (V_DC * R_MEAS_DUTY) / (2.0f * i_meas);
Rs = r_ph;
return Rs;
}
// 步骤2: 测量定子电感
float measure_inductance(void) {
float i_peak = 0, i_valley = 0, delta_i;
float l_ph;
// 设置A-B相PWM占空比为L_MEAS_DUTY
set_pwm_duty(PWM_A_HIGH, L_MEAS_DUTY);
set_pwm_duty(PWM_B_LOW, 0.0f);
set_pwm_duty(PWM_C_HIGH, 0.0f);
// 采样电流纹波峰谷值(需在PWM周期内同步采样)
for (int i = 0; i < SAMPLE_NUM; i++) {
float i_now = read_phase_current();
if (i_now > i_peak) i_peak = i_now;
if (i_now < i_valley) i_valley = i_now;
}
delta_i = i_peak - i_valley;
// 相电感 = Vdc * D * Tsw / delta_I
l_ph = (V_DC * L_MEAS_DUTY * T_SW) / delta_i;
Ls = l_ph;
return Ls;
}
// 步骤3: 计算反电动势常数(需外部拖动电机)
float calculate_ke(float mech_speed_rpm) {
float elec_speed_rad = (mech_speed_rpm / 60.0f) * 2.0f * M_PI * POLE_PAIRS;
float e_pp; // 线反电动势峰峰值(V)
// 采样两相间反电动势(通过电压传感器)
e_pp = read_line_back_emf_pp();
// Ke = E_pp / (2 * w_elec)
Ke = e_pp / (2.0f * elec_speed_rad);
return Ke;
}
// 参数辨识主入口
void motor_param_identify(void) {
printf("=== 电机参数辨识开始 ===\r\n");
Rs = measure_resistance();
printf("Rs = %.4f Ohm\r\n", Rs);
Ls = measure_inductance();
printf("Ls = %.4f H\r\n", Ls);
// 外部以500rpm拖动转子
Ke = calculate_ke(500.0f);
printf("Ke = %.6f V*s/rad\r\n", Ke);
printf("=== 辨识完成 ===\r\n");
}
运行与验证方法
硬件连接:将电机UVW三相接入驱动器,母线接24V直流电源,电流传感器串联在A相,电压传感器并联在A-B相间。
执行流程:
- 调用
motor_param_identify(),观察串口输出Rs和Ls值; - 用另一台电机或手摇柄以500rpm匀速拖动被测电机转子,调用
calculate_ke(500.0f)读取Ke。
通过条件:
- Rs测量值与万用表实测值误差<5%;
- Ls测量值与LCR表实测值误差<10%;
- Ke换算为Kt(转矩常数)后,与电机手册标称值误差<10%。
常见问题
- 电感测量偏大:检查PWM死区时间是否过大,导致有效占空比低于设定值;建议死区<1μs。
- 电阻测量不稳定:确保电机静止且无外部负载,采样前等待电流完全稳定(时间常数τ = L/R通常<10ms)。
- Ke测量误差:拖动转速需稳定,建议用闭环控制的测功机;电压采样需使用差分探头避免共模干扰。