1. 三相电流采样与标定概述
在电机控制系统中,三相电流采样是FOC(磁场定向控制)算法实现的基础环节。准确可靠的电流采样数据直接影响着控制系统的性能和稳定性。本实验基于STM32G431微控制器,针对无刷电机FOC控制中的三相电流采样链路进行系统性验证与标定。
电流采样链路通常包含以下几个关键环节:
- 电流传感器或采样电阻
- 信号调理电路(放大、滤波)
- ADC转换模块
- 数字信号处理算法
在实际应用中,这些环节都会引入不同程度的误差,包括:
- 零点偏置(Offset)
- 增益误差(Gain Error)
- 非线性误差
- 温度漂移
因此,在正式进行FOC控制前,必须对电流采样链路进行全面的标定和验证。
2. 硬件平台与系统架构
2.1 硬件平台选型
本实验采用ST官方提供的P-NUCLEO-IHM03电机控制套件,该套件包含以下主要组件:
-
控制模块:NUCLEO-G431RB开发板
- 基于Arm Cortex-M4内核,主频170MHz
- 内置浮点运算单元(FPU)
- 丰富的高级模拟外设
-
驱动模块:X-NUCLEO-IHM16M1电机驱动板
- 基于STSPIN830三相驱动器
- 支持单电阻或三电阻电流采样架构
- 集成过流保护功能
-
电机负载:GBM2804H-100T云台直流无刷电机
- 额定电压12V
- 低转速高扭矩特性
2.2 电流采样架构选择
本实验采用三电阻采样架构,具有以下特点:
-
采样点位置:
- 在每个下桥臂MOSFET的源极接入采样电阻
- 典型阻值在5-50mΩ范围内
-
信号调理电路:
- 差分放大器将小信号放大到ADC可测量范围
- 低通滤波器抑制高频噪声
-
ADC采样时机:
- 在PWM周期中点进行采样
- 此时相电流相对稳定
3. STM32G431外设配置
3.1 定时器配置
TIM1高级定时器用于生成PWM信号和触发ADC采样:
-
PWM生成配置:
- 计数模式:中心对齐模式
- PWM频率:16kHz(典型值)
- 死区时间:根据MOSFET特性设置
-
ADC触发配置:
- 使用TIM1_CH4比较事件触发ADC
- 触发时刻设置在PWM周期中点
c复制// TIM1初始化代码片段
htim1.Instance = TIM1;
htim1.Init.Prescaler = 0;
htim1.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED1;
htim1.Init.Period = PWM_PERIOD;
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.RepetitionCounter = 0;
htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
3.2 ADC配置
ADC1配置为注入组模式,实现三相电流同步采样:
-
基本参数:
- 分辨率:12位
- 数据对齐:右对齐
- 扫描模式:使能
-
触发设置:
- 触发源:TIM1_CC4事件
- 触发边沿:上升沿
-
通道配置:
- 注入组通道数:3
- 采样顺序:Ia→Ib→Ic
- 采样时间:统一设置为最优值
c复制// ADC初始化代码片段
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.ScanConvMode = ENABLE;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc1.Init.LowPowerAutoWait = DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DR;
hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
hadc1.Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE;
hadc1.Init.OversamplingMode = DISABLE;
4. 零点标定实验实现
4.1 标定原理与方法
零点标定的目的是测量并补偿电流采样链路的固有偏置。具体步骤包括:
-
标定条件:
- 关闭PWM输出或设置占空比为0
- 确保电机相电流实际为零
-
数据处理方法:
- 采集足够数量的样本(通常1000-10000个)
- 计算每个通道的平均值作为偏置值
- 后续采样时实时减去偏置值
4.2 代码实现细节
- 变量定义:
c复制#define PHASE_A 0
#define PHASE_B 1
#define PHASE_C 2
#define N_PHASES 3
volatile uint16_t raw_samples[N_PHASES]; // 原始ADC值
volatile int32_t offset_values[N_PHASES]; // 偏置值
volatile int32_t compensated_values[N_PHASES]; // 补偿后值
static volatile int64_t sum_samples[N_PHASES]; // 累加和
static volatile uint32_t sample_count; // 采样计数
static volatile uint8_t calibration_done; // 标定完成标志
- ADC回调函数:
c复制void HAL_ADCEx_InjectedConvCpltCallback(ADC_HandleTypeDef* hadc)
{
// 只处理ADC1
if (hadc->Instance != ADC1) return;
// 读取三相电流原始值
raw_samples[PHASE_A] = HAL_ADCEx_InjectedGetValue(hadc, ADC_INJECTED_RANK_1);
raw_samples[PHASE_B] = HAL_ADCEx_InjectedGetValue(hadc, ADC_INJECTED_RANK_2);
raw_samples[PHASE_C] = HAL_ADCEx_InjectedGetValue(hadc, ADC_INJECTED_RANK_3);
// 标定阶段:累加采样值
if (!calibration_done) {
for (int i = 0; i < N_PHASES; i++) {
sum_samples[i] += raw_samples[i];
}
sample_count++;
// 达到预定采样次数后计算偏置
if (sample_count >= CALIBRATION_SAMPLES) {
for (int i = 0; i < N_PHASES; i++) {
offset_values[i] = (int32_t)(sum_samples[i] / sample_count);
}
calibration_done = 1;
}
}
// 实时补偿偏置
for (int i = 0; i < N_PHASES; i++) {
compensated_values[i] = (int32_t)raw_samples[i] - offset_values[i];
}
}
- 主程序流程:
c复制int main(void)
{
// 硬件初始化
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_ADC1_Init();
MX_TIM1_Init();
// 启动定时器和ADC
HAL_TIM_Base_Start(&htim1);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_4);
HAL_ADCEx_InjectedStart_IT(&hadc1);
// 初始化标定变量
for (int i = 0; i < N_PHASES; i++) {
sum_samples[i] = 0;
}
sample_count = 0;
calibration_done = 0;
printf("开始零点标定...\r\n");
// 等待标定完成
while (!calibration_done) {
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
HAL_Delay(100);
}
printf("标定完成\r\n");
printf("偏置值: A相=%ld, B相=%ld, C相=%ld\r\n",
offset_values[PHASE_A],
offset_values[PHASE_B],
offset_values[PHASE_C]);
// 主循环
while (1) {
// 实时监测补偿后电流值
MonitorCurrentValues();
HAL_Delay(500);
}
}
5. 实验结果分析
5.1 典型标定结果
执行零点标定程序后,典型的串口输出结果如下:
code复制开始零点标定...
标定完成
偏置值: A相=1893, B相=1896, C相=1904
补偿后统计: 均值=[0,0,0], 峰峰值=[10,5,6]
5.2 结果解读
-
偏置值分析:
- 三相偏置值接近但略有差异(1893-1904)
- 差异主要来自运放和ADC的个体差异
- 偏置值大小与硬件设计(如运放偏置)相关
-
补偿效果:
- 补偿后均值收敛到0,证明标定有效
- 峰峰值波动反映系统噪声水平
- 各相噪声特性可能不同
-
长期稳定性:
- 建议定期重新标定(如每24小时)
- 温度变化较大时应重新标定
- 系统重启后必须重新标定
6. 进阶话题与优化建议
6.1 标定算法优化
- 中值滤波:
- 在存在脉冲干扰时,均值可能不准确
- 可采用中值滤波提高鲁棒性
c复制// 中值滤波实现示例
int32_t MedianFilter(int32_t new_sample, int32_t *buffer, uint8_t size)
{
// 更新采样缓冲区
for (int i = size-1; i > 0; i--) {
buffer[i] = buffer[i-1];
}
buffer[0] = new_sample;
// 排序并返回中值
int32_t temp[size];
memcpy(temp, buffer, size*sizeof(int32_t));
BubbleSort(temp, size);
return temp[size/2];
}
- 自适应标定:
- 动态调整标定采样次数
- 基于统计方差决定何时停止标定
6.2 温度补偿
-
温度监测:
- 使用MCU内部温度传感器
- 或外接温度传感器
-
补偿策略:
- 建立偏置-温度查找表
- 使用线性或多项式补偿公式
c复制// 温度补偿示例
void ApplyTemperatureCompensation(float current_temp)
{
// 简单线性补偿
float temp_coeff = 0.5; // LSB/°C
float temp_ref = 25.0; // 参考温度
for (int i = 0; i < N_PHASES; i++) {
offset_values[i] += (int32_t)(temp_coeff * (current_temp - temp_ref));
}
}
6.3 生产环境应用
- 标定参数存储:
- 保存到Flash或EEPROM
- 包含标定时间和温度信息
c复制// Flash存储结构体
typedef struct {
int32_t offsets[N_PHASES];
float temperature;
uint32_t timestamp;
uint16_t crc;
} CurrentCalibrationData;
- 自动标定流程:
- 上电时检查是否需要标定
- 提供强制标定接口
- 标定失败处理机制
7. 常见问题与解决方案
7.1 标定值不稳定
现象:
- 多次标定结果差异较大
- 补偿后零点漂移明显
可能原因:
- 硬件连接不可靠
- 电源噪声过大
- 采样时机不正确
- 电机未真正停止
解决方案:
- 检查所有硬件连接
- 增加电源滤波电容
- 验证PWM和ADC触发时序
- 确保PWM输出完全关闭
7.2 补偿后仍有偏置
现象:
- 补偿后均值不为零
- 偏置随运行条件变化
可能原因:
- 标定采样次数不足
- 存在非线性误差
- 温度影响未补偿
解决方案:
- 增加标定采样次数(如10000次)
- 考虑分段线性补偿
- 引入温度补偿机制
7.3 相间一致性差
现象:
- 三相偏置差异过大
- 补偿后各相噪声特性不同
可能原因:
- 运放或ADC通道性能差异
- 采样电阻精度不足
- 布线不对称引入干扰
解决方案:
- 筛选匹配的运放和ADC通道
- 使用更高精度采样电阻
- 优化PCB布局布线
8. 静态通流验证实验
8.1 实验目的
在完成零点标定后,需要通过静态通流实验验证:
- 各相采样通道的增益一致性
- 采样电路的线性度
- 电流极性判断正确性
8.2 实验方法
-
单相通流测试:
- 固定两相PWM为低
- 逐步改变另一相PWM占空比
- 记录ADC采样值
-
测试电流范围:
- 从零到最大允许电流
- 均匀选取5-10个测试点
-
数据处理:
- 绘制电流-ADC码值曲线
- 计算各相增益和线性度
8.3 参考代码
c复制void RunStaticCurrentTest(void)
{
const uint16_t test_points[] = {0, 500, 1000, 1500, 2000, 2500, 3000};
const uint8_t num_points = sizeof(test_points)/sizeof(test_points[0]);
printf("开始静态通流测试...\r\n");
// 测试A相
printf("\r\nA相测试:\r\n");
for (int i = 0; i < num_points; i++) {
SetPwmDuty(PHASE_A, test_points[i]);
SetPwmDuty(PHASE_B, 0);
SetPwmDuty(PHASE_C, 0);
HAL_Delay(100); // 等待稳定
int32_t current = GetAverageCurrent(PHASE_A, 100);
printf("占空比=%4u, 电流=%6ld\r\n", test_points[i], current);
}
// 同样方法测试B相和C相
// ...
printf("静态通流测试完成\r\n");
}
9. 低速运行观测实验
9.1 实验目的
在接近实际工作条件下验证:
- 动态采样数据的连续性
- 三相电流波形相位关系
- 采样时刻准确性
9.2 实验方法
-
开环运行条件:
- 固定转速(如100RPM)
- 固定电流幅值
- 观测电流波形
-
数据采集:
- 连续记录多个电周期的电流数据
- 通过串口或SWD接口输出
-
波形分析:
- 检查波形正弦度
- 验证三相120度相位差
- 确认无采样丢失或跳变
9.3 参考实现
c复制void RunLowSpeedTest(void)
{
printf("开始低速运行测试...\r\n");
// 设置开环运行参数
SetOpenLoopSpeed(100); // 100 RPM
SetCurrentAmplitude(1000); // 1000mA
// 启动电机
EnableMotorDriver();
// 采集数据
#define SAMPLE_COUNT 500
int32_t current_a[SAMPLE_COUNT];
int32_t current_b[SAMPLE_COUNT];
int32_t current_c[SAMPLE_COUNT];
for (int i = 0; i < SAMPLE_COUNT; i++) {
while(!new_sample_ready); // 等待新数据
new_sample_ready = 0;
current_a[i] = compensated_values[PHASE_A];
current_b[i] = compensated_values[PHASE_B];
current_c[i] = compensated_values[PHASE_C];
}
// 停止电机
DisableMotorDriver();
// 输出数据
printf("低速运行测试数据:\r\n");
for (int i = 0; i < SAMPLE_COUNT; i++) {
printf("%ld,%ld,%ld\r\n", current_a[i], current_b[i], current_c[i]);
}
printf("低速运行测试完成\r\n");
}
10. 工程实践建议
10.1 标定流程优化
-
自动化标定:
- 集成到生产测试程序
- 自动判断标定结果有效性
-
多点标定:
- 在不同温度点进行标定
- 建立温度补偿模型
-
标定数据管理:
- 记录标定环境和参数
- 支持标定数据导出
10.2 安全注意事项
-
硬件保护:
- 确保过流保护功能有效
- 限制最大测试电流
-
软件容错:
- 检测标定条件是否满足
- 异常情况自动中止
-
操作规范:
- 明确标定操作步骤
- 提供必要的警示信息
10.3 性能评估指标
-
静态指标:
- 零点偏置稳定性
- 各相增益一致性
- 线性度误差
-
动态指标:
- 波形失真度
- 相位一致性
- 采样延迟
-
环境适应性:
- 温度漂移特性
- 长期稳定性
在实际项目中,建议建立完整的测试报告模板,记录所有关键指标和测试条件,便于后续分析和问题追踪。