Link

#

FOC算法的简要介绍 v2.0.2

Field oriented control (FOC) 算法的主要任务是基于用户定义的电压 uq,通过连续读取电机转子位置 a,计算出适当的相电压ua,ubuc

FOC算法在电机转子中产生磁场的相位电压,该磁场正好在转子的永磁体的磁场后面90度,创造了一个推动效应。这是一个很好的动画表示,当运行简化版的FOC即六步调制时,电机内部发生了什么。

via Gfycat

另一种理解为什么我们需要在转子和定子磁场之间形成90度角的方法是记住导线穿过磁场时产生的电场的方程:

F = B*I*L*sin(alpha)

其中B 是磁场的强度, L是导电流的大小, alpha是磁场B和电流, I之间的角度。从这个方程中我们可以看到,为了获得最大的力 F = B*I*L ,我们需要保持alpha角等于90度或 PI/2弧度。

如何计算uaubuc 的恰当电压值

由于Simple FOC library 的目的是关于FOC算法的知识以及支持各种应用,两个最标准的FOC调制版本在这个库中实现。

  • 正弦PWM: SinePWM
  • 空间矢量PWM: SpaceVectorPWM

可以通过设置 motor.foc_modulation 的变量值进行配置:

motor.foc_modulation = FOCModulationType::SinePWM; // default
// or
motor.foc_modulation = FOCModulationType::SpaceVectorPWM;

正弦调制SinePWM

正弦调制法是基于两个变换方程。

逆派克变换法:


逆克拉克变换法:

以下是在中实现正弦PWM的代码:

// 使用FOC将Uq设置到电机的最佳角度
void BLDCMotor::setPhaseVoltage(float Uq, float angle_el) {
    // 正弦PWM调制 
    // 逆派克+克拉克变换

    // 角度在0和360°之间的归一化
    // 仅当使用_sin和_cos近似函数时才需要
    angle_el = normalizeAngle(angle_el + zero_electric_angle);
    // 逆派克变换
    Ualpha =  -_sin(angle_el) * Uq;  // -sin(angle) * Uq;
    Ubeta =  _cos(angle_el) * Uq;    //  cos(angle) * Uq;

    // 你克拉克变换
    Ua = Ualpha + voltage_power_supply/2;
    Ub = -0.5 * Ualpha  + _SQRT3_2 * Ubeta + voltage_power_supply/2;
    Uc = -0.5 * Ualpha - _SQRT3_2 * Ubeta + voltage_power_supply/2;

    // 给硬件设定电压
    setPwm(Ua, Ub, Uc);
}

空间矢量调制 SpaceVectorPWM

空间矢量调制基于两个步骤的计算:

在第一步,我们发现扇区s转子目前在。360度的角被分成6等份的60度。这个计算很简单。然后我们计算时间T0, T1T2T1T2告诉我们第一阶段和第二阶段应该开多久,T0告诉我们电机上0电压应该开多久。


第二步是将T0,1,2值投影到适当的占空比Ta,b,c,这些占空比直接取决于电机当前所在的扇区。

SectorTaTbTc
1T1 + T2 + T0/2T2 + T0/2T0/2
2T1 + T0/2T1 + T2 + T0/2T0/2
3T0/2T1 + T2 + T0/2T2 + T0/2
4T0/2T1+ T0/2T1 + T2 + T0/2
5T2 + T0/2T0/2T1 + T2 + T0/2
6T1 + T2 + T0/2T0/2T1 + T0/2

下面是一个例子使用SVM表生成pwm信号的参数: s = 2, T1 = 1/8 = 0.125, T2 = 1/8 = 0.125 and T0 = 1/2 = 0.5

这里是空间矢量PWM实现的代码在 SimpleFOClibrary :

// 使用FOC将Uq设置到电机的最佳角度
void BLDCMotor::setPhaseVoltage(float Uq, float angle_el) {
    // 解释SpaceVectorModulation (SVPWM)算法的视频如下
    // https://www.youtube.com/watch?v=QMSWUMEAejg

    // 如果负电压的变化与相相反
    // 角度 +180°
    if(Uq < 0) angle_el += _PI;
    Uq = abs(Uq);

    // 角度归一化,在0和360°之间
    // 仅当使用_sin和_cos近似函数时才需要
    angle_el = normalizeAngle(angle_el + zero_electric_angle + _PI_2);

    // 找到我们目前所在的象限
    int sector = floor(angle_el / _PI_3) + 1;
    // 计算占空比
    float T1 = _SQRT3*_sin(sector*_PI_3 - angle_el) * Uq/voltage_power_supply;
    float T2 = _SQRT3*_sin(angle_el - (sector-1.0)*_PI_3) * Uq/voltage_power_supply;
    // 两个版本 
    // 以电压电源为中心/2
      float T0 = 1 - T1 - T2;
    // 低电源电压,拉到0
    //float T0 = 0;

    // 计算占空比(时间)
    float Ta,Tb,Tc; 
    switch(sector){
    case 1:
        Ta = T1 + T2 + T0/2;
        Tb = T2 + T0/2;
        Tc = T0/2;
        break;
    case 2:
        Ta = T1 +  T0/2;
        Tb = T1 + T2 + T0/2;
        Tc = T0/2;
        break;
    case 3:
        Ta = T0/2;
        Tb = T1 + T2 + T0/2;
        Tc = T2 + T0/2;
        break;
    case 4:
        Ta = T0/2;
        Tb = T1+ T0/2;
        Tc = T1 + T2 + T0/2;
        break;
    case 5:
        Ta = T2 + T0/2;
        Tb = T0/2;
        Tc = T1 + T2 + T0/2;
        break;
    case 6:
        Ta = T1 + T2 + T0/2;
        Tb = T0/2;
        Tc = T1 + T0/2;
        break;
    default:
         // 可能的错误状态
          Ta = 0;
          Tb = 0;
          Tc = 0;
      }

      // 计算相电压和中心
      Ua = Ta*voltage_power_supply;
      Ub = Tb*voltage_power_supply;
      Uc = Tc*voltage_power_supply;
      break;
  }
  
  // 设置硬件中的电压
  setPwm(Ua, Ub, Uc);
}

我们应如何选择?

这是由 Uq = 0.5V的正弦和空间矢量调制产生的波形图像:

SinusoidalSpace Vector

这两种算法之间有几个关键的区别。但就SimpleFOClibrary而言,你需要知道的就是空间矢量算法更好地使用了电源的最大电压范围。在上面的表格中,你可以看到,对于Uq = 0.5V,正弦调制产生的正弦波的幅度正好等于1,空间矢量调制还不是平静的。由空间矢量产生的“双正弦波”的幅值为 2/sqrt(3) = 1.15 ,这意味着在使用相同的电源时,它可以向电机多输出15%的功率。

这意味着,当使用SinePWM时,你的供电电压 Vpower_supply可以设置最大为 Uq = 0.5 Vpower_supply 。如果使用 SpaceVectorPWM,你将能够设置Uq = 0.58 Vpower_supply

你应该通过改变电机参数motor.voltage_power_supply的值来指定电源电压Vpower_supply。默认值为 12V。如果你需要设置你的Vpower_supply为其他值,在这里更改它,FOC算法将据此调整适当的Uq (motor.voltage_q)值。

// 电源电压
motor.voltage_power_supply = 12;

如果我不指定这个参数呢?

如果你没有指定motor.voltage_power_supply算法仍然有效,但你motor.voltage_q的值将不再等于实际输出电压。

当我超过最大值Uq时会发生什么?

如果你试着把电压 Uq高于Uq = 0.5 Vpower_supply SinePWMUq = 0.58 Vpower_supplySpaceVectorPWM,它仍然会工作,但 Ua,b,c信号会饱和。

这里有一些 SinePWM的不同Uq值的图像。

Uq = 0.5 Vpower_supply Uq = 0.6 Vpower_supply Uq = Vpower_supply

基本上你可以在图像上看到的是Ua,b,c是饱和的,在你超过最大值后,你实际上不再设置正弦波到你的电机。 电机的功率仍在增加,但不再是直线或平滑的。

经验法则

在现实中,电机可以看到的差异一直到Uq ~ 0.7 Vpower_supply 。在此值之后,Ua,b,c过于饱和,Uq的进一步增加不会导致电机功率的增加。 但是每一个电机都有点不同,你可以很容易地根据经验检查这些值。将电机置于电压控制中,查看电压*Uq*后,电机功率将不再有改善(它将停止加速)。

进一步阅读

有关初始化过程、实时执行和实现细节的更多信息,请访问FOC implementation docs.