4. 电流采样与重构
任务目标
本案例实现永磁同步电机FOC控制中的相电流采样与重构。采用单电阻采样方案,在PWM周期内两次触发ADC,分别采集直流母线电流,结合当前开关状态重构出两相电流,并通过基尔霍夫定律计算第三相电流,最终输出完整的三相电流值供FOC算法使用。
实现原理
单电阻采样利用直流母线串联采样电阻,在PWM不同开关组合下,母线电流对应不同的相电流。通过在一个PWM周期内安排两次采样(分别在PWM中心处和边沿处),可覆盖全部六个扇区。采样时刻由PWM定时器同步触发ADC,确保采样点位于开关状态稳定区间。
关键代码
// current_sampling.h
#ifndef CURRENT_SAMPLING_H
#define CURRENT_SAMPLING_H
#include <stdint.h>
typedef struct {
float ia; // A相电流
float ib; // B相电流
float ic; // C相电流
} ThreePhaseCurrent;
typedef struct {
uint16_t adc_value1; // 第一次采样值(PWM中心)
uint16_t adc_value2; // 第二次采样值(PWM边沿)
float bus_voltage; // 母线电压(V)
float shunt_resistor; // 采样电阻(Ω)
float gain; // 放大倍数
uint8_t sector; // 当前扇区(0-5)
} SingleShuntSample;
// 初始化采样参数
void CurrentSampling_Init(SingleShuntSample *sample, float bus_voltage,
float shunt_resistor, float gain);
// 根据扇区重构三相电流
ThreePhaseCurrent CurrentSampling_Reconstruct(SingleShuntSample *sample);
#endif
// current_sampling.c
#include "current_sampling.h"
static float adc_to_current(uint16_t adc_value, float vref, uint16_t adc_max,
float shunt_resistor, float gain) {
float voltage = (float)adc_value * vref / (float)adc_max;
return voltage / (shunt_resistor * gain);
}
void CurrentSampling_Init(SingleShuntSample *sample, float bus_voltage,
float shunt_resistor, float gain) {
sample->bus_voltage = bus_voltage;
sample->shunt_resistor = shunt_resistor;
sample->gain = gain;
sample->adc_value1 = 0;
sample->adc_value2 = 0;
sample->sector = 0;
}
ThreePhaseCurrent CurrentSampling_Reconstruct(SingleShuntSample *sample) {
ThreePhaseCurrent currents = {0, 0, 0};
float vref = 3.3f; // ADC参考电压
uint16_t adc_max = 4095; // 12位ADC
// 将两次ADC采样值转换为电流
float i_sample1 = adc_to_current(sample->adc_value1, vref, adc_max,
sample->shunt_resistor, sample->gain);
float i_sample2 = adc_to_current(sample->adc_value2, vref, adc_max,
sample->shunt_resistor, sample->gain);
// 根据扇区重构相电流
// 扇区定义:0-5对应空间矢量图的六个扇区
switch (sample->sector) {
case 0: // 扇区I: 上桥A导通,B、C下桥导通
currents.ia = i_sample1;
currents.ib = -i_sample2;
break;
case 1: // 扇区II: 上桥A、B导通,C下桥导通
currents.ia = i_sample1;
currents.ic = -i_sample2;
break;
case 2: // 扇区III: 上桥B导通,A、C下桥导通
currents.ib = i_sample1;
currents.ia = -i_sample2;
break;
case 3: // 扇区IV: 上桥B、C导通,A下桥导通
currents.ib = i_sample1;
currents.ia = -i_sample2;
break;
case 4: // 扇区V: 上桥C导通,A、B下桥导通
currents.ic = i_sample1;
currents.ib = -i_sample2;
break;
case 5: // 扇区VI: 上桥C、A导通,B下桥导通
currents.ic = i_sample1;
currents.ia = -i_sample2;
break;
default:
break;
}
// 由基尔霍夫定律计算第三相电流 (ia + ib + ic = 0)
if (sample->sector == 0 || sample->sector == 3) {
currents.ic = -(currents.ia + currents.ib);
} else if (sample->sector == 1 || sample->sector == 4) {
currents.ib = -(currents.ia + currents.ic);
} else if (sample->sector == 2 || sample->sector == 5) {
currents.ia = -(currents.ib + currents.ic);
}
return currents;
}
测试代码
#include <stdio.h>
#include "current_sampling.h"
int main() {
SingleShuntSample sample;
CurrentSampling_Init(&sample, 24.0f, 0.01f, 10.0f);
// 模拟扇区I的采样值
// 假设实际电流: ia = 2.0A, ib = -1.0A, ic = -1.0A
// 母线电流在扇区I: 第一次采样 = ia = 2.0A, 第二次采样 = -ib = 1.0A
// 电压 = 电流 * 电阻 * 增益 = 2.0 * 0.01 * 10 = 0.2V
// ADC值 = 电压 / 3.3 * 4095 = 248
sample.sector = 0;
sample.adc_value1 = 248; // 对应2.0A
sample.adc_value2 = 124; // 对应1.0A
ThreePhaseCurrent result = CurrentSampling_Reconstruct(&sample);
printf("重构结果:\n");
printf("ia = %.2f A\n", result.ia);
printf("ib = %.2f A\n", result.ib);
printf("ic = %.2f A\n", result.ic);
// 验证: 三相电流之和应接近0
float sum = result.ia + result.ib + result.ic;
printf("三相电流之和: %.2f A\n", sum);
if (sum < 0.01f && sum > -0.01f) {
printf("测试通过: 三相电流满足基尔霍夫定律\n");
return 0;
} else {
printf("测试失败: 三相电流之和不为零\n");
return 1;
}
}
编译与运行
gcc -o test_sampling current_sampling.c test_sampling.c -lm
./test_sampling
验证方法
运行测试程序后,观察输出结果。预期输出为:
重构结果:
ia = 2.00 A
ib = -1.00 A
ic = -1.00 A
三相电流之和: 0.00 A
测试通过: 三相电流满足基尔霍夫定律
判定通过条件:三相电流之和值小于0.01A,且各相电流值与输入设定一致。实际工程中,需将ADC采样值替换为真实ADC外设读取值,并确保PWM触发ADC的采样时刻与扇区判断逻辑正确同步。