本期学习的主要内容结合前两期FOC的控制原理和MATLAB建模仿真的内容,对有传感器的正弦波控制程序进行一个梳理,承上启下,从而达到更好的学习效果。
针对于FOC方式控制的PMSM,主要有三种相电流采集方式,其名称及特点分别为:
①三电阻法:最基本的、可靠方式;
②单电阻法:一种低成本方式;
③电流传感器法:比较高成本的方式。
而在所给的有传感器的正弦波控制程序中,所选择的的电流采样方式为三个电阻电流取样,参数为THREE_SHUNT。在头文件STM32F10x_MCconf.h中,也给出了另外俩种电流采样方式的参数——SINGLE_SHUNT、ICS_SENSORS,并且在程序中,也给出了相关程序,具体程序如下所示,其中,子函数SVPWM_3ShuntInit()是设置三电阻法的电流取样和PWM周期,而针对于另两种方式的初始化函数SVPWM_IcsInit()和SVPWM_1ShuntInit(),也是对相关参数的初始化,在之后的学习中,可对这两种方式,进行试验学习。
#ifdef THREE_SHUNT //三个电阻电流取样
SVPWM_3ShuntInit(); //设置电流取样,PWM周期
#elif defined ICS_SENSORS
SVPWM_IcsInit();
#elif defined SINGLE_SHUNT
SVPWM_1ShuntInit();
#endif
当定时器、PID等初始化结束之后,程序正式启动(即上电完成),需进行按键扫描及显示屏显示程序,程序段分别如下所示。从中,可以看出,按键扫描频率为8ms一次,具有消抖功能,且各个按键都具有各自的作用。
void KeyProc()
{
U8 i;
if(fgKeyDeal == 0)//8ms 检测一次
{
return;
}
fgKeyDeal=0;
if(ucKeyPressTime != 0)//长按的时间定义
{
ucKeyPressTime--;
}
fgKeyDeal= 0;
switch(ucKeyDat) //判断那个键按下
{
case 0:
i = 0;
break;
case SetKey:
i = SetKey;
break;
case FunKey:
i = FunKey;
break;
case LeftKey:
i = LeftKey;
break;
case RightKey:
i = RightKey;
break;
case UpKey:
i = UpKey;
break;
case DownKey:
i = DownKey;
break;
default:
i = OtherKey;
break;
}
if(i == ucPreKey)//判断是否跟上个键一样
{
if(ucKeyDebouce != 0)//去抖动,时间6*8
{
ucKeyDebouce--;
return;
}
if(fgBusy)
{
if(i == NoKey)
{
fgBusy = 0; // 此处处理释放有效键
ucKeyNew = 0;
ucKeyOld = 0;
}
}
else
{
if((i != NoKey) && (i != OtherKey))
{
fgBusy = 1;
ucKeyNew = i;
ucKeyOld = i;
}
}
}
else
{
ucPreKey = i;
ucKeyDebouce = KeyDebouce2; // 72ms
}
if(ucKeyNew != 0)
{
if(ucKeyOld != 0)
{
ucKeyOld = 0;
switch(ucKeyNew)
{
case SetKey:
ProcSetKey(); //不同的按键不同的处理程序//返回按键
break;
case FunKey:
ProcFunKey();
break;
case LeftKey:
ProcLeftKey(); //下键处理程序
break;
case RightKey:
ProcRightKey(); //右键处理程序
break;
case UpKey:
ProcUpKey(); //确认键处理程序
break;
case DownKey:
ProcDownKey(); //左键处理程序
break;
default:
break;
}
}
else
{
}
}
}
在主函数中,当电机的启动参数和PID参数配置正确之后,电机正常启动,随后进行电流采样,并对其采样过程进行空间矢量调制,以电流传感器法为例,调制函数为SVPWM_IcsCalcDutyCycles (),具体代码如下所示,其基本思路是利用Park逆变换和Clark逆变换,计算与输入值相对应的占空比值。同理,对于另两种电流采样方式来说,都具备这个作用,而针对于三电阻法的空间矢量控制而言,其还具有为下一个周期配置AD转换器和TIM0的作用。
void SVPWM_IcsCalcDutyCycles (Volt_Components
Stat_Volt_Input)
{
u8 bSector;
s32 wX,wY, wZ, wUAlpha, wUBeta;
u16 hTimePhA=0, hTimePhB=0, hTimePhC=0;
wUAlpha =Stat_Volt_Input.qV_Component1 * T_SQRT3 ;//park逆变换,?
wUBeta =-(Stat_Volt_Input.qV_Component2 * T);
wX =wUBeta;
wY =(wUBeta + wUAlpha)/2;//clark逆变换
wZ =(wUBeta - wUAlpha)/2;
// Sector calculation from wX, wY, wZ
if (wY<0)
{
if(wZ<0)
{
bSector = SECTOR_5;
}
else // wZ >= 0
if(wX<=0)
{
bSector = SECTOR_4;
}
else // wX > 0
{
bSector = SECTOR_3;
}
}
else //wY > 0
{
if(wZ>=0)
{
bSector = SECTOR_2;
}
else //wZ < 0
if(wX<=0)
{
bSector = SECTOR_6;
}
else // wX > 0
{
bSector = SECTOR_1;
}
}
switch(bSector)
{
case SECTOR_1: //时间区间是0-4-6-7-7-6-4-0
case SECTOR_4: //时间区间是0-1-3-7-7-3-1-0
hTimePhA = (T/8) + ((((T + wX) - wZ)/2)/131072);
hTimePhB = hTimePhA + wZ/131072;
hTimePhC = hTimePhB - wX/131072;
break;
case SECTOR_2:
case SECTOR_5:
hTimePhA = (T/8) + ((((T + wY) - wZ)/2)/131072);
hTimePhB = hTimePhA + wZ/131072;
hTimePhC = hTimePhA - wY/131072;
break;
case SECTOR_3:
case SECTOR_6:
hTimePhA = (T/8) + ((((T - wX) + wY)/2)/131072);
hTimePhC = hTimePhA - wY/131072;
hTimePhB = hTimePhC + wX/131072;
break;
default:
break;
}
CR1 = hTimePhA;
TIM1->CCR2 = hTimePhB;
TIM1->CCR3 = hTimePhC;
}
为了实现FOC的矢量控制,需要对PMSM的转矩和电流进行调节,从而实现FOC矢量算法。详细代码如下所示,其基本思路是根据电流采样的Ia、Ib,通过矢量对称计算出Ic,并根据Clark和Park变换,计算出Id和Iq,,然后根据参考值 Iqs 和 Ids 来计算 e,并通过PID控制,最后使得电流环和转矩环达到平衡。
void FOC_Model(void)
{
#ifdef FEED_FORWARD_CURRENT_REGULATION
Volt_Components Stat_Volt_q_d_4;
s32 wtemp;
#endif
#if defined HALL_SENSORS
//Integrate Speed for rotor angle update
HALL_IncElectricalAngle();
#endif
Stat_Curr_a_b = GET_PHASE_CURRENTS();//取得当前电流ia,ib
Stat_Curr_alfa_beta = Clarke(Stat_Curr_a_b);//clarke 变换成i_alfa,i_beta
Stat_Curr_q_d = Park(Stat_Curr_alfa_beta,GET_ELECTRICAL_ANGLE);
#ifdef FEED_FORWARD_CURRENT_REGULATION
/*loads the Torque Regulator output reference voltage Vqs*/
Stat_Volt_q_d_4.qV_Component1 = PID_Regulator(Stat_Curr_q_d_ref_ref.qI_Component1,Stat_Curr_q_d.qI_Component1,&PID_Torque_InitStructure);
/*loads the Flux Regulator output reference voltage Vds*/
Stat_Volt_q_d_4.qV_Component2 = PID_Regulator(Stat_Curr_q_d_ref_ref.qI_Component2,Stat_Curr_q_d.qI_Component2,&PID_Flux_InitStructure);
wtemp = (s32)(Stat_Volt_q_d_4.qV_Component1 + Stat_Volt_q_d_3.qV_Component1);
SATURATION_TO_S16(wtemp);
at_Volt_q_d.qV_Component1 = (s16)wtemp;
wtemp = (s32)(Stat_Volt_q_d_4.qV_Component2 + Stat_Volt_q_d_3.qV_Component2);
TURATION_TO_S16(wtemp);
Stat_Volt_q_d.qV_Component2 = (s16)wtemp;
#else
/*loads the Torque Regulator output reference voltage Vqs*/
Stat_Volt_q_d.qV_Component1 =
PID_Regulator(Stat_Curr_q_d_ref_ref.qI_Component1,
Stat_Curr_q_d.qI_Component1, &PID_Torque_InitStructure);
/*loads the Flux Regulator output reference voltage Vds*/
Stat_Volt_q_d.qV_Component2 = PID_Regulator(Stat_Curr_q_d_ref_ref.qI_Component2,
Stat_Curr_q_d.qI_Component2, &PID_Flux_InitStructure);
#endif
//circle limitation
RevPark_Circle_Limitation();//限制Stat_Volt_q_d 的值
/*Performs the Reverse Park transformation, i.e transforms stator voltages Vqs and Vds into Valpha and Vbeta on a stationary reference frame*/
Stat_Volt_alfa_beta = Rev_Park(Stat_Volt_q_d);
/*Valpha and Vbeta finally drive the power stage*/
CALC_SVPWM(Stat_Volt_alfa_beta);
#ifdef FEED_FORWARD_CURRENT_REGULATION
Stat_Volt_q_d_2.qV_Component1 = (s16)((Stat_Volt_q_d_2.qV_Component1*(VOLTAGE_SAMPLING_BUFFER-1)+Stat_Volt_q_d_4.qV_Component1)/LTAGE_SAMPLING_BUFFER);
Stat_Volt_q_d_2.qV_Component2 = (s16)((Stat_Volt_q_d_2.qV_Component2*(VOLTAGE_SAMPLING_BUFFER-1)+Stat_Volt_q_d_4.qV_Component2)/VOLTAGE_SAMPLING_BUFFER);
#endif
#ifdef FLUX_WEAKENING
Stat_Volt_q_d_1.qV_Component1 = (s16)((Stat_Volt_q_d_1.qV_Component1*(VOLTAGE_SAMPLING_BUFFER-1)+Stat_Volt_q_d.qV_Component1)/OLTAGE_SAMPLING_BUFFER);
Stat_Volt_q_d_1.qV_Component2 = (s16)((Stat_Volt_q_d_1.qV_Component2*VOLTAGE_SAMPLING_BUFFER-1)+tat_Volt_q_d.qV_Component2)/OLTAGE_SAMPLING_BUFFER);
#endif
}
本期的学习主要是在原理和仿真的学习之后,对有传感器的正弦波控制的程序进行进一步的学习理解,总的来说,对有感正弦波部分有了更深的理解。之后的学习将是从有感向无感的过渡。