在前面的博客已经讲到电机本体的Simulink模型搭建,其中能够自定义电机的库模型,或者直接经过仿真器件进行搭建均可以。这部份内容能够参考前面的内容:电机的数学模型永磁同步电机的矢量控制策略(二)一一一数学模型html
按照SVPWM的实现流程进行仿真模型搭建,如图1所示。
图1 SVPWM的仿真模型web
对应于专门讲解SVPWM控制波形产生的:SVPWM控制算法
如下附上DSP上专门这块的SVPWM控制C++代码:
先定义函数名称及功能编程
#ifndef Svpwm_dq_H #define Svpwm_dq_H #include "DSP2833x_Project.h" #include "IQmathLib.h" typedef struct { _iq Ualpha; // 二相静止坐标系alpha-轴 _iq Ubeta; // 二相静止坐标系beta-轴 _iq Ta; // 三相矢量占空比Ta _iq Tb; // 三相矢量占空比Tb _iq Tc; // 三相矢量占空比Tc _iq tmp1; // 三相静止坐标系的电压temp1 _iq tmp2; // 三相静止坐标系的电压temp2 _iq tmp3; // 三相静止坐标系的电压temp3 Uint16 VecSector; //矢量空间扇区号 } SVPWM , *p_SVPWM ; #define SVPWM_DEFAULTS { 0,0,0,0,0,0,0,0,0} // 初始化参数 extern SVPWM Svpwmdq; void SVPWM_Cale(p_SVPWM pV); // svpwm调制算法函数 #endif /* Svpwm_dq*/
再而后接着按SVPWM的输出进行功能函数的编程以下:svg
#include "Main_PMSM_QEncoder.h" SVPWM Svpwmdq=SVPWM_DEFAULTS; // SVPWM是7段式矢量调试,扇区与输出电压占空比通过简化后为对称输出,1和4,2和5,3和6对称 // 文档给出是按照7段式SVPWM一点点按照矢量调制原理推到,中间推到有Uabc的三相电压 // T1和T1做用时间,Txyz时间最终等效Tabc三相输入占空比, // Udc/√3=1=IQ(1.0), 是调制最大电1 是等效为IQ24是16777216 电压利用率是100%,算死区计算2*1.8=3.6/80us=4.5% // 调制利用率等于(1-0.045)=0.955=95.5% 约等于31000 // Ualpha和Ubeta是和uq ud等幅值变换因此都是-32767到32768 void SVPWM_Cale(p_SVPWM pV) { pV->tmp1= pV->Ubeta; // 至关于二相静止坐标--到三相静止变换出Uabc pV->tmp2= _IQdiv2(pV->Ubeta) + (_IQmpy(_IQ(0.866),pV->Ualpha)); pV->tmp3= pV->tmp2 - pV->tmp1; pV->VecSector=3; // 根据三相电压符号计算矢量扇区 pV->VecSector=(pV->tmp2> 0)?( pV->VecSector-1):pV->VecSector; pV->VecSector=(pV->tmp3> 0)?( pV->VecSector-1):pV->VecSector; pV->VecSector=(pV->tmp1< 0)?(7-pV->VecSector) :pV->VecSector; if (pV->VecSector==1 || pV->VecSector==4) // 根据矢量扇区计算矢量占空比Tabc { pV->Ta= pV->tmp2; pV->Tb= pV->tmp1-pV->tmp3; pV->Tc=-pV->tmp2; } else if(pV->VecSector==2 || pV->VecSector==5) { pV->Ta= pV->tmp3+pV->tmp2; pV->Tb= pV->tmp1; pV->Tc=-pV->tmp1; } else { pV->Ta= pV->tmp3; pV->Tb=-pV->tmp3; pV->Tc=-(pV->tmp1+pV->tmp2); } }
SVPWM的输出图形当时在作实验的时候没有记录保存,后续若是容许我更新补充哈,详细结合实验步骤来分析波形特色。函数
没有含有PWM生成的模块,仅含有电流环和转速环的控制,针对数学模型的推导与创建。输出波形如图3所示。
图2 转速环和电流环的电机控制模型oop
图3 电机控制相应量的输出波形:q-d轴电流、转速学习
从图3可看出,依据坐标变换的矢量解耦控制,d轴电流最终趋向于0,q轴最终趋于一个稳定值,这个与坐标变换里面所讲到的结论是一致的。你们能够参考下这个:坐标变换ui
下面给出DSP上专门这块的SVPWM控制C++代码:.net
#ifndef PI_Cale_H #define PI_Cale_H #include "IQmathLib.h" typedef struct { _iq Ref; // PI控制的给定参数 _iq Fbk; // PI控制的反馈参数 _iq Out; // PI控制的输出参数 _iq OutF; // PI控制的滤波后输出参数 _iq Kp; // PI控制的比例参数 _iq Ki; // PI控制的积分参数 _iq Umax; // PI控制的输出限制最大幅值参数 _iq Umin; // PI控制的输出限制最小幅值参数 _iq up; // PI控制的比例项输出参数 _iq ui; // PI控制的积分项输出参数 _iq v1; // PI控制的历史输出项参数 _iq i1; // PI控制的历史积分项输出参数 } PI_Control, *p_PI_Control ; #define PI_Control_DEFAULTS {0,0,0,0,0,0,_IQ(1.0),0,0,0,0,0} // 初始化参数 extern PI_Control pi_spd ; extern PI_Control pi_id ; extern PI_Control pi_iq ; void PI_Controller(p_PI_Control pV); //PI控制算法函数 void PI_Pare_init(void ); //PI控制参数初始化 #endif /* PI_Cale*/
具体的功能函数给出以下:
#include "Main_PMSM_QEncoder.h" PI_Control pi_spd = PI_Control_DEFAULTS; PI_Control pi_id = PI_Control_DEFAULTS; PI_Control pi_iq = PI_Control_DEFAULTS; // 此程序PID是软件文档介绍有区别,文档写出基本PID公式算法 // 此PID省略D,同时加入抗积分保护算法, // 判断PI输出结果是否被限制,达到限制后,这积分保持历史状态,不在累加 // 参考网上抗积分饱和原理 https://blog.csdn.net/qq_22520215/article/details/72896637 // 能够采用抗积分饱和算法,其思路就是:若是上一次的输出控制量超过了饱和值,饱和值为正, // 则这一次只积分负的误差,饱和值为负,则这一次只积分正的误差,从而避免系统长期留在饱和区! void PI_Controller(p_PI_Control pV) { /* proportional term */ pV->up = pV->Ref - pV->Fbk; /* integral term */ pV->ui = (pV->Out == pV->v1)?(_IQmpy(pV->Ki, pV->up)+ pV->i1) : pV->i1; pV->i1 = pV->ui; // 输出值达到保护输出值就锁定积分值不在累加 /* control output*/ pV->v1 = _IQmpy(pV->Kp, (pV->up )) + pV->ui; // _IQmpy 是移位2…^24次方 因此Kp/16777216 pV->Out= _IQsat(pV->v1, pV->Umax, pV->Umin); // 限制输出 } void PI_Pare_init(void ) { //_IQmpy 是移位2…^24次方 因此Kp/16777216 Ki/16777216 pi_spd.Kp=_IQ(0.22); pi_spd.Ki=_IQ(0.00097); // 0.0001*10 / 0.2 T*SpeedLoopPrescaler/0.2 pi_spd.Umax =_IQ(0.85); pi_spd.Umin =_IQ(0.0); // 二闭环 speed和id闭环,采用速度闭环 id电流闭环 则速度环输出uq电压 //三个闭环,id闭环输出为电压Vd,speed速度闭环输出给定电流iq,iq闭环输出等于给定Vq //速度环输出的是参考电流,本开发板的电流设计±8A左右,100mr电路,电路放大2倍,电流中点电压1.65V pi_id.Kp=_IQ(0.025); // pi_id.Ki=_IQ(0.00048); // pi_id.Umax =_IQ(0.1); pi_id.Umin =_IQ(-0.1); pi_iq.Kp=_IQ(0.028); pi_iq.Ki=_IQ(0.00056); pi_iq.Umax =_IQ(0.85); pi_iq.Umin =_IQ(0.0); }
1.双闭环矢量控制策略:转速环PI控制器+电流环PI控制器+SVPWM
2.双闭环矢量控制策略: 转速环PI控制器+电流环PI控制器+SVPWM+电流环的前馈补偿控制
3.双闭环矢量控制策略: 转速环SMC控制器+电流环PI控制器+SVPWM
4.双闭环矢量控制策略: 转速环SMC控制器+电流环PI控制器+SVPWM+电流环的前馈补偿控制
5.双闭环矢量控制策略: 转速环ADRC控制器+电流环PI控制器+SVPWM
6.双闭环矢量控制策略:转速环复合控制策略(PI+SMC)+电流环PI控制器+SVPWM
**微电机核心期刊论文已录用,而且正式刊出《基于滑模观测器估计偏差反馈的永磁同步电机转速控制策略》**有须要参考学习的朋友能够私我。
如下是学习LADRC的源代码,后续的LADRC学习资料和具体讲解敬请期待后续博客更新。
LADRC的DSP源代码以下:
#ifndef LADRC_H #define LADRC_H #include <stdint.h> #include <stdio.h> #include "IQmathLib.h" #include "math.h" typedef struct { //两个输入一个输出共32个 /*****安排过分过程TD*******///8 float ref; //自抗扰控制的给定转速 float x1; //跟踪微分期状态量 float x2; //跟踪微分期状态量微分项 float r; //时间尺度 float h; //ADRC系统积分时间 uint16_t N0; //跟踪微分器解决速度超调h0=N*h float h0; float fh; //最速微分加速度跟踪量 /*****扩张状态观测器ESO*******///10 /******已系统输出y和输入u来跟踪估计系统状态和扰动*****/ float z1; float z2; float z3; //根据控制对象输入与输出,提取的扰动信息 float e; //系统状态偏差 float y; //y系统输出量 float fe; float fe1; float w0; //调试参数 float beta_01; float beta_02; float beta_03; /**********系统状态偏差反馈率*********///5 float e0;//状态偏差积分项 float e1;//状态误差 float e2;//状态量微分项 float u0;//非线性组合系统输出 float u;//带扰动补偿后的输出 float d;//SMDO滑模干扰观测器的干扰量输出 /*********第一种组合形式PD*********///10 float beta_0;//线性 float wc; //调试参数 float beta_1;//非线性组合参数 float beta_2;//u0=beta_1*e1+beta_2*e2+(beta_0*e0); /*********第二种组合形式*********/ float alpha1;//u0=beta_1*fal(e1,alpha1,zeta)+beta_2*fal(e2,alpha2,zeta) float alpha2;//0<alpha1<1<alpha2 float zeta;//线性段的区间长度 /*********第三种组合形式*********/ float h1;//u0=-fhan(e1,e2,r,h1); uint16_t N1;//跟踪微分器解决速度超调h0=N*h /*********第四种组合形式*********/ float c;//u0=-fhan(e1,c*e2*e2,r,h1); float b0;//扰动补偿 /*********强制类型转换*********/ // float Out; //转速输出,iq给定 } LADRC_Control, *p_LADRC_Control ; //初始化各个参数 #define LADRC_Control_DEFAULTS {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} // 初始化参数 extern LADRC_Control LADRC_spd ; //int16_t Sign_ADRC(float Input) //符号函数 //int16_t Fsg_ADRC(float x,float d) // 开关函数/比较函数 //float Fal_ADRC(float e,float alpha,float zeta) // 原点附近有连线性段的连续幂次函数 //float Constrain_Float(float amt, float low, float high) //归一化区间函数 void LADRC_Controller(p_LADRC_Control pV); //LADRC控制算法函数 void LADRC_Pare_init(void ); //LADRC控制参数初始化 #endif /* LADRC */ //=========================================================================== // No more. //===========================================================================
#include "Main_PMSM_QEncoder.h" LADRC_Control LADRC_spd = LADRC_Control_DEFAULTS; //符号函数 int16_t Sign_ADRC(float Input) { int16_t output=0; if(Input>1E-6) output=1; else if(Input<-1E-6) output=-1; else output=0; return output; } // 开关函数/比较函数 int16_t Fsg_ADRC(float x,float d) { int16_t output=0; output=(Sign_ADRC(x+d)- Sign_ADRC(x-d))/2; return output; } // 原点附近有连线性段的连续幂次函数 float Fal_ADRC(float e,float alpha,float zeta) { int16 s=0; float fal_output=0; s= (Sign_ADRC(e+zeta)-Sign_ADRC(e-zeta))/2; fal_output = e*s/(powf(zeta,1-alpha))+powf(abs(e),alpha)*Sign_ADRC(e)*(1-s); return fal_output; } float Constrain_Float(float amt, float low, float high) //归一化区间函数 { return ((amt)<(low)?(low):((amt)>(high)?(high):(amt))); } //constrain(amt,low,high)函数的工做过程是,若是值amt小于low,则返回low; //若是amt大于high,则返回high;不然,返回amt。该函数通常能够用于将值归一化到某个区间内 //除法运算函数 //float Division_function(float A, float B) //除法函数 // { // return ((amt)<(low)?(low):((amt)>(high)?(high):(amt))); // } // 此程序是线性自抗扰控制 //宏定义的问题,和宏定义同名的参数被使用,当作变量 void LADRC_Controller(p_LADRC_Control pV) { float d=0, a0=0, Y=0, a1=0, a2=0, A=0; float x1_delta=0; // float temp_e2=0; /* Step1:安排跟踪微分过程TD */ /***** 安排过分过程,输入为指望给定, 由TD跟踪微分器获得: 过渡指望信号x1,过渡指望微分信号x2 ******/ // 输入指望转速Ref-----wr x1_delta = pV->x1-pV->ref; //偏差量-----用x1-v(k)替代x1获得离散更新公式 pV->h0 = pV->N0*pV->h; //h0 = N0*h 用h0替代h,解决最速跟踪微分器速度超调问题 d = pV->r*pV->h0*pV->h0; //d=rh0^2; a0 = pV->h0*pV->x2; //a0=h0*x2 Y = x1_delta+a0; //y=x1-z+a0 a1=sqrt(d*(d+8*abs(Y))); // a1=sqrt(d*(d+8*ABS(y))]) a2=a0+Sign_ADRC(Y)*(a1-d)/2; // a2=a0+sign(y)*(a1-d)/2/单个的符号函数,极小数近似等于0 A = (a0+Y)*Fsg_ADRC(Y,d)+a2*(1-Fsg_ADRC(Y,d)); // a =(a0+y-a2)*sign(y,d)+a2 pV->fh = -pV->r*(A/d)*Fsg_ADRC(A,d)-pV->r*Sign_ADRC(A)*(1-Fsg_ADRC(A,d)); // fh =-r*[a/d-sign(a)]*sign(a,d)-r*sign(a) // h为ADRC系统积分时间 pV->x1 = pV->x1 + pV->h*pV->x2; //指望信号x1 pV->x2 = pV->x2 + pV->h*pV->fh; //指望微分信号x2 //LADRC_spd.fh LADRC_spd. /* Step2:ESO扩张状态观测器 */ /***** 扩张状态观测器,获得反馈信号的扩张状态: 一、状态信号z1; 二、状态速度信号z2; 三、状态加速度信号z3。 其中z一、z2用于做为状态反馈与TD微分跟踪器获得的x1,x2作差后, 通过非线性函数映射,乘以beta系数后, 组合获得未加入状态加速度估计扰动补偿的原始控制量u *********/ //y系统输出量,转速反馈值-----we;安排输出u;(两个输入三个输出) pV->e = pV->z1-pV->y; //e=z1-y 状态偏差 // pV->fe =Fal_ADRC(pV->e,0.5,pV->h); //避免高频颤振/*---http://www.docin.com/p-2071650216.html-----*/ // pV->fe1=Fal_ADRC(pV->e,0.25,pV->h); // /*************扩展状态量更新**********/ // pV->z1+=pV->z1+pV->h*(pV->z2-pV->beta_01*pV->e); // pV->z2+=pV->h*(pV->z3-pV->beta_02*pV->fe+ pV->b0*pV->u); //ESO估计状态加速度信号,进行扰动补偿,传统MEMS陀螺仪漂移较大,估计会产生漂移 // pV->z3+=pV->h*(-pV->beta_03*pV->fe1); //ESO估计状态加速度信号,进行扰动补偿,传统MEMS陀螺仪漂移较大,估计会产生漂移 pV->z1=pV->z1+pV->h*(pV->z2-pV->beta_01*pV->e); //beta_01取值的范围能够依据经验公式 pV->z2=pV->z2+pV->h*(pV->z3-pV->beta_02*pV->e+ pV->b0*(pV->u+pV->d)); //扰动补偿+SMDO pV->z3=pV->z3+pV->h*(-pV->beta_03*pV->e); //pV->z3没有用到 /* 线性扩张状态观测器*/ /* Step3:NLSEF */ /********状态偏差反馈率***/ // pV->e0+=pV->e1*pV->h;//状态积分项 // pV->e0=pV->e0+pV->e1*pV->h;//状态积分项 pV->e1=pV->x1-pV->z1; //状态误差项 LADRC_spd.x2 pV->e2=pV->x2-pV->z2; //状态微分项 LADRC_spd.z2 /* Step4:线性组合PD */ /* fhan_Input->u0=//fhan_Input->beta_0*fhan_Input->e0 +fhan_Input->beta_1*fhan_Input->e1 +fhan_Input->beta_2*fhan_Input->e2; */ // temp_e2 = Constrain_Float(pV->e2,-3000,3000); //3000 // pV->u0 = (pV->beta_1 * Fal_ADRC(pV->e1,pV->alpha1,pV->zeta)- pV->beta_2 * pV->z2-pV->z3)/(pV->b0); //SMDO+扰动补偿 pV->u0 = ((pV->beta_1 * pV->e1)- pV->beta_2 * pV->z2-pV->z3+pV->d)/(pV->b0); // pV->u0 = pV->beta_1 * Fal_ADRC(pV->e1,pV->alpha1,pV->zeta)- pV->beta_2 * Fal_ADRC(temp_e2,pV->alpha2,pV->zeta)-pV->z3; // pV->u0 = pV->beta_1 * Fal_ADRC(pV->e1,pV->alpha1,pV->zeta)+ pV->beta_2 * Fal_ADRC(temp_e2,pV->alpha2,pV->zeta); /* Step5:控制输出 */ /* control output*/ pV->u=Constrain_Float(pV->u0,0,14260633.6); ////带扰动补偿后的输出 // 限制输出-1500 // LADRC_spd.u0 } void LADRC_Pare_init(void ) { // 自抗扰控制器参数设置15个 /*Float----最大的数是2^(-32)到2^32-1------4294967295 */ LADRC_spd.r= 6000000; //TD跟踪微分器300000 LADRC_spd.h= 0.005; //h0=h*N0=0.01 LADRC_spd.N0= 2; // 带宽调参法/*https://blog.csdn.net/handsome_for_kill/article/details/88398467*/ LADRC_spd.w0 = 50; LADRC_spd.beta_01= 3*LADRC_spd.w0; //200 //150; //3*wo//100扩张状态观测器ESO,wo=50000 LADRC_spd.beta_02= 3*LADRC_spd.w0*LADRC_spd.w0; //133.3 //7500;//3*wo^2//1000 LADRC_spd.beta_03= LADRC_spd.w0*LADRC_spd.w0*LADRC_spd.w0; //125 //125000;//wo^3// // 系统特性,与被控对象有关 LADRC_spd.b0= 0.003727458; //0.003727458扰动补偿b0 0.001 LADRC_spd.beta_0= 0.002; //非线性组合 //线性控制器PD LADRC_spd.wc = 16; LADRC_spd.beta_1= LADRC_spd.wc*LADRC_spd.wc; //400 //wc^2 0.0005 LADRC_spd.beta_2= 2*LADRC_spd.wc; //40 // 2*wc 1.0 LADRC_spd.N1= 5; LADRC_spd.c= 5; // 原点附近有连线性段的连续幂次函数 LADRC_spd.alpha1= 0.8;//0.8 LADRC_spd.alpha2= 1.5;//1.5 LADRC_spd.zeta= 50; } //=========================================================================== // No more. //===========================================================================
当你在忙起来的时候,你就以为在实现与自我实现中寻找到那个平衡点——进步。但愿能够天天进步一点点,以前的博客(包括这篇)都是在总结与回顾以前所学习的内容与所得,后续将持续更新,感谢您的关注与点赞!!!