在电机控制领域,永磁同步电机(PMSM)的无传感器控制一直是工程师们关注的焦点。传统观测器方案在零低速场合表现不佳,而高频方波注入技术恰好弥补了这一缺陷。但要将算法从理论仿真落地到实际硬件平台,需要跨越三大技术鸿沟:
首先是时序精确性问题。高频注入需要在特定时刻施加激励信号并采集响应电流,这对代码执行的时序精度提出了严苛要求。在Simulink离散仿真环境中,模块化的建模方式往往难以保证时序的严格同步。
其次是计算实时性挑战。FOC算法本身就需要在每个PWM周期内完成Clarke变换、Park变换、PI调节、反Park变换和SVPWM生成等一系列运算,再加入高频注入的信号处理和位置估算,对处理器的计算能力提出了更高要求。
最后是工程实现复杂度。实际系统中需要考虑死区效应补偿、电流采样噪声抑制、参数鲁棒性等现实问题,这些都是在纯仿真环境中容易被忽略的关键细节。
传统Simulink建模采用离散模块组合的方式,虽然直观但存在两个致命缺陷:一是模块间数据传输引入的延迟会导致时序错乱,二是生成的代码结构冗余效率低下。而S-Function(系统函数)方案则完美解决了这些问题:
c复制#define S_FUNCTION_NAME PMSM_HFI_FOC
#define S_FUNCTION_LEVEL 2
#include "simstruc.h"
static void mdlInitializeSizes(SimStruct *S) {
ssSetNumSFcnParams(S, 0);
if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) return;
ssSetNumContStates(S, 0);
ssSetNumDiscStates(S, 1);
// 配置输入输出端口
if (!ssSetNumInputPorts(S, 3)) return;
ssSetInputPortWidth(S, 0, 2); // Ia, Ib电流
ssSetInputPortWidth(S, 1, 1); // 速度给定
ssSetInputPortWidth(S, 2, 1); // 使能信号
if (!ssSetNumOutputPorts(S, 4)) return;
ssSetOutputPortWidth(S, 0, 3); // PWM占空比
ssSetOutputPortWidth(S, 1, 1); // 估算角度
ssSetOutputPortWidth(S, 2, 1); // 估算速度
ssSetOutputPortWidth(S, 3, 1); // 状态标志
}
高频方波注入需要严格遵循"注入-采样-处理"的周期性流程,采用状态机实现是最佳选择。在我们的设计中,将整个控制过程划分为6个状态:
c复制typedef enum {
INIT,
INJ_POS,
SAMP_POS,
INJ_NEG,
SAMP_NEG,
PROCESS
} HFI_State;
typedef struct {
HFI_State state;
uint16_t counter;
float I_alpha_pos, I_beta_pos;
float I_alpha_neg, I_beta_neg;
float theta_est;
float speed_est;
} HFI_Handler;
状态转换通过计数器精确控制,确保每个状态持续时间与PWM周期严格同步。例如正向注入阶段持续2个PWM周期(5kHz开关频率下为400us),正好对应2.5kHz的注入频率。
高频方波注入的本质是通过施加高频电压激励,利用电机凸极效应产生的响应电流来提取转子位置信息。具体实现时需要解决三个关键问题:
c复制void HFI_Inject(HFI_Handler *h, Motor *m) {
switch(h->state) {
case INJ_POS:
// 施加Vh电压矢量
SVM_SetVoltage(m->Vh, 0, m->pwm);
if(++h->counter >= INJ_CYCLES) {
h->state = SAMP_POS;
h->counter = 0;
}
break;
case SAMP_POS:
// 采集正向电流
ClarkeTransform(m->Ia, m->Ib, &h->I_alpha_pos, &h->I_beta_pos);
h->state = INJ_NEG;
break;
case PROCESS:
// 计算电流差异
float delta_Ialpha = h->I_alpha_pos - h->I_alpha_neg;
float delta_Ibeta = h->I_beta_pos - h->I_beta_neg;
// 外差法解算位置
h->theta_est = atan2f(delta_Ibeta, delta_Ialpha) / 2;
h->state = INJ_POS;
break;
}
}
原始的外差法计算得到的角度存在两个问题:一是反正切函数的计算耗时较大,二是在过零点附近存在跳变。我们采用三种优化手段:
c复制typedef struct {
float theta;
float speed;
float Kp;
float Ki;
float err_prev;
} PLL_Estimator;
void PLL_Update(PLL_Estimator *pll, float theta_meas, float Ts) {
float err = theta_meas - pll->theta;
// 角度差相位包装
if(err > PI) err -= 2*PI;
else if(err < -PI) err += 2*PI;
// PI调节器
pll->speed = pll->Kp * err + pll->Ki * (err + pll->err_prev) * Ts/2;
pll->theta += pll->speed * Ts;
// 角度归一化
if(pll->theta > PI) pll->theta -= 2*PI;
else if(pll->theta < -PI) pll->theta += 2*PI;
pll->err_prev = err;
}
良好的代码结构是算法可靠运行的基础。我们将整个FOC系统分解为多个功能模块,每个模块用独立的结构体管理相关数据和配置:
c复制typedef struct {
float Kp;
float Ki;
float Kd;
float out_max;
float out_min;
float integral;
float prev_err;
} PID_Controller;
typedef struct {
float Udc;
float Tdead;
float Ts;
uint16_t cnt_max;
} PWM_Config;
typedef struct {
float Rs;
float Ld;
float Lq;
float psi;
float pole_pairs;
} Motor_Params;
typedef struct {
PID_Controller speed_pid;
PID_Controller id_pid;
PID_Controller iq_pid;
PWM_Config *pwm;
Motor_Params *params;
float theta_mech;
float speed_mech;
} FOC_Handler;
这种设计带来三大优势:
电流环作为FOC最内层的控制回路,其性能直接影响整个系统的动态响应。我们实现了三种优化策略:
c复制void CurrentLoopUpdate(FOC_Handler *foc, float Id_ref, float Iq_ref,
float Id_meas, float Iq_meas, float omega_e) {
// d轴电压前馈
float Vd_ff = foc->params->Rs * Id_ref - omega_e * foc->params->Lq * Iq_meas;
// q轴电压前馈
float Vq_ff = foc->params->Rs * Iq_ref + omega_e *
(foc->params->Ld * Id_meas + foc->params->psi);
// PI调节器
float Vd_pi = PID_Update(&foc->id_pid, Id_ref - Id_meas);
float Vq_pi = PID_Update(&foc->iq_pid, Iq_ref - Iq_meas);
// 合成最终电压
foc->Vd = Vd_ff + Vd_pi;
foc->Vq = Vq_ff + Vq_pi;
}
在实际逆变器中,IGBT的开关过程存在不可忽略的延迟时间(通常0.5-5us)。为防止上下管直通,必须插入死区时间,这会导致输出电压畸变,具体表现为:
死区效应引起的电压误差可以表示为:
code复制V_err = sign(I) * (Tdead/Ts) * Vdc
其中Tdead为死区时间,Ts为PWM周期,Vdc为母线电压。
我们实现了一种实时补偿算法,核心思想是根据电流极性动态调整PWM占空比:
c复制void DeadTimeCompensation(PWM_Phase *p, float I, PWM_Config *cfg) {
float comp = cfg->Tdead / cfg->Ts * cfg->Udc;
if(I > 0.1f) { // 正向电流
p->ton += comp;
}
else if(I < -0.1f) { // 负向电流
p->toff += comp;
}
// 边界保护
p->ton = constrain(p->ton, 0, cfg->cnt_max);
p->toff = constrain(p->toff, 0, cfg->cnt_max);
}
实际应用中还需要注意:
整个无感FOC系统的参数调试需要遵循特定顺序:
电流环整定:
速度环整定:
高频注入参数:
在实际调试中经常会遇到以下典型问题:
问题1:启动时电机抖动
问题2:带载能力差
问题3:高速时估算误差大
在TMS320F28335平台上实现的测试结果表明:
低速性能:
动态响应:
稳态精度:
关键波形图示:
这套方案已经成功应用于多个工业现场,包括:
移植到不同平台时需要注意三点: