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的采样时刻与扇区判断逻辑正确同步。