SVPWM驱动电机有杂音

[复制链接]
 楼主| trouvan 发表于 2020-1-19 23:31 | 显示全部楼层 |阅读模式
小弟最近在学习SVPWM,看了很多资料,想自己实现一个SVPWM。但实际尝试后发现,电机能转,但会有杂音。
使用STM32,SVPWM使用TIM8高级定时器,频率设置为25K。照理来说频率为25K应该不会有杂音了。



我的驱动原理为:
给定一个theta值(单位°/s),目标矢量的角度为theta,幅度为1
1ms给theta值增加一个小增量,同时计算此时该目标矢量的alpha、beta分量,实际上就是theta的cos 和sin
根据theta计算此时目标矢量落在1-6哪个扇区,取出该扇区相邻的两个非零矢量,假设落在第一扇区,那么取出矢量 U4 和U6。
通过这两个矢量U4 U6分别导通一定的时间t1t2,来合成目标矢量。

实际上计算出来的t1t2是百分比,用1-t1-t2,即可得到零矢量的导通时间,通过t1 t2 和零矢量的导通时间,来决定A、B、C三相
SVPWM的定时器比较值(CCR)。

这种方法我用simulink仿真过了,电机波形与simulink自带的SVPWM模块是一样的,但是实际驱动的时候,就会有杂音,不知道问题在何处。



 楼主| trouvan 发表于 2020-1-19 23:32 | 显示全部楼层
本帖最后由 trouvan 于 2020-1-19 23:35 编辑

主要代码:(因为一直改来改去,写得比较乱)
  1. #include "foc.h"
  2. #include "tim.h"
  3. #include "math.h"
  4. #include "arm_math.h"
  5. #include "adc.h"


  6. #define PAIRS   7   //Pole of Pairs
  7. #define PART_NUM   3072 // 多少细分
  8. #define MIN(a,b)    a<b?a:b

  9. uint16_t ADC_Values_Raw[4];
  10. uint16_t ADC_Values_Raw2[4];
  11. //#define PI  3.1415926f
  12. typedef struct{
  13.     uint8_t a;
  14.     uint8_t b;
  15.     uint8_t c;
  16.     float theta;
  17.     float x;
  18.     float y;
  19. }Uvect_Mos;

  20. typedef struct{
  21.     float ccra;
  22.     float ccrb;
  23.     float ccrc;
  24. }CCR_Duty;

  25. Uvect_Mos U0={0,0,0,0};
  26. Uvect_Mos U4={1,0,0,0};
  27. Uvect_Mos U6={1,1,0,PI/3};
  28. Uvect_Mos U2={0,1,0,PI/3*2};
  29. Uvect_Mos U3={0,1,1,PI};
  30. Uvect_Mos U1={0,0,1,PI/3*4};
  31. Uvect_Mos U5={1,0,1,PI/3*5};
  32. Uvect_Mos U7={1,1,1,0};

  33. Uvect_Mos *Uvects[6]={&U1,&U2,&U3,&U4,&U5,&U6};

  34. CCR_Duty CCR_Dutys={0};
  35. static float theta=0;
  36. float RPS=0.1;   // 转速

  37. void UVects_Init(){
  38.     for(int i=0;i<6;++i){
  39.         float v_theta=Uvects[i]->theta;
  40.         Uvects[i]->x=cosf(v_theta);
  41.         Uvects[i]->y=sinf(v_theta);
  42.     }
  43. }

  44. void Foc_Init(float rps){
  45.     // rps unit is r/s
  46.     int interupt_time=0;
  47.     int PSC=0;

  48.     //interupt_time=rps*PAIRS*PART_NUM;
  49.     //PSC=1281/interupt_time;    //84000000/65535/interrupt_time
  50.     //TIM7->ARR=84000000/(PSC+1)/interupt_time;
  51.     //TIM7->PSC=PSC;
  52.     interupt_time=rps*PAIRS*PART_NUM;
  53.     PSC=1281/interupt_time;
  54.     //TIM8->ARR=168000000/(PSC+1)/interupt_time/2;                   // TIM8的初始化写在别处了,ARR值为3360,重复计数器设为1,定时器频率168Mhz,因此算下来,ARR=3360的中断频率就是25K
  55.     //TIM8->PSC=PSC;
  56.     //TIM8->ARR=6200;
  57.     //TIM8->PSC=0;
  58.    

  59.     UVects_Init();
  60.     HAL_TIM_PWM_Start(&htim8,TIM_CHANNEL_1);
  61.     HAL_TIM_PWM_Start(&htim8,TIM_CHANNEL_2);
  62.     HAL_TIM_PWM_Start(&htim8,TIM_CHANNEL_3);

  63.     HAL_TIMEx_PWMN_Start(&htim8,TIM_CHANNEL_1);
  64.     HAL_TIMEx_PWMN_Start(&htim8,TIM_CHANNEL_2);
  65.     HAL_TIMEx_PWMN_Start(&htim8,TIM_CHANNEL_3);
  66.     //HAL_TIM_Base_Start_IT(&htim7);

  67.     //ADC
  68.     HAL_ADC_Start_DMA(&hadc1,(uint32_t *)ADC_Values_Raw,2);
  69.     HAL_ADC_Start_DMA(&hadc2,(uint32_t *)ADC_Values_Raw2,3);
  70.     HAL_TIM_Base_Start_IT(&htim8);
  71. }

  72. uint8_t get_area(uint32_t now_theta){
  73.     return now_theta/60+1;
  74. }

  75. void get_area_u(uint8_t area,Uvect_Mos *u1,Uvect_Mos *u2){
  76.     switch (area)
  77.     {
  78.     case 1:
  79.         *u1=U4;
  80.         *u2=U6;
  81.         break;
  82.     case 2:
  83.         *u1=U6;
  84.         *u2=U2;
  85.         break;
  86.     case 3:
  87.         *u1=U2;
  88.         *u2=U3;
  89.         break;
  90.     case 4:
  91.         *u1=U3;
  92.         *u2=U1;
  93.         break;
  94.     case 5:
  95.         *u1=U1;
  96.         *u2=U5;
  97.         break;
  98.     case 6:
  99.         *u1=U5;
  100.         *u2=U4;
  101.         break;
  102.     default:
  103.         break;
  104.     }
  105. }

  106. void get_t(float theta,float * t1,float *t2){
  107. /*
  108. /       u2y x               u2x y       \
  109. | ----------------- - ----------------- |
  110. | u1x u2y - u2x u1y   u1x u2y - u2x u1y |
  111. |                                       |
  112. |       u1x y               u1y x       |
  113. | ----------------- - ----------------- |
  114. \ u1x u2y - u2x u1y   u1x u2y - u2x u1y /
  115. */
  116.     float temp_t1,temp_t2;
  117.     float theta_f;  // 单位为rad
  118.     Uvect_Mos u1,u2;
  119.     float x,y;
  120.     get_area_u(get_area(theta),&u1,&u2);
  121.     //theta_f=(float)theta*2.0f*PI/360;
  122.     arm_sin_cos_f32(theta,&y,&x);
  123.     x*=0.86f;
  124.     y*=0.86f;   // sqrt(3)/2 没错
  125.     //x=0.86f*cosf(theta_f);
  126.     //y=0.86f*sinf(theta_f);
  127.     temp_t1=u2.y*x/(u1.x*u2.y-u2.x*u1.y)-(u2.x*y)/(u1.x*u2.y-u2.x*u1.y);
  128.     temp_t2=u1.x*y/(u1.x*u2.y-u2.x*u1.y)-(u1.y*x)/(u1.x*u2.y-u2.x*u1.y);

  129.     *t1=temp_t1;
  130.     *t2=temp_t2;

  131. }

  132. CCR_Duty get_ccr_duty(float t1,float t2,Uvect_Mos u1,Uvect_Mos u2){
  133.     float t0,t3;
  134.     CCR_Duty result;
  135.     t0=(1-t1-t2)/2;
  136.     t3=t0;

  137.     result.ccra=U7.a*t3+u1.a*t1+u2.a*t2;
  138.     result.ccrb=U7.b*t3+u1.b*t1+u2.b*t2;
  139.     result.ccrc=U7.c*t3+u1.c*t1+u2.c*t2;

  140.     return result;
  141. }

  142. void SVPWM_Step(CCR_Duty duty){  // 此函数调用频率为25KHZ
  143.     TIM8->CCR1=duty.ccrc*TIM8->ARR;
  144.     TIM8->CCR2=duty.ccrb*TIM8->ARR;
  145.     TIM8->CCR3=duty.ccra*TIM8->ARR;
  146. }



  147. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){

  148.     if(htim->Instance==TIM7){
  149.         //svpwm();
  150.     }
  151.     if(htim->Instance==TIM8){
  152.             //svpwm();
  153.         SVPWM_Step(CCR_Dutys);
  154.     }
  155. }

  156. #define dealtK PAIRS*360.0f/1000.0f
  157. void Theta_Handler(){   // 此函数1ms调用一次
  158.     Uvect_Mos u1,u2;
  159.     float t1,t2;
  160.     float dealt=RPS*dealtK;
  161.     theta+=dealt;
  162.     if(theta>360){
  163.         theta-=360;
  164.     }
  165.     uint8_t area=get_area((int)theta);
  166.     get_area_u(area,&u1,&u2);
  167.     get_t(theta,&t1,&t2);
  168.     CCR_Dutys=get_ccr_duty(t1,t2,u1,u2);
  169. }


niuz 发表于 2020-1-21 20:58 | 显示全部楼层
没加死区的原因吧
davidjiang1973 发表于 2020-1-24 10:02 | 显示全部楼层
电机的角度你是人为给的,相当于是开环运行。用电机转子位置的实际角度试试看。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

13

主题

61

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部

13

主题

61

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部