jixulifu2 发表于 2024-8-18 19:24

【中科昊芯HXS320F28025C】电机FOC开环

<div class='showpostmsg'> 本帖最后由 jixulifu2 于 2024-8-18 23:36 编辑

<h3>Field-Oriented Control (FOC) &mdash;&mdash; 磁场定向控制</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>&nbsp;</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&alpha;&beta;的关系:无刷电机通常由UVW三相组成,为了方便计算,需要把三相中每一项的分量隐射到一个直角坐标系U&alpha;,U&beta;中,使用我们最常见的三角函数解一下,如下图示意</p>

<div style="text-align: center;"></div>

<div>公式:</div>

<div><span style="font-size:18px;">U&alpha;​=Ud​cos(&theta;)&minus;Uq​sin(&theta;)</span></div>

<div><span style="font-size:18px;">U&beta;=Udsin⁡(&theta;)+Uqcos⁡(&theta;)</span></div>

<ul>
        <li>U&alpha;​&nbsp;和&nbsp;U&beta; 分别是 &alpha;&beta; 坐标系下的电压分量。</li>
        <li>Ud和&nbsp;Uq分别是 dq 坐标系下的电压分量。</li>
        <li data-spm-anchor-id="5176.28103460.0.i17.541d572cw7AQJP">&theta;&nbsp;是电机定子磁场角度。</li>
</ul>

<p>求出U&alpha;和U&beta;​后传入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 &lt;math.h&gt;

#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&gt; 0.577)Uref= 0.577;                                            
        if(Uref&lt;-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 &gt;= 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>

Jacktang 发表于 2024-8-20 07:25

<p>代码中并没有角度获得方式,可以在主循环while(1)里模拟一个自增的开环角度,好的</p>

freebsder 发表于 2024-8-23 15:44

<p>谢谢分享,期待后续!</p>
页: [1]
查看完整版本: 【中科昊芯HXS320F28025C】电机FOC开环