2. FOC电流环调试实战要点:电流采样与偏置校准
各位工程师朋友,咱们直接进入正题。电流采样是FOC控制的地基,地基没打好,后面什么SVPWM、观测器全是白搭。我见过太多人花大把时间调PI参数,结果发现是电流采样偏置没校好——那种挫败感,啧,我懂。
这一节咱们就掰开揉碎,把电流采样的原理、偏置误差的来源,以及怎么在校准代码里把它干掉,一次性说清楚。
2.1 相电流采样原理:三种主流方案
先看采样拓扑。目前主流方案就三种:单电阻、双电阻、三电阻。它们各有各的脾气,我按实际项目中的选择优先级来聊。
| 方案 | 采样电阻数 | 成本 | 精度 | 适用场景 |
|---|---|---|---|---|
| 单电阻 | 1个(直流母线侧) | 最低 | 中等(需重构) | 低成本风机、泵类 |
| 双电阻 | 2个(下桥臂) | 中等 | 较高 | 通用伺服、机器人关节 |
| 三电阻 | 3个(下桥臂) | 最高 | 最高 | 高精度、大功率驱动 |
2.1.1 单电阻采样
单电阻采样只用一个电阻,放在直流母线负端。它的核心逻辑是:在PWM周期的不同时刻,母线电流等于不同相的电流。通过在一个周期内采样两次,就能重构出两相电流。
但这里有个坑——采样窗口不够。当占空比接近0%或100%时,有效采样时间太短,ADC根本来不及稳定。我在做一款低压风机驱动器时就吃过这个亏,低速时电流波形全是毛刺,后来加了最小脉宽限制才解决。
2.1.2 双电阻采样
双电阻是目前最常用的方案。两个电阻分别放在V相和W相的下桥臂,U相电流通过基尔霍夫定律计算得到:Iu = -(Iv + Iw)。
它的优点是:任意时刻都能直接采样两相,不需要像单电阻那样卡采样窗口。缺点是:当某一相占空比接近0时,该相下桥臂没有电流流过,采样值会丢失。我一般会在代码里加一个移相补偿逻辑,把采样点避开死区。
2.1.3 三电阻采样
三电阻方案最直接,每相一个采样电阻,各相独立。精度最高,但成本也最高。一般用在伺服驱动器或大功率场合。它的调试最简单——直接读ADC值就行,不需要重构。
我的建议: 如果你做通用产品,优先选双电阻。性价比最高,调试难度适中。单电阻适合成本敏感且对低速性能要求不高的场景。三电阻?除非甲方明确要求,否则别给自己找麻烦。
2.2 采样偏置误差的来源与影响
好了,原理讲完,咱们聊聊偏置。偏置误差说白了就是:当电流为0时,ADC读到的值不是0。
为什么会这样?三个主要原因:
- 运放输入偏置电压: 运放不是理想的,输入端总有个几mV到几十mV的偏置。这个偏置会被放大,直接反映在ADC读数上。
- ADC参考电压漂移: 参考电压Vref如果不够稳,ADC的零点也会跟着飘。我遇到过用板载LDO给ADC供电的情况,温度一上来,零点能飘20个LSB。
- PCB布局引入的共模噪声: 采样电阻到运放的走线如果太长,或者地线处理不好,共模噪声会叠加到采样信号上。嗯,这个在电机驱动板上尤其常见。
偏置误差的影响有多大?我直接给你算笔账:
- 假设你的ADC是12位,Vref=3.3V,那么1个LSB对应约0.8mV。
- 如果偏置是10个LSB,那就是8mV的误差。
- 对于0.01Ω的采样电阻,这相当于0.8A的电流误差。
- 在FOC里,这个误差会直接变成转矩波动和转速抖动。
注意: 偏置误差不是固定的!它会随温度、电源电压变化。所以只做一次出厂校准是不够的,最好在每次电机启动前做一次快速校准。
2.3 偏置校准的步骤与代码实现
校准的思路其实很简单:让电机处于静止状态(电流为0),然后采集N次ADC值,取平均作为偏置值。后续每次采样都减去这个偏置值。
具体步骤:
- 确保电机静止: 关闭PWM输出,或者让所有下桥臂导通(主动短路)。我个人习惯用主动短路,这样能更快让电流归零。
- 采集ADC样本: 连续采集M次(我一般取64次或128次),存入数组。
- 剔除异常值: 去掉最大值和最小值,防止偶发噪声干扰。
- 计算平均值: 对剩余样本求平均,得到偏置值。
- 保存偏置值: 存入全局变量或结构体,供后续采样使用。
下面是我在实际项目中用的一段校准代码,C语言风格,跑在STM32G4上:
/* 电流采样偏置校准函数 */
/* 返回值:0-成功,-1-校准失败 */
int current_offset_calibrate(float *offset_u, float *offset_v, float *offset_w)
{
#define SAMPLE_COUNT 64
uint16_t raw_buf_u[SAMPLE_COUNT];
uint16_t raw_buf_v[SAMPLE_COUNT];
uint16_t raw_buf_w[SAMPLE_COUNT];
uint32_t sum_u = 0, sum_v = 0, sum_w = 0;
uint16_t min_u, max_u, min_v, max_v, min_w, max_w;
int i;
/* 1. 关闭PWM,使电机处于静止状态 */
pwm_disable();
delay_ms(10); /* 等待电流衰减 */
/* 2. 采集原始数据 */
for(i = 0; i < SAMPLE_COUNT; i++) {
adc_read_all(&raw_buf_u[i], &raw_buf_v[i], &raw_buf_w[i]);
delay_us(10); /* 采样间隔 */
}
/* 3. 剔除最大值和最小值 */
min_u = max_u = raw_buf_u[0];
min_v = max_v = raw_buf_v[0];
min_w = max_w = raw_buf_w[0];
for(i = 0; i < SAMPLE_COUNT; i++) {
/* U相 */
if(raw_buf_u[i] < min_u) min_u = raw_buf_u[i];
if(raw_buf_u[i] > max_u) max_u = raw_buf_u[i];
/* V相 */
if(raw_buf_v[i] < min_v) min_v = raw_buf_v[i];
if(raw_buf_v[i] > max_v) max_v = raw_buf_v[i];
/* W相 */
if(raw_buf_w[i] < min_w) min_w = raw_buf_w[i];
if(raw_buf_w[i] > max_w) max_w = raw_buf_w[i];
}
/* 4. 求和(跳过最大值和最小值) */
for(i = 0; i < SAMPLE_COUNT; i++) {
if(raw_buf_u[i] != min_u && raw_buf_u[i] != max_u) sum_u += raw_buf_u[i];
if(raw_buf_v[i] != min_v && raw_buf_v[i] != max_v) sum_v += raw_buf_v[i];
if(raw_buf_w[i] != min_w && raw_buf_w[i] != max_w) sum_w += raw_buf_w[i];
}
/* 5. 计算平均值并转换为电流值(单位:A) */
/* 假设ADC为12位,Vref=3.3V,运放增益为50,采样电阻0.01Ω */
*offset_u = (float)sum_u / (SAMPLE_COUNT - 2) * 3.3f / 4096.0f / 50.0f / 0.01f;
*offset_v = (float)sum_v / (SAMPLE_COUNT - 2) * 3.3f / 4096.0f / 50.0f / 0.01f;
*offset_w = (float)sum_w / (SAMPLE_COUNT - 2) * 3.3f / 4096.0f / 50.0f / 0.01f;
/* 6. 恢复PWM */
pwm_enable();
return 0;
}
经验之谈: 校准完成后,我习惯再读一次ADC值,验证一下偏置是否真的被消除了。如果发现偏置仍然大于2~3个LSB,我会检查一下运放供电是否稳定,或者采样电阻的焊接有没有虚焊。曾经有一次,我折腾了一整天,最后发现是采样电阻的焊盘裂了——嗯,那感觉,你懂的。
2.4 知识体系总览
为了让你对整个章节的逻辑有个直观印象,我画了一张图。它把采样原理、偏置来源、校准流程串在了一起,方便你对照着看。
这张图从左到右、从上到下,把整个知识链条串起来了。你调试的时候如果遇到问题,可以顺着这个图排查:先看采样方案对不对,再看偏置来源,最后检查校准流程和代码。
好了,这一节的内容就到这儿。偏置校准是电流环调试的第一步,也是最重要的一步。把它做扎实了,后面的电流环带宽、PI参数整定才能有意义。别嫌麻烦,磨刀不误砍柴工。