FOC控制库MCSDK5.4.4梳理(3)——电流环和MMITABLE生成方法

一、前言

  电流环是FOC控制算法中的最内环,是一个负反馈闭环调节系统,使电机以恒定电流去运转。主要流程是:电流采样->Clark变换->Park变换->反Park变换->SVPWM输出,之后再进行下一轮计算。FOC计算频率较高,是ADC采样频率,一般在10kHz到20kHz之间,整个计算过程没有用到浮点数,以提高计算效率

二、源代码解析

1、电流环控制流程

图1 电流环控制框图

  如图1所示,电流环控制流程是一个负反馈的调节过程,唯一外部变量是IRef_qd,是外层速度环的变量,是根据目标速度和当前速度的误差,经由速度PID得出的值,该值是电流环的目标电流值,用来控制电流环电流的大小
  电流环的工作流程是,先电流采样得到A和B两相的电流IaIb;经过Clark变换得到,这是将电流沿坐标轴分解后的分量;经过Park变换得到IqId,这是电流在电机转子直轴和交轴方向的分量;根据IRef_qd,通过电流环PID计算出UqUd,这是电压在电机转子直轴和交轴方向的分量;再通过SVPWM计算出电机ABC三相的占空比,给到电机,再进行下一轮计算

2、Clark变换

图2 Clark变换

  如图2所示,图中显示了α轴、β轴与ABC三相电流的关系,与代码相一致。将三相电流按照α轴、β轴向量分解:

  根据三相电流标量和等于零,消掉C相电流ic

  三相电压和电流矢量合成后,幅值都会变为原来的3/2,为了保证是等幅变换,需要将幅值乘以2/3,(推导过程见:https://blog.csdn.net/weixin_43900981/article/details/136289110),则:

  源代码注释如下:

//输入形参: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的平方和取值范围是02*32767*32767,将其等分为128个区间,则每一区间长度为2*32768*32768/128=16777216。假设MAX_MODULE29490,则等比例缩小的区间是[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,如此循环,直到23276732767,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;
}

三、结语

  电流环分了三章来讲的,涉及的理论内容不少,因为主要是解析代码,理论部分没有展开说,还需要大家对照相关资料去看。电流环解析到此结束,后续会再讲解速度环和位置反馈的部分

  • 18
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值