User Tools

Site Tools

blog:2024-04-25_share_foc_mcsdk_3_mmitable



2024-04-25 Share: FOC控制庫MCSDK5.4.4梳理(3)-電流環和MMITABLE產生方法

Local Backup

一、前言

  • 電流環是FOC控制演算法中最內環,是負回饋閉環調節系統,使馬達以恆定的電流去運轉。主要流程是:電流採樣→Clark變換→Park變換→反Park變換→SVPWM輸出,之後再進行下一輪計算。 FOC計算頻率較高,是ADC取樣頻率,一般在10kHz到20kHz之間,整個計算過程沒有用到浮點數,以提高計算效率

二、原始碼解析

1、電流環控制流程


  • 圖1 電流環控制框圖
  • 如圖1所示,電流環控制流程是一個負回饋的調節過程,唯一外部變數是IRef_qd,是外層速度環的變量,是根據目標速度和當前速度的誤差,經由速度PID得出的值,該值是電流環的目標電流值,用來控制電流環電流的大小電流環的工作流程是,先電流取樣得到A和B兩相的電流Ia和Ib;經過Clark變換得到Iα和Iβ,這是將電流沿座標軸分解後的分量;經過Park變換得到Iq和Id,這是電流在馬達轉子直軸和交軸方向的分量;根據IRef_qd,透過電流環PID計算出Uq和Ud,這是電壓在馬達轉子直軸和交軸方向的分量;再透過SVPWM計算出電機ABC三相的佔空比,給到電機,再進行下一輪計算

2、Clark變換


  • 圖2 Clark變換
  • 如圖2所示,圖中顯示了α軸、β軸與ABC三相電流的關係,與程式碼相符。將三相電流依照α軸、β軸向量分解:
  • 根據三相電流標量和等於零,消掉C相電流ic:
  • 三相電壓和電流向量合成後,振幅都會變成原來的3/2,為了確保是等幅變換,需要將振幅乘以2/3,(推導過程請參考:FOC控制庫MCSDK5.4.4梳理(1)-SVPWM -知乎(zhihu.com)),則:
  • 原始碼註解如下:
  • //输入形参:AB相电流
    __weak alphabeta_t MCM_Clarke( ab_t Input  )
    {
      alphabeta_t Output;
      int32_t a_divSQRT3_tmp, b_divSQRT3_tmp ;
      int32_t wbeta_tmp;
      int16_t hbeta_tmp;
    
      /* Iα = Ia*/
      Output.alpha = Input.a;
      /* aTemp = Ia/sqrt(3) */
      /* divSQRT_3[1/sqrt(3)]的值是0x49E6, 计算方法32768/sqrt(3)=18918 */
      a_divSQRT3_tmp = divSQRT_3 * ( int32_t )Input.a;
      /* bTemp = Ib/sqrt(3) */
      b_divSQRT3_tmp = divSQRT_3 * ( int32_t )Input.b;
      /* Ib = -Ia/sqrt(3) - Ib/sqrt(3) - Ib/sqrt(3) */
      /* 右移15位的原因是divSQRT_3变量是Q15类型,所以要除以32768 */
      wbeta_tmp = ( -( a_divSQRT3_tmp ) - ( b_divSQRT3_tmp ) -
                     ( b_divSQRT3_tmp ) ) >> 15;
      /* 有效性判断 */
      ...
      return ( Output );
    }

2.Park變換


  • 圖3 Park變換
  • Park變換是將α和β分量沿著馬達的d軸和q軸分解。這裡解釋一下,d軸稱為直軸,是馬達永磁轉子的N極的方向,q軸為交軸,與d軸垂直,兩個方向控制馬達的正反轉。理想情況下,d軸電流為零,q軸控制著馬達轉動方向,馬達負載力矩越大,q軸電流越大。如圖3所示,θ為電角度,電角度的零點是β軸方向,我們將α和β軸分量沿著d和q軸方向分解:
  • 原始碼註解如下:
  • //输入形参:α和β电流分量;电角度
    __weak qd_t MCM_Park( alphabeta_t Input, int16_t Theta )
    {
      qd_t Output;
      int32_t d_tmp_1, d_tmp_2, q_tmp_1, q_tmp_2;
      Trig_Components Local_Vector_Components;
      int32_t wqd_tmp;
      int16_t hqd_tmp;
    
      /* 查表法计算正弦和余弦值,Q15格式 */
      Local_Vector_Components = MCM_Trig_Functions( Theta );
      /* q_tmp_1=Iα*cos(θ) */
      q_tmp_1 = Input.alpha * ( int32_t )Local_Vector_Components.hCos;
      /* q_tmp_2=Iβ*sin(θ) */
      q_tmp_2 = Input.beta * ( int32_t )Local_Vector_Components.hSin;
      /* Iq=Iα*cos(θ)-Iβ*sin(θ),Q15格式所以要除以32768*/
      wqd_tmp = ( q_tmp_1 - q_tmp_2 ) >> 15;
    
      /* 有效性判断 */
      ...
      Output.q = hqd_tmp;
      /* d轴电流计算 */
      ...
      return ( Output );
    }

3、電流環PID

  • 電流環PID將監控值(電流取樣)和控制量(輸出電壓)連結起來,形成一個閉迴路系統,即電流環。 FOC控制中僅用到了P(比例調節)和I(積分調節),函數輸入參數是d軸和q軸目前電流值,跟目標電流值的差,輸出量是d軸和q軸的電壓。
  • //输入形参:PID控制结构体;误差
    __weak int16_t PI_Controller( PID_Handle_t * pHandle, int32_t wProcessVarError )
    {
      int32_t wProportional_Term, wIntegral_Term, wOutput_32, wIntegral_sum_temp;
      int32_t wDischarge = 0;
      int16_t hUpperOutputLimit = pHandle->hUpperOutputLimit;
      int16_t hLowerOutputLimit = pHandle->hLowerOutputLimit;
    
      /* P调节:KpG*误差 */
      wProportional_Term = pHandle->hKpGain * wProcessVarError;
    
      /* I系数是否有效 */
      if ( pHandle->hKiGain == 0 )
      {
        pHandle->wIntegralTerm = 0;
      }
      else
      {
        /* I调节:累计误差+KiG*误差 */
        wIntegral_Term = pHandle->hKiGain * wProcessVarError;
        wIntegral_sum_temp = pHandle->wIntegralTerm + wIntegral_Term;
        ...
      }
      /* Kp=KpG/KpD Ki=KiG/KiD */
      /* 为了保证计算过程不涉及浮点数,Kp和Ki用分数表示,这里需要除掉各自的分母 */
      wOutput_32 = ( wProportional_Term >> pHandle->hKpDivisorPOW2 ) + ( pHandle->wIntegralTerm >> pHandle->hKiDivisorPOW2 );
      ...
      return ( ( int16_t )( wOutput_32 ) );
    }
  • 電流環PID係數整數沒有萬能的公式,電路板和馬達不同,PI係數數也會不同,具體情況需具體分析。空載或輕載情況下,電流環PI係數對馬達的運轉影響不大,過調或震盪也沒有大問題,不會損壞設備。如果要跑出馬達的極限參數,電流環和速度環係數還是要好好調整的,否則會因為過電流或震盪損壞設備。 MCSDK給出了一種計算電流環PI係數的方法:

  • 圖4 電流環PI計算方法
  • LS:線電感、WC:電流環頻寬、VBUS:母線電壓、Rshunt:取樣電阻、T:PWM週期、AOP:電流放大器增益。改為C代碼形式,計算結果僅供參考,具體情況具體分析
  • void PIDCal(void)
    {
        //母线电压 采样电阻 电流放大倍数 线电感 线电阻 截止频率rad/s pwm频率
        float Vbus = 48.0, Rshunt = 0.002, Aop = 27, Ls = 0.00016, Rs = 0.027, Wc = 4000, freq = 14000.0;
        float AB = Vbus * Rshunt * Aop / 3.3;
        float Kip = Ls * Wc / AB;
        float kii = Rs * Wc / AB / freq;
        printf("KIP : %f  KII : %f\n", Kip, kii);
    }

4.反Park變換


  • 圖5 反Park變換
  • 反Park變換是Park變換的逆變換,將d軸和q軸的電壓成分重新分解到α軸和β軸上:
  • //输入形参:q和d电压分量;电角度
    __weak alphabeta_t MCM_Rev_Park( qd_t Input, int16_t Theta )
    {
      int32_t alpha_tmp1, alpha_tmp2, beta_tmp1, beta_tmp2;
      Trig_Components Local_Vector_Components;
      alphabeta_t Output;
    
      Local_Vector_Components = MCM_Trig_Functions( Theta );
      /* Vα= Vd*Sin(θ) + Vq*Cos(θ) */
      alpha_tmp1 = Input.q * ( int32_t )Local_Vector_Components.hCos;
      alpha_tmp2 = Input.d * ( int32_t )Local_Vector_Components.hSin;
      Output.alpha = ( int16_t )( ( ( alpha_tmp1 ) + ( alpha_tmp2 ) ) >> 15 );
      /* Vβ= Vd*Cos(θ) - Vq*Sin(θ) */
      beta_tmp1 = Input.q * ( int32_t )Local_Vector_Components.hSin;
      beta_tmp2 = Input.d * ( int32_t )Local_Vector_Components.hCos;
      Output.beta = ( int16_t )( ( beta_tmp2 - beta_tmp1 ) >> 15 );
    
      return ( Output );
    }

5.Circle_Limitation及MMITABLE生成方法

  • 此函數是用來限制PWM的最大可調佔空比的,一般設定為90%就可以了,即32767*0.9=29490(MAX_MODULE=29490)。
  • //输入形参:q和d电压分量
    __weak qd_t Circle_Limitation( CircleLimitation_Handle_t * pHandle, qd_t Vqd )
    {
      uint16_t table_element;
      uint32_t uw_temp;
      int32_t  sw_temp;
      qd_t local_vqd = Vqd;
      //Vqd的平方和
      sw_temp = ( int32_t )( Vqd.q ) * Vqd.q +
                ( int32_t )( Vqd.d ) * Vqd.d;
      uw_temp = ( uint32_t ) sw_temp;
      /* Vqd的平方和 大于 设置的最大可调占空比时 */
      if ( uw_temp > ( uint32_t )( pHandle->MaxModule ) * pHandle->MaxModule )
      {
        /* 计算 Vqd的平方和 对应的数组下标 */
        uw_temp /= ( uint32_t )( 16777216 );
        uw_temp -= pHandle->Start_index;
    
        /* 获取缩小比例 */
        table_element = pHandle->Circle_limit_table[( uint8_t )uw_temp];
        /* 等比例缩小Vqd */
        sw_temp = Vqd.q * ( int32_t )table_element;
        local_vqd.q = ( int16_t )( sw_temp / 32768 );
        sw_temp = Vqd.d * ( int32_t )( table_element );
        local_vqd.d = ( int16_t )( sw_temp / 32768 );
      }
      return ( local_vqd );
    }
  • 下面說一下MMITABLE如何生成,Vqd的平方和取值範圍是0到2*32767*32767,將其等分為128個區間,則每一區間長度為2*32768*32768/128=16777216。假設MAX_MODULE為29490,則等比例縮小的區間是[29490*29490, 2*32767*32767]。 MAX_MODULE在第29490*29490/16777216=51區間,可以得出START_INDEX為51,第52區間的左值是29490*29490+16777216=886437316,則MAX_MODULE[0]=sqrt(29490*29490/886437316)*32767=32455,如此循環,直到2 32767 32767,C程式碼計算過程如下:
  • const int16_t MAX_MODULE = 29490;
    int MMITable(void)
    {
        int32_t START_INDEX = MAX_MODULE * MAX_MODULE / 16777216;
        printf("START_INDEX: %d\n", START_INDEX);
        int32_t END_INDEX = 2 * 32767 * 32767 / 16777216;
        printf("END_INDEX: %d\n", END_INDEX);
        int32_t ARR_SIZE = END_INDEX - START_INDEX + 1;
        printf("ARR_SIZE: %d\n", ARR_SIZE);
        // int32_t ONE_PART = ((2 * 32767 * 32767) - (MAX_MODULE * MAX_MODULE)) / ARR_SIZE;
        int32_t ONE_PART = 16777216;
        printf("ONE_PART: %d\n", ONE_PART);
    
        double start = MAX_MODULE * MAX_MODULE;
        double temp = 0.0;
        int32_t result = 0;
        for(int32_t i = 1;i <= ARR_SIZE;i++)
        {
            temp = start / (start + i * ONE_PART);
            temp = sqrt(temp);
            result = temp * 32767;
            printf("%d,", result);
            if(i % 10 == 0)
                printf("\\\n");
        }
        printf("\n");
        return 0;
    }

三、結語

  • 電流環分了三章來講的,牽涉的理論內容不少,因為主要是解析程式碼,理論部分沒有展開說,還需要大家對照相關資料去看。電流環解析到此結束,後續再講解速度環和位置回授的部分

TAGS

  • 36 person(s) visited this page until now.

Permalink blog/2024-04-25_share_foc_mcsdk_3_mmitable.txt · Last modified: 2024/04/26 15:06 by jethro

oeffentlich