去年夏天,我们团队接手了一个工业排气风机的量产项目,要求在全工况范围内实现±1%的转速精度。当时市面上大多数方案要么依赖编码器,要么在低速段抖得像筛糠。最终我们基于STM32G071这颗M0内核芯片,打磨出一套无感FOC方案,实测在50-3000RPM范围内转矩波动小于2%。这套方案的核心在于龙伯格观测器的创新实现和独特的调制策略,今天我就把踩过的坑和调参秘籍都摊开来聊聊。
传统龙伯格观测器在电机参数变化时容易失稳,我们在α-β坐标系下做了滑模改进。关键点在于这个非线性反馈项的设计:
c复制typedef struct {
float alpha; // 观测器增益(建议0.8-1.2)
float beta; // 滑模系数(建议50-100)
float est_flux[2]; // αβ轴磁链估计值
float back_emf[2]; // 反电动势观测值
float Rs; // 定子电阻(需在线辨识)
} LuenbergerObserver;
滑模面的计算采用了符号函数与饱和函数的混合策略,这个技巧让低速稳定性提升了40%:
c复制// 混合滑模面计算
float s = (Iα - observer->est_flux[0]) * observer->beta
- (Iβ - observer->est_flux[1]) * observer->alpha;
// 符号函数+饱和函数混合
if(fabs(s) > SLIDE_THRESH){
observer->back_emf[0] = K_SLIDE * sign(s);
} else {
observer->back_emf[0] = K_SLIDE * (s/SLIDE_THRESH);
}
调试心得:滑模增益K_SLIDE的取值与电机反电动势常数直接相关,建议先用6步方波驱动电机,测量空载反电动势幅值,取1.2倍作为初始值。
观测器输出的反电动势需要经过锁相环提取转速和位置。我们采用二阶PLL结构,其传递函数为:
code复制H(s) = (2ζωn*s + ωn²)/(s² + 2ζωn*s + ωn²)
对应的离散化实现代码如下:
c复制void PLL_Update(PLL_TypeDef *pll, float emf_alpha, float emf_beta){
float sin_theta = pll->sin_val;
float cos_theta = pll->cos_val;
// 相位检测器
float error = emf_alpha * cos_theta - emf_beta * sin_theta;
// 环路滤波器
pll->integrator += error * pll->ki;
float freq = error * pll->kp + pll->integrator;
// 压控振荡器
pll->angle += freq * pll->dt + pll->offset;
pll->sin_val = arm_sin_f32(pll->angle);
pll->cos_val = arm_cos_f32(pll->angle);
}
参数整定经验:
风机应用最头疼的就是未知初始位置和可能存在的逆风状态。我们采用电流矢量幅值检测法:
c复制#define WIND_THRESH 0.3f // 额定电流的30%
bool Check_ReverseWind(void){
// 施加固定方向矢量
SVM_Output(0, 0.5f * Vdc);
delay_ms(50);
// 检测电流响应
float Iq = Get_CurrentQ();
if(Iq < -WIND_THRESH){
return true; // 逆风状态
}
return false;
}
避坑指南:阈值WIND_THRESH需要根据风叶惯量调整。叶轮直径越大,该值应越小。我们整理的经验公式:阈值 = 0.3 * (D/0.3)^2,其中D为叶轮直径(米)
预定位阶段:
低速拖拽阶段:
观测器切换阶段:
c复制if(rpm_est > SWITCH_RPM){
torque_current = 0.7*openloop_current + 0.3*closedloop_current;
}
传统SVPWM在低调制比时谐波失真严重。我们根据调制比自动切换策略:
| 调制比范围 | 调制策略 | THD改善 |
|---|---|---|
| M < 0.3 | 七段式 | 4.2% |
| 0.3 ≤ M <0.7 | 五段式 | 2.8% |
| M ≥ 0.7 | 三段式 | 基准 |
七段式关键实现代码:
c复制void SVM_7Segment(Sector_TypeDef sector, float t1, float t2){
float t0 = (1 - t1 - t2)/2;
switch(sector){
case SECTOR_I:
TIM1->CCR1 = (t1 + t2 + t0) * period_max;
TIM1->CCR2 = (t2 + t0) * period_max;
TIM1->CCR3 = t0 * period_max;
break;
// 其他扇区类似...
}
}
M0芯片没有硬件死区补偿,我们在软件中实现了动态补偿:
c复制void DeadTime_Compensation(float *u, float *v, float *w){
static float dt_comp = 0.05f; // 初始补偿量(标幺值)
// 根据电流方向调整补偿量
if(Ia > 0.1f) u += dt_comp;
else if(Ia < -0.1f) u -= dt_comp;
// 其他两相类似...
}
实测数据:补偿后效率提升1.5%,特别是在低速重载工况
先调电阻辨识:
python复制# 参数辨识脚本示例
def identify_Rs():
apply_voltage(0.5, 0) # 施加直流电压
measure_current()
Rs = voltage / current
return Rs
再调滑模增益:
最后调PLL带宽:
matlab复制% 带宽扫描脚本
bw_range = linspace(0.1, 10, 20);
for bw = bw_range
set_pll_bandwidth(bw);
measure_settling_time();
end
电流环比例系数:
code复制Kp = Ls * ωc
积分系数:
code复制Ki = Rs * ωc
其中:
我们遇到过PWM开关导致ADC采样异常的情况,解决方案:
电机温升会导致参数变化,我们采用的在线辨识策略:
c复制void Online_Parameter_Estimation(void){
// 每10秒执行一次电阻辨识
if(tick % 10 == 0){
Rs = Estimate_Rs();
observer->Rs = Rs * 1.05; // 加5%裕量
}
}
统计数据显示80%的启动失败源于:
对应的解决方案:
这套方案最终实现了98.7%的批量生产良率,关键就在于这些细节处的打磨。最后分享一个调试技巧:用LED指示灯实时显示观测器状态,绿灯表示正常运行,红灯闪烁表示失步,比看波形效率高多了。