FOC SVPMM算法C语言实现

记录自己手写FOC算法流程之SVPWM实现。

SVPWM的原理就不过多赘述,SVPWM模块的输入是Uα和Uβ,输出的三相占空比,这里直接上代码:

结构体及宏定义如下

#define PI		(3.141526535f)        //Pi的数学的定义
#define DIV_1_2	(0.5f)                //1除2
#define Sqrt_3_div_2	(0.86602f)    //根号3除2
#define Vdc	(5.0f)                    //假设的VBus,这个根据自己的代码修改
#define Ts	(2400 * 2)	              //周期,PWM计数器        
#define SVPWM_K (1.732f * Ts / Vdc)   //这个是SVPWM的算法公式

//DQ轴坐标系结构体
struct DQ_Aix
{
		float V_d;	    //d-q坐标系,d轴电压分量
		float V_q;	    //d-q坐标系,q轴电压分量
		float theta;	//转子电气角度
};

//α-β轴坐标系结构体
struct AlphaBeta_Aix
{
		float V_Alpha;	    //α-β坐标系,α轴电压分量
		float V_Beta;		//α-β坐标系,β轴电压分量
};

struct SVPWM_Control
{
		uint8_t sector;	        //扇区
		float X;				//SVPWM算法中间变量
		float Y;				//SVPWM算法中间变量
		float Z;				//SVPWM算法中间变量
		float T_First;	        //SVPWM算法中间变量
		float T_Second;	        //SVPWM算法中间变量
		float T0;		 		//SVPWM算法中间变量
		float Ta;				//SVPWM算法中间变量
		float Tb;				//SVPWM算法中间变量
		float Tc;				//SVPWM算法中间变量
};

//三个占空比控制结构体
struct SVPWM_Time
{	
		float Ta;			//A相占空比PWM寄存器的值
		float Tb;			//B相占空比PWM寄存器的值
		float Tc;			//C相占空比PWM寄存器的值
};

1、Uα和Uβ获取,使用逆帕克变换

//逆克拉克变换
void AntiParkTransfer(struct DQ_Aix dq ,struct AlphaBeta_Aix* ptr)
{
		ptr->V_Alpha = dq.V_d * cosf(dq.theta) - dq.V_q * sinf(dq.theta);
		ptr->V_Beta = dq.V_d * sinf(dq.theta) + dq.V_q * cosf(dq.theta);
}

//这里我偷懒用的是C语言的math库,实际使用可以根据自己的情况使用查表法后者是优化后的正余弦算法

2、根据Uα和Uβ得到当前的扇区

//当前扇区计算
void CalculateSector(struct AlphaBeta_Aix ab, struct SVPWM_Control* ptr)
{
		int8_t A = 0;
		int8_t B = 0;
		int8_t C = 0;
		int8_t N = 0;
		
		float VA = ab.V_Beta;
		float VB = ab.V_Alpha * Sqrt_3_div_2 - DIV_1_2 * ab.V_Beta;
		float VC = 0 - ab.V_Alpha * Sqrt_3_div_2 - DIV_1_2 * ab.V_Beta;
	
		ptr->X = SVPWM_K * ab.V_Beta;
		ptr->Y = SVPWM_K * (ab.V_Alpha * Sqrt_3_div_2 + DIV_1_2 * ab.V_Beta);
		ptr->Z = SVPWM_K * (0 - ab.V_Alpha * Sqrt_3_div_2 + DIV_1_2 * ab.V_Beta);
	
		if(VA > 0)
		{
				A = 1;
		}
		else
		{
				A = 0;
		}
		
		if(VB > 0)
		{
				B = 1;
		}
		else
		{
				B = 0;
		}
		
		if(VC > 0)
		{
				C = 1;
		}
		else
		{
				C = 0;
		}
		
		N = 4*C + 2*B + A;
		
		switch(N)
		{
			case 3:
				ptr->sector = 1;
				break;
			case 1:
				ptr->sector = 2;
				break;
			case 5:
				ptr->sector = 3;
				break;
			case 4:
				ptr->sector = 4;
				break;
			case 6:
				ptr->sector = 5;
				break;
			case 2:
				ptr->sector = 6;
				break;
		}	
}

3、计算占空比

//计算出占空比
void CalulateDutyCycle(struct SVPWM_Control* ctrl,struct SVPWM_Time* ptr)
{
		switch(ctrl->sector)
		{
			case 2:
				ctrl->T_First = ctrl->Z;
				ctrl->T_Second = ctrl->Y;
				break;
			case 6:
				ctrl->T_First = ctrl->Y;
				ctrl->T_Second = 0 - ctrl->X;
				break;
			case 1:
				ctrl->T_First = 0 - ctrl->Z;
				ctrl->T_Second = ctrl->X;
				break;
			case 4:
				ctrl->T_First = 0 - ctrl->X;
				ctrl->T_Second = ctrl->Z;
				break;
			case 3:
				ctrl->T_First = ctrl->X;
				ctrl->T_Second = 0 - ctrl->Y;
				break;
			case 5:
				ctrl->T_First = 0 - ctrl->Y;
				ctrl->T_Second = 0 - ctrl->Z;
				break;
		}
		
		if((ctrl->T_First + ctrl->T_Second) > Ts)
		{
				ctrl->T_First  = ctrl->T_First  * Ts / (ctrl->T_First + ctrl->T_Second);
				ctrl->T_Second = ctrl->T_Second  * Ts / (ctrl->T_First + ctrl->T_Second);
		}			
		
		ctrl->T0 = (Ts - ctrl->T_First - ctrl->T_Second) / 2;
		
		ctrl->Ta = ctrl->T0 / 2;
		ctrl->Tb = ctrl->Ta + ctrl->T_First / 2;
		ctrl->Tc = ctrl->Tb + ctrl->T_Second / 2;
		
		switch(ctrl->sector)
		{
			case 2:
				ptr->Ta = ctrl->Tb;
				ptr->Tb = ctrl->Ta;
				ptr->Tc = ctrl->Tc;
				break;
			case 6:
				ptr->Ta = ctrl->Ta;
				ptr->Tb = ctrl->Tc;
				ptr->Tc = ctrl->Tb;
				break;
			case 1:
				ptr->Ta = ctrl->Ta;
				ptr->Tb = ctrl->Tb;
				ptr->Tc = ctrl->Tc;
				break;
			case 4:
				ptr->Ta = ctrl->Tc;
				ptr->Tb = ctrl->Tb;
				ptr->Tc = ctrl->Ta;
				break;
			case 3:
				ptr->Ta = ctrl->Tc;
				ptr->Tb = ctrl->Ta;
				ptr->Tc = ctrl->Tb;
				break;
			case 5:
				ptr->Ta = ctrl->Tb;
				ptr->Tb = ctrl->Tc;
				ptr->Tc = ctrl->Ta;
				break;
		}
		
}

4、测试代码

static void TestSVPMW(void)
{
	
		AntiParkTransfer(dq_Aix ,&ab_Aix);
		CalculateSector(ab_Aix ,&Svpwm_Ctrl);
		CalulateDutyCycle(&Svpwm_Ctrl ,&PhaseTime);
	
		//模拟角度变化
		if(Tick >= 1.00f)
		{
				Tick = 0.001f;
		}
		else
		{
				Tick += 0.001f;
		}
		
		dq_Aix.theta = 2 * PI * Tick;
	
}

5、测试结果

逆帕克变换测试,上面红色的是角度,下面的是Uα和Uβ

SVPWM波形测试

最上面的是角度,中间的是扇区计算,最下面的是三相占空比,可以看出来是标准的马鞍波

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值