打印

SVPWM驱动电机有杂音

[复制链接]
1327|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
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 编辑

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


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

uint16_t ADC_Values_Raw[4];
uint16_t ADC_Values_Raw2[4];
//#define PI  3.1415926f
typedef struct{
    uint8_t a;
    uint8_t b;
    uint8_t c;
    float theta;
    float x;
    float y;
}Uvect_Mos;

typedef struct{
    float ccra;
    float ccrb;
    float ccrc;
}CCR_Duty;

Uvect_Mos U0={0,0,0,0};
Uvect_Mos U4={1,0,0,0};
Uvect_Mos U6={1,1,0,PI/3};
Uvect_Mos U2={0,1,0,PI/3*2};
Uvect_Mos U3={0,1,1,PI};
Uvect_Mos U1={0,0,1,PI/3*4};
Uvect_Mos U5={1,0,1,PI/3*5};
Uvect_Mos U7={1,1,1,0};

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

CCR_Duty CCR_Dutys={0};
static float theta=0;
float RPS=0.1;   // 转速

void UVects_Init(){
    for(int i=0;i<6;++i){
        float v_theta=Uvects[i]->theta;
        Uvects[i]->x=cosf(v_theta);
        Uvects[i]->y=sinf(v_theta);
    }
}

void Foc_Init(float rps){
    // rps unit is r/s
    int interupt_time=0;
    int PSC=0;

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

    UVects_Init();
    HAL_TIM_PWM_Start(&htim8,TIM_CHANNEL_1);
    HAL_TIM_PWM_Start(&htim8,TIM_CHANNEL_2);
    HAL_TIM_PWM_Start(&htim8,TIM_CHANNEL_3);

    HAL_TIMEx_PWMN_Start(&htim8,TIM_CHANNEL_1);
    HAL_TIMEx_PWMN_Start(&htim8,TIM_CHANNEL_2);
    HAL_TIMEx_PWMN_Start(&htim8,TIM_CHANNEL_3);
    //HAL_TIM_Base_Start_IT(&htim7);

    //ADC
    HAL_ADC_Start_DMA(&hadc1,(uint32_t *)ADC_Values_Raw,2);
    HAL_ADC_Start_DMA(&hadc2,(uint32_t *)ADC_Values_Raw2,3);
    HAL_TIM_Base_Start_IT(&htim8);
}

uint8_t get_area(uint32_t now_theta){
    return now_theta/60+1;
}

void get_area_u(uint8_t area,Uvect_Mos *u1,Uvect_Mos *u2){
    switch (area)
    {
    case 1:
        *u1=U4;
        *u2=U6;
        break;
    case 2:
        *u1=U6;
        *u2=U2;
        break;
    case 3:
        *u1=U2;
        *u2=U3;
        break;
    case 4:
        *u1=U3;
        *u2=U1;
        break;
    case 5:
        *u1=U1;
        *u2=U5;
        break;
    case 6:
        *u1=U5;
        *u2=U4;
        break;
    default:
        break;
    }
}

void get_t(float theta,float * t1,float *t2){
/*
/       u2y x               u2x y       \
| ----------------- - ----------------- |
| u1x u2y - u2x u1y   u1x u2y - u2x u1y |
|                                       |
|       u1x y               u1y x       |
| ----------------- - ----------------- |
\ u1x u2y - u2x u1y   u1x u2y - u2x u1y /
*/
    float temp_t1,temp_t2;
    float theta_f;  // 单位为rad
    Uvect_Mos u1,u2;
    float x,y;
    get_area_u(get_area(theta),&u1,&u2);
    //theta_f=(float)theta*2.0f*PI/360;
    arm_sin_cos_f32(theta,&y,&x);
    x*=0.86f;
    y*=0.86f;   // sqrt(3)/2 没错
    //x=0.86f*cosf(theta_f);
    //y=0.86f*sinf(theta_f);
    temp_t1=u2.y*x/(u1.x*u2.y-u2.x*u1.y)-(u2.x*y)/(u1.x*u2.y-u2.x*u1.y);
    temp_t2=u1.x*y/(u1.x*u2.y-u2.x*u1.y)-(u1.y*x)/(u1.x*u2.y-u2.x*u1.y);

    *t1=temp_t1;
    *t2=temp_t2;

}

CCR_Duty get_ccr_duty(float t1,float t2,Uvect_Mos u1,Uvect_Mos u2){
    float t0,t3;
    CCR_Duty result;
    t0=(1-t1-t2)/2;
    t3=t0;

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

    return result;
}

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



void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){

    if(htim->Instance==TIM7){
        //svpwm();
    }
    if(htim->Instance==TIM8){
            //svpwm();
        SVPWM_Step(CCR_Dutys);
    }
}

#define dealtK PAIRS*360.0f/1000.0f
void Theta_Handler(){   // 此函数1ms调用一次
    Uvect_Mos u1,u2;
    float t1,t2;
    float dealt=RPS*dealtK;
    theta+=dealt;
    if(theta>360){
        theta-=360;
    }
    uint8_t area=get_area((int)theta);
    get_area_u(area,&u1,&u2);
    get_t(theta,&t1,&t2);
    CCR_Dutys=get_ccr_duty(t1,t2,u1,u2);
}


使用特权

评论回复
板凳
niuz| | 2020-1-21 20:58 | 只看该作者
没加死区的原因吧

使用特权

评论回复
地板
davidjiang1973| | 2020-1-24 10:02 | 只看该作者
电机的角度你是人为给的,相当于是开环运行。用电机转子位置的实际角度试试看。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

13

主题

61

帖子

1

粉丝