返回列表 发新帖我要提问本帖赏金: 30.00元(功能说明)

[APM32F4] 基于磁链观测器无感foc的代码解读

[复制链接]
3311|3
 楼主| 穿西装的强子 发表于 2025-1-4 11:53 | 显示全部楼层 |阅读模式
本帖最后由 穿西装的强子 于 2025-1-8 18:47 编辑

#申请原创#  @21小跑堂
无感foc与有感foc的区别只是有没有接入编码器、HALL传感器的区别;
有感foc通过编码器、HALL识别初始角度,计算电角度;
无感foc有许多方案进行电角度识别,高频注入、磁链观测等多种方案,这次只说明磁链观测器的方案解读;
先是foc的配置,一般有但电阻、双电阻、三电阻识别,常用的双电阻识别较多;
理论上双电阻可以计算出第三路电流;
foc大致流程
通过三路电流,Ia,Ib,Ic值,使用clark变化,得到Iα和Iβ;
使用Park变化得到d轴电流和q轴电流;
通过pid电流环使用Id/Iq得到Vd/Vq;
根据编码器或其它方式得到电角度;
使用逆向park变化通过电角度参数得到Vα和Vβ;
计算SVPWM;
根据Vα和Vβ获取当前所在电角度扇区,计算SVPWM的Ta,Tb,Tc值,输出到三相桥的pwm控制;

磁链观测器源码

  1. /***************************************/
  2. //函数功能:观测器初始化
  3. //输入参数:无
  4. //返回值:        无
  5. //备注:
  6. /***************************************/
  7. void flux_observer_init(void)
  8. {
  9.     Foc_observer.Rs = MOTOR_RS;
  10.     Foc_observer.Ls = MOTOR_LS;
  11.     Foc_observer.Flux = MOTOR_FLUX;
  12.    
  13.     Foc_observer.PLL_kp = 0.27f;
  14.     Foc_observer.PLL_ki = 0.028f;
  15.     Foc_observer.PLL_Err = 0.0f;
  16.     Foc_observer.PLL_Interg = 0.0f;
  17.     Foc_observer.PLL_Ui = 0.0f;
  18.    
  19.     Foc_observer.Ctrl_ts = 0.0001f;
  20.     Foc_observer.Gain = 20000.0f;
  21.     Foc_observer.Err = 0.0f;
  22.     Foc_observer.Theta = 0.0f;
  23.     Foc_observer.speed_hz = 0.0f;
  24.    
  25.     flux_in_wb[0] = 0.0f;
  26.     flux_in_wb[1] = 0.0f;
  27.    
  28.     fluxS_in_wb[0] = 0.0f;
  29.     fluxS_in_wb[1] = 0.0f;
  30.    
  31.     fluxR_in_wb[0] = 0.0f;
  32.     fluxR_in_wb[1] = 0.0f;
  33.    
  34.     speed_calc_cnt = 0;
  35.     speed_acc = 0.0f;
  36.     speed_now = 0.0f;
  37. }

  38. /***************************************/
  39. //函数功能:  磁链观测器
  40. //输入参数:无
  41. //返回值:        无
  42. //备注:
  43. /***************************************/
  44. void flux_observer(void)
  45. {
  46.     float VoltRs[2];
  47.     float VoltdPhi[2];
  48.    
  49.     float g_fluxfluxR = 0.0f;
  50.     float sin_theta = 0.0f;
  51.     float cos_theta = 0.0f;
  52.    
  53.     //calc alpha axis flux
  54.     VoltRs[0] = Foc_observer.Rs * Foc_calc.Ialpha;
  55.     VoltdPhi[0] = Foc_calc.Valpha  - VoltRs[0];
  56.     VoltdPhi[0] += fluxR_in_wb[0] * Foc_observer.Err * Foc_observer.Gain;
  57.     flux_in_wb[0] += VoltdPhi[0] * Foc_observer.Ctrl_ts;
  58.    
  59.     //calc beta axis flux
  60.     VoltRs[1] = Foc_observer.Rs * Foc_calc.Ibeta;
  61.     VoltdPhi[1] = Foc_calc.Vbeta  - VoltRs[1];
  62.     VoltdPhi[1] += fluxR_in_wb[1] * Foc_observer.Err * Foc_observer.Gain;
  63.     flux_in_wb[1] += VoltdPhi[1] * Foc_observer.Ctrl_ts;
  64.    
  65.     //calc flux in stator
  66.     fluxS_in_wb[0] = Foc_observer.Ls * Foc_calc.Ialpha;
  67.     fluxS_in_wb[1] = Foc_observer.Ls * Foc_calc.Ibeta;
  68.    
  69.     //calc flux in rotor
  70.     fluxR_in_wb[0] = flux_in_wb[0] - fluxS_in_wb[0];
  71.     fluxR_in_wb[1] = flux_in_wb[1] - fluxS_in_wb[1];
  72.    
  73.     g_fluxfluxR = fluxR_in_wb[0] * fluxR_in_wb[0] + fluxR_in_wb[1] * fluxR_in_wb[1];

  74.     Foc_observer.Err = Foc_observer.Flux * Foc_observer.Flux - g_fluxfluxR;
  75.    
  76.     sin_theta = arm_sin_f32(Foc_observer.Theta);
  77.     cos_theta = arm_cos_f32(Foc_observer.Theta);        

  78.     Foc_observer.PLL_Err = fluxR_in_wb[1] * cos_theta - fluxR_in_wb[0] * sin_theta;
  79.     Foc_observer.PLL_Interg += Foc_observer.PLL_Err * Foc_observer.PLL_ki;        
  80.     Foc_observer.PLL_Ui = Foc_observer.PLL_Err * Foc_observer.PLL_kp + Foc_observer.PLL_Interg;   
  81.    
  82.     Foc_observer.Theta += Foc_observer.PLL_Ui;
  83.    
  84.     if (Foc_observer.Theta < 0.0f)
  85.     {
  86.         Foc_observer.Theta += MATH_2PI;  
  87.     }
  88.     else if (Foc_observer.Theta > MATH_2PI)
  89.     {
  90.         Foc_observer.Theta -= MATH_2PI;  
  91.     }
  92.    
  93.     if (speed_calc_cnt < 10)
  94.     {
  95.         speed_acc += Foc_observer.PLL_Ui;
  96.         speed_calc_cnt++;
  97.     }
  98.     else
  99.     {
  100.         speed_now = speed_acc / (0.001f * MATH_2PI);
  101.         Foc_observer.speed_hz = Foc_observer.speed_hz * 0.99f + speed_now * 0.01f;
  102.         
  103.         speed_acc = 0.0f;
  104.         speed_calc_cnt = 0;
  105.     }
  106. }

flux_observer函数的核心部分,主要实现了基于磁场定向控制(FOC)的电机磁通观测器的计算逻辑。以下是详细的功能解释:

1. 变量声明与初始化
float VoltRs[2];
float VoltdPhi[2];

float g_fluxfluxR = 0.0f;
float sin_theta = 0.0f;
float cos_theta = 0.0f;

VoltRs :存储α轴和β轴的电阻压降。
VoltdPhi :存储α轴和β轴的磁通变化。
g_fluxfluxR :用于存储转子磁通的平方和。
sin_theta  和  cos_theta :用于存储角度的正弦和余弦值。

2. 计算α轴磁通
//calc alpha axis flux
VoltRs[0] = Foc_observer.Rs * Foc_calc.Ialpha;
VoltdPhi[0] = Foc_calc.Valpha - VoltRs[0];
VoltdPhi[0] += fluxR_in_wb[0] * Foc_observer.Err * Foc_observer.Gain;
flux_in_wb[0] += VoltdPhi[0] * Foc_observer.Ctrl_ts;

计算电阻压降 : VoltRs[0] = Foc_observer.Rs * Foc_calc.Ialpha ,其中  Foc_observer.Rs  是电机电阻, Foc_calc.Ialpha  是α轴电流。
计算磁通变化 : VoltdPhi[0] = Foc_calc.Valpha - VoltRs[0] ,即α轴电压减去电阻压降。
添加误差修正 : VoltdPhi[0] += fluxR_in_wb[0] * Foc_observer.Err * Foc_observer.Gain ,根据转子磁通误差进行修正。
更新总磁通 : flux_in_wb[0] += VoltdPhi[0] * Foc_observer.Ctrl_ts ,根据时间步长更新α轴磁通。

3. 计算β轴磁通
//calc beta axis flux
VoltRs[1] = Foc_observer.Rs * Foc_calc.Ibeta;
VoltdPhi[1] = Foc_calc.Vbeta - VoltRs[1];
VoltdPhi[1] += fluxR_in_wb[1] * Foc_observer.Err * Foc_observer.Gain;
flux_in_wb[1] += VoltdPhi[1] * Foc_observer.Ctrl_ts;

计算电阻压降 : VoltRs[1] = Foc_observer.Rs * Foc_calc.Ibeta ,其中  Foc_calc.Ibeta  是β轴电流。
计算磁通变化 : VoltdPhi[1] = Foc_calc.Vbeta - VoltRs[1] ,即β轴电压减去电阻压降。
添加误差修正 : VoltdPhi[1] += fluxR_in_wb[1] * Foc_observer.Err * Foc_observer.Gain ,根据转子磁通误差进行修正。
更新总磁通 : flux_in_wb[1] += VoltdPhi[1] * Foc_observer.Ctrl_ts ,根据时间步长更新β轴磁通。

4. 计算定子磁通
//calc flux in stator
fluxS_in_wb[0] = Foc_observer.Ls * Foc_calc.Ialpha;
fluxS_in_wb[1] = Foc_observer.Ls * Foc_calc.Ibeta;

计算定子磁通 :根据电感 ( Foc_observer.Ls ) 和电流 ( Foc_calc.Ialpha ,  Foc_calc.Ibeta ) 计算定子磁通。

5. 计算转子磁通
//calc flux in rotor
fluxR_in_wb[0] = flux_in_wb[0] - fluxS_in_wb[0];
fluxR_in_wb[1] = flux_in_wb[1] - fluxS_in_wb[1];

计算转子磁通 :从总磁通中减去定子磁通得到转子磁通。

6. 计算磁通误差
g_fluxfluxR = fluxR_in_wb[0] * fluxR_in_wb[0] + fluxR_in_wb[1] * fluxR_in_wb[1];
Foc_observer.Err = Foc_observer.Flux * Foc_observer.Flux - g_fluxfluxR;

计算转子磁通的平方和 : g_fluxfluxR = fluxR_in_wb[0] * fluxR_in_wb[0] + fluxR_in_wb[1] * fluxR_in_wb[1] 。
更新磁通误差 : Foc_observer.Err = Foc_observer.Flux * Foc_observer.Flux - g_fluxfluxR ,即期望磁通的平方减去实际磁通的平方和。

7. 计算PLL误差
sin_theta = arm_sin_f32(Foc_observer.Theta);
cos_theta = arm_cos_f32(Foc_observer.Theta);        

Foc_observer.PLL_Err = fluxR_in_wb[1] * cos_theta - fluxR_in_wb[0] * sin_theta;
Foc_observer.PLL_Interg += Foc_observer.PLL_Err * Foc_observer.PLL_ki;        
Foc_observer.PLL_Ui = Foc_observer.PLL_Err * Foc_observer.PLL_kp + Foc_observer.PLL_Interg;   

计算正弦和余弦值 :使用  arm_sin_f32  和  arm_cos_f32  计算当前角度的正弦和余弦。
计算PLL误差 : Foc_observer.PLL_Err = fluxR_in_wb[1] * cos_theta - fluxR_in_wb[0] * sin_theta 。
更新PLL积分项 : Foc_observer.PLL_Interg += Foc_observer.PLL_Err * Foc_observer.PLL_ki 。
计算PLL输出 : Foc_observer.PLL_Ui = Foc_observer.PLL_Err * Foc_observer.PLL_kp + Foc_observer.PLL_Interg 。

8. 更新角度
Foc_observer.Theta += Foc_observer.PLL_Ui;

if (Foc_observer.Theta < 0.0f)
{
    Foc_observer.Theta += MATH_2PI;  
}
else if (Foc_observer.Theta > MATH_2PI)
{
    Foc_observer.Theta -= MATH_2PI;  
}

更新角度 :根据PLL输出更新角度。
确保角度在合理范围内 :如果角度小于0,则加2π;如果角度大于2π,则减2π。

9. 计算速度
if (speed_calc_cnt < 10)
{
    speed_acc += Foc_observer.PLL_Ui;
    speed_calc_cnt++;
}
else
{
    speed_now = speed_acc / (0.001f * MATH_2PI);
    Foc_observer.speed_hz = Foc_observer.speed_hz * 0.99f + speed_now * 0.01f;

    speed_acc = 0.0f;
    speed_calc_cnt = 0;
}

累加PLL输出 :当计数小于10时,累加PLL输出。
计算当前速度 :当计数等于10时,计算平均速度并更新速度估计。
重置计数 :重置速度累加器和计数器以便下一次循环。

这段代码通过一系列计算,实现了对电机α轴和β轴磁通的观测,并根据观测结果调整角度和速度。具体步骤包括计算电阻压降、磁通变化、定子和转子磁通、磁通误差、PLL误差,以及更新角度和速度。



打赏榜单

21小跑堂 打赏了 30.00 元 2025-01-16
理由:恭喜通过原创审核!期待您更多的原创作品~

评论

FOC控制中的磁链观测器源码的逐行解读,通过对源码的解读分析,更容易理解FOC的电机磁通观测器的计算逻辑  发表于 2025-1-16 17:19
药无尘 发表于 2025-1-8 15:51 | 显示全部楼层
挺好的文章,搞的有点乱,后面代码的讲解能排版好点就好了
 楼主| 穿西装的强子 发表于 2025-1-8 18:48 | 显示全部楼层
药无尘 发表于 2025-1-8 15:51
挺好的文章,搞的有点乱,后面代码的讲解能排版好点就好了

感谢反馈,已重新排版
您需要登录后才可以回帖 登录 | 注册

本版积分规则

63

主题

264

帖子

3

粉丝
快速回复 在线客服 返回列表 返回顶部