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相间。

执行流程:

  1. 调用motor_param_identify(),观察串口输出Rs和Ls值;
  2. 用另一台电机或手摇柄以500rpm匀速拖动被测电机转子,调用calculate_ke(500.0f)读取Ke。

通过条件:

  • Rs测量值与万用表实测值误差<5%;
  • Ls测量值与LCR表实测值误差<10%;
  • Ke换算为Kt(转矩常数)后,与电机手册标称值误差<10%。
电机参数辨识流程 步骤1: 电阻测量 注入10%直流电压 采样稳态电流 Rs = U/(2·I) 步骤2: 电感测量 注入50%高频PWM 采样电流纹波ΔI Ls = U·D·T/ΔI 步骤3: Ke测量 外部拖动500rpm 采样线反电动势 Ke = E/(2·ω) 辨识输出参数 Rs = 0.85 Ω Ls = 0.42 mH Ke = 0.023 V·s/rad

常见问题

  • 电感测量偏大:检查PWM死区时间是否过大,导致有效占空比低于设定值;建议死区<1μs。
  • 电阻测量不稳定:确保电机静止且无外部负载,采样前等待电流完全稳定(时间常数τ = L/R通常<10ms)。
  • Ke测量误差:拖动转速需稳定,建议用闭环控制的测功机;电压采样需使用差分探头避免共模干扰。