4. 采样窗口计算与验证

任务目标

在单电阻FOC系统中,三相PWM占空比决定母线电流采样时刻。本案例计算不同占空比组合下的有效采样窗口宽度,并验证窗口是否满足ADC采样保持时间要求。

采样窗口定义

单电阻采样利用下桥臂导通期间流过采样电阻的相电流。当两相下桥臂同时导通时,母线电流等于第三相电流。有效采样窗口指两相下桥臂同时导通的时间段,其宽度由占空比决定。

设三相占空比为 \(d_a, d_b, d_c\)(0~1),采用中心对齐PWM。两相下桥臂同时导通的条件是这两相的占空比均小于第三相。窗口宽度计算规则:

  • 将三相占空比排序:\(d_{min} \le d_{mid} \le d_{max}\)
  • 窗口1(对应最大相电流):宽度 = \(d_{mid} - d_{min}\),出现在最小相与中间相下桥臂同时导通期间
  • 窗口2(对应中间相电流):宽度 = \(d_{max} - d_{mid}\),出现在最小相与最大相下桥臂同时导通期间

实际采样需选择宽度较大的窗口,且该宽度必须大于ADC采样保持时间与开关噪声稳定时间之和。

完整实现代码

#include <stdio.h>
#include <stdint.h>
#include <math.h>

#define PWM_FREQ        20000.0f   // 20kHz
#define PWM_PERIOD      1.0f/PWM_FREQ
#define ADC_SAMPLE_TIME 1.0e-6f    // 1us ADC采样保持
#define SWITCH_SETTLE   0.5e-6f    // 0.5us开关噪声稳定
#define MIN_WINDOW      (ADC_SAMPLE_TIME + SWITCH_SETTLE)

// 三相占空比结构
typedef struct {
    float da, db, dc;
} Duty3Phase;

// 排序辅助
static void sort3(float* a, float* b, float* c) {
    float tmp;
    if (*a > *b) { tmp=*a; *a=*b; *b=tmp; }
    if (*b > *c) { tmp=*b; *b=*c; *c=tmp; }
    if (*a > *b) { tmp=*a; *a=*b; *b=tmp; }
}

// 计算两个采样窗口宽度(单位:秒)
void calc_windows(Duty3Phase d, float* win1, float* win2) {
    float dmin = d.da, dmid = d.db, dmax = d.dc;
    sort3(&dmin, &dmid, &dmax);
    
    // 窗口宽度 = 占空比差 × PWM周期 / 2(中心对齐,双边对称)
    *win1 = (dmid - dmin) * PWM_PERIOD / 2.0f;
    *win2 = (dmax - dmid) * PWM_PERIOD / 2.0f;
}

// 验证采样可行性
// 返回1表示至少一个窗口可用,0表示不可用
int verify_sampling(Duty3Phase d, float* best_win) {
    float w1, w2;
    calc_windows(d, &w1, &w2);
    
    float w_max = (w1 > w2) ? w1 : w2;
    *best_win = w_max;
    
    if (w_max >= MIN_WINDOW) {
        printf("窗口1=%.3fus  窗口2=%.3fus  最大=%.3fus\n", 
               w1*1e6f, w2*1e6f, w_max*1e6f);
        printf("最小要求=%.3fus → 采样可行\n", MIN_WINDOW*1e6f);
        return 1;
    } else {
        printf("窗口1=%.3fus  窗口2=%.3fus  最大=%.3fus\n", 
               w1*1e6f, w2*1e6f, w_max*1e6f);
        printf("最小要求=%.3fus → 采样不可行,需移相或插入零矢量\n", MIN_WINDOW*1e6f);
        return 0;
    }
}

int main() {
    // 测试用例1:正常占空比(约60°/180°扇区)
    Duty3Phase d1 = {0.30f, 0.50f, 0.80f};
    printf("=== 用例1: da=0.30 db=0.50 dc=0.80 ===\n");
    float best;
    verify_sampling(d1, &best);
    
    // 测试用例2:窄窗口(占空比接近)
    Duty3Phase d2 = {0.40f, 0.45f, 0.50f};
    printf("\n=== 用例2: da=0.40 db=0.45 dc=0.50 ===\n");
    verify_sampling(d2, &best);
    
    // 测试用例3:极端占空比(接近0或1)
    Duty3Phase d3 = {0.05f, 0.50f, 0.95f};
    printf("\n=== 用例3: da=0.05 db=0.50 dc=0.95 ===\n");
    verify_sampling(d3, &best);
    
    return 0;
}

编译与运行

gcc -o window_calc window_calc.c -lm
./window_calc

验证方法与判定标准

程序输出每个用例的两个窗口宽度及最大窗口值,并与最小要求(1.5μs)比较:

  • 用例1(0.30/0.50/0.80):窗口1=(0.50-0.30)×25μs=5.0μs,窗口2=(0.80-0.50)×25μs=7.5μs,最大7.5μs ≥ 1.5μs → 可行
  • 用例2(0.40/0.45/0.50):窗口1=(0.45-0.40)×25μs=1.25μs,窗口2=(0.50-0.45)×25μs=1.25μs,最大1.25μs < 1.5μs → 不可行
  • 用例3(0.05/0.50/0.95):窗口1=(0.50-0.05)×25μs=11.25μs,窗口2=(0.95-0.50)×25μs=11.25μs,最大11.25μs ≥ 1.5μs → 可行

判定通过条件:程序输出与上述计算一致,且能正确区分可行与不可行场景。用例2验证了窄窗口检测能力——当占空比过于接近时,采样窗口不足,需要在实际系统中通过移相或调整PWM模式解决。

关键说明

中心对齐PWM下,窗口宽度为占空比差×半周期(因上下计数对称,每周期出现两次采样窗口)。实际ADC触发应设置在窗口中心点,即最小相与中间相下桥臂同时导通的中间时刻。若最大窗口仍不足,需采用移相或非对称PWM扩展采样窗口。