【中科昊芯HXS320F28025C】电机FOC开环
<div class='showpostmsg'> 本帖最后由 jixulifu2 于 2024-8-18 23:36 编辑<h3>Field-Oriented Control (FOC) —— 磁场定向控制</h3>
<p data-spm-anchor-id="5176.28103460.0.i5.541d572c6tS0R4">磁场定向控制(Field-Oriented Control,简称FOC)是一种先进的电机控制策略,主要用于交流电机(如感应电机和永磁同步电机)的高性能控制。FOC的主要目的是通过精确控制电机的磁场和转矩,来实现电机的高效和精确控制。</p>
<h3>FOC的工作原理</h3>
<p>FOC的核心思想是将电机的旋转坐标系(dq坐标系)与电机的磁场方向对齐,从而将电机的多相(通常是三相)电流分解成两个独立的分量:励磁电流(d轴电流)和转矩电流(q轴电流)。这种分解使得电机的控制变得更加直观和简单,因为可以通过单独控制这两个分量来分别控制电机的磁场和转矩。</p>
<p> </p>
<p>下面是FOC经典框图</p>
<p></p>
<p>HXS320F280025C是昊芯浮点DSC平台上的最新产品,基于自主研发的H28x内核,32位浮点RISC-V DSP架构,支持三角函数数学单元和CRC扩展指令集,完美适配FOC。该片增加了可配置逻辑模块(CLB),用户可添加自定义逻辑:支持多种通信端口,增强型控制外设,可满足电机驱动/控制、光伏逆变器和数字电源等行业的产品布局;基于FPU浮点处理单元,支持FOC算法、有感/无感角度分析、多电平控制、复杂电力电子拓扑算法以及宽带半导体驱动等应用。</p>
<p>今天我们手撸一个简易FOC开环框架:</p>
<p>思路解析解析:</p>
<p>刨去三环,编码器和3相全桥电路,我们要实现的是输入Ud.Uq,angle,输出ABC桥控制信号,也就是占空比信息。</p>
<p>Ud、Uq:通常称为 dq 坐标系。这个坐标系包括 d 轴(励磁轴)和 q 轴(转矩轴)。Ud 表示 d 轴上的电压分量,Uq 是施加在 q 轴上的电压分量,用于控制转矩电流 Iq。转矩电流 Iq 与电机产生的转矩有关,通过控制 Uq,可以调整电机的转矩。这两个值是我们人为设定的,所以只需要在后面代码中传入参数计算就可以。</p>
<p>Ud、Uq与Uαβ的关系:无刷电机通常由UVW三相组成,为了方便计算,需要把三相中每一项的分量隐射到一个直角坐标系Uα,Uβ中,使用我们最常见的三角函数解一下,如下图示意</p>
<div style="text-align: center;"></div>
<div>公式:</div>
<div><span style="font-size:18px;">Uα=Udcos(θ)−Uqsin(θ)</span></div>
<div><span style="font-size:18px;">Uβ=Udsin(θ)+Uqcos(θ)</span></div>
<ul>
<li>Uα 和 Uβ 分别是 αβ 坐标系下的电压分量。</li>
<li>Ud和 Uq分别是 dq 坐标系下的电压分量。</li>
<li data-spm-anchor-id="5176.28103460.0.i17.541d572cw7AQJP">θ 是电机定子磁场角度。</li>
</ul>
<p>求出Uα和Uβ后传入SVPWM模块</p>
<p>SVPWM介绍:SVPWM的核心是将电机所需的电压表示为一系列空间矢量,并通过选择适当的电压矢量来合成期望的输出电压。这种方法能够更高效地利用逆变器的电压和电流容量,进而提高电机驱动系统的整体效率。</p>
<p>放两张教材里的图吧,详细介绍的话可以单独开一个篇章,有兴趣的小伙伴自行查看吧</p>
<div style="text-align: center;"></div>
<div style="text-align: center;"></div>
<div style="text-align: center;"></div>
<div style="text-align: center;"></div>
<div style="text-align: center;"></div>
<div>接下来是Clark变换:</div>
<div>主要用于将三相静止坐标系下的信号转换到两相静止坐标系下,理解了Clark也就理解了反Park</div>
<div>
<ul>
<li data-spm-anchor-id="5176.28103460.0.i45.541d572cw7AQJP"><strong>减少维度</strong>:从三个变量减少到两个变量,简化了控制系统的设计。</li>
<li><strong>保持功率不变</strong>:Clark变换是等功率变换,即变换前后系统的总功率保持不变。</li>
<li data-spm-anchor-id="5176.28103460.0.i46.541d572cw7AQJP"><strong>便于控制</strong>:两相坐标系下的信号更容易被控制算法处理,特别是对于矢量控制技术而言</li>
</ul>
<p>接下来就愉快的手撸代码吧:</p>
</div>
<p>延续上一期的工程,新建一个FOC.c和FOC.h</p>
<pre>
<code class="language-cpp">#include "FOC.h"
#include <math.h>
#define PWM_Period
#define _PI 3.14159265359
#define _PI_2 1.57079632679
#define _PI_3 1.0471975512
#define _2PI 6.28318530718
#define _3PI_2 4.71238898038
#define _PI_6 0.52359877559
#define _SQRT3 1.73205080757
float voltage_power_supply;
// 设置PWM
// 输入参数:
// - Uq: q轴电压分量
// - Ud: d轴电压分量
// - angle_el: 电角度
void SetSVPWM(float Uq, float Ud, float angle_el)
{
float Uref;
float U_alpha,U_beta;
float T0,T1,T2;
float Ta,Tb,Tc;
int sector;
//反Park
U_alpha=Ud*cos(angle_el)-Uq*sin(angle_el);
U_beta=Ud*sin(angle_el)+Uq*cos(angle_el);
//计算参考电压矢量的幅值
Uref=_sqrt(U_alpha*U_alpha + U_beta*U_beta) / voltage_power_supply;
//六边形的内切圆(SVPWM最大不失真旋转电压矢量赋值)根号3/3
if(Uref> 0.577)Uref= 0.577;
if(Uref<-0.577)Uref=-0.577;
//判断参考电压矢量所在扇区:
angle_el = Angle_deal(angle_el+_PI_2);
sector = (angle_el / _PI_3) + 1;
//计算两个相邻电压矢量作用时间
T1 = _SQRT3*sin(sector*_PI_3 - angle_el) * Uref;
T2 = _SQRT3*sin(angle_el - (sector-1.0)*_PI_3) * Uref;
T0 = 1 - T1 - T2;
switch(sector)
{
case 1:
Ta = T1 + T2 + T0/2;
Tb = T2 + T0/2;
Tc = T0/2;
break;
case 2:
Ta = T1 +T0/2;
Tb = T1 + T2 + T0/2;
Tc = T0/2;
break;
case 3:
Ta = T0/2;
Tb = T1 + T2 + T0/2;
Tc = T2 + T0/2;
break;
case 4:
Ta = T0/2;
Tb = T1+ T0/2;
Tc = T1 + T2 + T0/2;
break;
case 5:
Ta = T2 + T0/2;
Tb = T0/2;
Tc = T1 + T2 + T0/2;
break;
case 6:
Ta = T1 + T2 + T0/2;
Tb = T0/2;
Tc = T1 + T0/2;
break;
default:// 错误状态
Ta = 0;
Tb = 0;
Tc = 0;
}
//输出PWM,配置占空比
EPWM_setCounterCompareValue(epwm1Info.epwmModule,EPWM_COUNTER_COMPARE_A, Ta*PWM_Period);
EPWM_setCounterCompareValue(epwm2Info.epwmModule,EPWM_COUNTER_COMPARE_A, Tb*PWM_Period);
EPWM_setCounterCompareValue(epwm3Info.epwmModule,EPWM_COUNTER_COMPARE_A, Tc*PWM_Period);
}
//将输入的角度 angle 归一化到 [0, 2π) 区间内。
float Angle_deal(float angle)
{
float a = fmod(angle, _2PI);
return a >= 0 ? a : (a + _2PI);
}</code></pre>
<p>代码中并没有角度获得方式,可以在主循环while(1)里模拟一个自增的开环角度,当然也可以来自编码器、霍尔或者无传感器算法估算的转子位置。</p>
<p>受限于手头并没有实物,我们就不做演示了。</p>
</div><script> var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;" style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
if(parseInt(discuz_uid)==0){
(function($){
var postHeight = getTextHeight(400);
$(".showpostmsg").html($(".showpostmsg").html());
$(".showpostmsg").after(loginstr);
$(".showpostmsg").css({height:postHeight,overflow:"hidden"});
})(jQuery);
} </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script> <p>代码中并没有角度获得方式,可以在主循环while(1)里模拟一个自增的开环角度,好的</p>
<p>谢谢分享,期待后续!</p>
页:
[1]