FOC算法(SVPWM算法)

FOC 即磁场定向控制(Field Oriented Control),是一种用于电机控制的先进技术。它通过坐标变换,将电机的定子电流分解为励磁电流和转矩电流,实现对电机磁场和转矩的解耦控制。FOC 能使电机在不同工况下都保持良好的性能,具有高精度、高动态响应、高效率等优点,可提高电机的运行稳定性和可靠性,降低能耗。广泛应用于工业自动化、电动汽车、机器人等领域,是现代电机控制的核心技术之一。

目录

FOC的主要流程:

SVPWM

1.三相逆变电路:

2.计算扇区

3.计算作用时间

4.七段式时间分配

分配方法解释:

5.设置互补输出和死区时间

 1. 选择合适的定时器

 2. 配置定时器的基本参数

3. 配置 PWM 输出通道

4. 启用互补输出

5. 设置死区时间

6. 使能刹车功能(可选)

克拉克变换:

帕克变换:

帕克逆变换:

SVPWM 的优势

FOC相关代码:(SVPWM,帕克变换,帕克逆变换,克拉克变换)


FOC的主要流程:

1,对电机三相电流进行采样,获得Ia,Ib,Ic。

2,进行克拉克变换和帕克变换(需要电机电角度,在有感FOC中可由编码器获取),克拉克变换就是将三相静止坐标系(a−b−c 坐标系)下的物理量转换到两相静止坐标系(α−β 坐标系),帕克变换就是将静止的坐标系变换成旋转的(跟随采集到的电流的变化旋转,使正弦电流变成直线)

3,帕克变换之后得到Iq和Id,(Id我们希望它等于0),将这两个值放到PI控制器得到Uq和Ud(电流环PI控制,当然我们也可以加入速度环和角度环)

4,再进行帕克逆变换(进行PI控制后的量我们再让它旋转起来,因为给电机的是正弦型的电压),将结果放入SVPWM算法中(SVPWM算法输入U_alfa,U_beta,,输出的就是控制三相逆变电路的Ia(A相),Ib(B相),Ic(C相))

5,SVPWM控制逆变器驱动电机

注:由于作者时间不足,写的比较匆忙,排版和内容的整理不到位,敬请谅解!建议看完大体流程后,先去看下面的三个变换,再来看SVPWM算法。

新整理文章:FOC算法与SVPWM-CSDN博客

SVPWM

  • 逆变器开关状态与电压矢量:以三相电压型逆变器为例,它有 6 个功率开关器件,通过控制这些开关器件的通断,可以得到 8 种不同的开关状态,对应着 6 个非零电压矢量和 2 个零电压矢量。例如,当 A 相上桥臂开关导通,B、C 相下桥臂开关导通时,输出的电压矢量为V1;当所有上桥臂开关导通或所有下桥臂开关导通时,输出的是零电压矢量V0或V7。
  • 扇区划分:将电压空间矢量平面划分为 6 个扇区,每个扇区为 60°。根据当前电压空间矢量所在的扇区,可以确定需要合成该矢量的两个相邻非零电压矢量和零电压矢量。例如,若电压空间矢量位于第一扇区,则需要使用V1和V2以及零电压矢量来合成。
  • 矢量合成与占空比计算:根据伏秒平衡原理,在一个采样周期内,通过合理分配相邻非零电压矢量和零电压矢量的作用时间,使得合成的电压空间矢量与参考电压矢量相等。以第一扇区为例,假设参考电压矢量Vref在该扇区,通过计算Vref在V1和V2方向上的投影,得到V1和V2的作用时间T1和T2,再根据采样周期T_s,计算出零电压矢量的作用时间T0 = Ts - T1 - T2。
  • PWM 信号生成:根据计算得到的各电压矢量的作用时间,生成相应的 PWM 信号,控制逆变器开关器件的通断。例如,在一个采样周期内,先施加T1时间的V1对应的开关状态,再施加T2时间的V2对应的开关状态,最后施加T0时间的零电压矢量对应的开关状态,从而实现对逆变器输出电压的控制,达到控制电机运行的目的。

1.三相逆变电路:

  三组半桥一共有8种组合方式,编码分别为:000001010011100101110111 。我    们打开第一组半桥的上桥臂、第二组和第三组半桥的下桥臂(其余的关闭),那么就可以让电        流 从电源正极流过电机的a相,流经b、c相,然后回到电源负极

  • 注:三相逆变电路上下桥不能同时导通。
  • 上桥开通下桥关断定义为状态1
  • 上桥关断下桥开通定义为状态0

2.计算扇区

3.计算作用时间

注:计算方式不止一种(在后续的文章中会讲解)

4.七段式时间分配

void SevenSegmentAllocation(float T1, float T2, float T0, uint16_t *CCR1, uint16_t *CCR2, uint16_t *CCR3) {
    float T0_half = T0 / 2;
    float Ta, Tb, Tc;

    // 计算各相的时间
    Ta = T0_half + T1 + T2;
    Tb = T0_half + T2;
    Tc = T0_half;

    // 七段式时间分配
    *CCR1 = (uint16_t)(Ta * (TIM1->ARR + 1) / T_S);
    *CCR2 = (uint16_t)(Tb * (TIM1->ARR + 1) / T_S);
    *CCR3 = (uint16_t)(Tc * (TIM1->ARR + 1) / T_S);
}
  • T0_half:将零矢量的作用时间 T0 分为两半。
  • TaTbTc:分别计算三相的时间,这里是基于七段式 SVPWM 的时间分配原则。
  • *CCR1*CCR2*CCR3:将计算得到的时间转换为定时器的比较寄存器值,用于控制 PWM 的占空比。

分配方法解释:

  • 在扇区1时,合成目标矢量的是v1(100)和v2(110)以及0矢量(000),(111)。因为0矢量要平均分配,所以t0/2(000是低电平,111是高电平,高电平占一半),而v1和v2在A相都是1,所以Ta=t1+t2+t0/2。而v1在B相为0,所以时间不计(计算的时间是作用时间,即上桥臂打开的时间)。所以Tb=t2+t0/2。而v1,v2在C相都是0,所以Tc=t0/2。Ta,Tb,Tc就是三路PWM波的高电平时间,即对应A,B,C三相逆变电路的上桥臂开通时间。
  • 注意:不同扇区下,t1,t2对应的开关状态是不同的。

5.设置互补输出和死区时间

 1. 选择合适的定时器

 通常,高级定时器(如 TIM1、TIM8)支持互补输出和死区时间设置,适合用于驱动三相逆变器。  在 STM32CubeMX 的 “Pinout & Configuration” 选项卡中,选择一个高级定时器,例如 TIM1。

 2. 配置定时器的基本参数

  • 时钟源:选择定时器的时钟源,一般使用内部时钟(Internal Clock)。
  • 预分频器(Prescaler):设置预分频器的值,用于调整定时器的时钟频率。计算公式为:定时器时钟频率 = 系统时钟频率 / (预分频器值 + 1)
  • 自动重载值(Auto-reload value):设置自动重载寄存器的值,决定 PWM 的周期。PWM 周期计算公式为:PWM周期 = (自动重载值 + 1) * 定时器时钟周期

3. 配置 PWM 输出通道

  • 通道模式:将定时器的通道配置为 PWM 模式。在 “Mode” 下拉菜单中选择 “PWM Generation CHx”(x 为通道号)。
  • PWM 模式:选择 PWM 模式,通常使用 PWM 模式 1 或 PWM 模式 2。
  • 占空比:设置初始的占空比,通过改变比较寄存器的值来调整。

4. 启用互补输出

在定时器的配置选项中,找到 “Output Compare Mode” 部分,对于每个通道,启用互补输出(Complementary Output)。这样,每个通道会自动生成一个互补的 PWM 信号。

5. 设置死区时间

  • 在定时器的配置选项中,找到 “Dead Time and Break Inputs” 部分。
  • 死区时间值:设置死区时间的值。死区时间的计算公式为:死区时间 = 死区时间值 * 定时器时钟周期。可以根据实际需求调整死区时间的大小,以避免同一桥臂的上下管同时导通。
  • 死区时间寄存器:根据 STM32 的不同系列,可能需要设置不同的死区时间寄存器。例如,在 TIM1 中,可以通过设置 BDTR 寄存器的 DTG 位来设置死区时间。

6. 使能刹车功能(可选)

如果需要刹车功能,可以在 “Dead Time and Break Inputs” 部分启用刹车输入(Break Input),并设置相应的参数。

/* TIM1 init function */
void MX_TIM1_Init(void)
{
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};
  TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};

  htim1.Instance = TIM1;
  htim1.Init.Prescaler = 0;
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim1.Init.Period = 999;
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim1.Init.RepetitionCounter = 0;
  htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_Init(&htim1) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 500;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
  sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
  if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_ENABLE;
  sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_ENABLE;
  sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
  sBreakDeadTimeConfig.DeadTime = 10; // 设置死区时间
  sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
  sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
  sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
  if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK)
  {
    Error_Handler();
  }
  HAL_TIM_MspPostInit(&htim1);
}

克拉克变换:

  • 克拉克变换是将三相静止坐标系(a−b−c 坐标系)下的物理量转换到两相静止坐标系(α−β 坐标系)下的变换方法。在交流电机控制中,三相系统的分析和控制较为复杂,通过克拉克变换可以将三相问题简化为两相问题,降低计算复杂度。

帕克变换:

  • 帕克变换是将两相静止坐标系(α−β 坐标系)下的物理量转换到两相旋转坐标系(d−q 坐标系)下的变换方法。在 d−q 坐标系中,电机的控制方程可以得到进一步简化,实现对电机的磁场和转矩的解耦控制。

帕克逆变换:

  • 帕克逆变换是帕克变换的逆过程,它将两相旋转坐标系(d−q 坐标系)下的物理量转换回两相静止坐标系(α−β 坐标系)下,以便生成用于驱动电机的三相电压或电流信号。
  • 在电机控制中,经过控制算法得到 d−q 坐标系下的控制量后,需要通过帕克逆变换将其转换回 α−β 坐标系,再经过SVPWM得到三相控制信号,从而实现对电机的精确控制。

SVPWM 的优势

  • 直流电压利用率高:相比传统的正弦脉宽调制(SPWM),SVPWM 能够更有效地利用直流母线电压,输出的基波电压幅值更高,可使电机获得更大的输出转矩和功率。
  • 谐波含量低:SVPWM 生成的电压波形更接近正弦波,谐波含量较低,能够减少电机的谐波损耗和转矩脉动,提高电机的运行效率和稳定性。
  • 易于数字化实现:其算法基于空间矢量的概念,便于采用数字信号处理器(DSP)或现场可编程门阵列(FPGA)等数字控制芯片进行实现,具有较高的灵活性和可靠性。

FOC相关代码:(SVPWM,帕克变换,帕克逆变换,克拉克变换)


void SVPWM_3ShuntCalcDutyCycles (Volt_Components Stat_Volt_Input)
{
   s32 wX, wY, wZ, wUAlpha, wUBeta;
   u16  hTimePhA=0, hTimePhB=0, hTimePhC=0, hTimePhD=0;
   u16  hDeltaDuty;
    
   wUAlpha = Stat_Volt_Input.qV_Component1 * T_SQRT3;
   wUBeta = -(Stat_Volt_Input.qV_Component2 * T);

   wX = wUBeta;
   wY = (wUBeta + wUAlpha)/2;
   wZ = (wUBeta - wUAlpha)/2;
   
  // Sector calculation from wX, wY, wZ
   if (wY<0)
   {
      if (wZ<0)
      {
        bSector = SECTOR_5;
      }
      else // wZ >= 0
        if (wX<=0)
        {
          bSector = SECTOR_4;
        }
        else // wX > 0
        {
          bSector = SECTOR_3;
        }
   }
   else // wY > 0
   {
     if (wZ>=0)
     {
       bSector = SECTOR_2;
     }
     else // wZ < 0
       if (wX<=0)
       {  
         bSector = SECTOR_6;
       }
       else // wX > 0
       {
         bSector = SECTOR_1;
       }
    }
   
   /* Duty cycles computation */
  PWM4Direction=PWM2_MODE;
    
  switch(bSector)
  {  
    case SECTOR_1:
                hTimePhA = (T/8) + ((((T + wX) - wZ)/2)/131072);
				hTimePhB = hTimePhA + wZ/131072;
				hTimePhC = hTimePhB - wX/131072;
                
                // ADC Syncronization setting value             
                if ((u16)(PWM_PERIOD-hTimePhA) > TW_AFTER)
                {
                  hTimePhD = PWM_PERIOD - 1;
                }
                else
                {
                  hDeltaDuty = (u16)(hTimePhA - hTimePhB);
                  
				  // Definition of crossing point
                  if (hDeltaDuty > (u16)(PWM_PERIOD-hTimePhA)*2) 
                  {
                      hTimePhD = hTimePhA - TW_BEFORE; // Ts before Phase A 
                  }
                  else
                  {
                      hTimePhD = hTimePhA + TW_AFTER; // DT + Tn after Phase A
                     
                    if (hTimePhD >= PWM_PERIOD)
                    {
                      // Trigger of ADC at Falling Edge PWM4
                      // OCR update
                      
                      //Set Polarity of CC4 Low
                      PWM4Direction=PWM1_MODE;
                      
                      hTimePhD = (2 * PWM_PERIOD) - hTimePhD-1;
                    }
                  }
                }
                            
                break;
    case SECTOR_2:
                hTimePhA = (T/8) + ((((T + wY) - wZ)/2)/131072);
				hTimePhB = hTimePhA + wZ/131072;
				hTimePhC = hTimePhA - wY/131072;
                
                // ADC Syncronization setting value
                if ((u16)(PWM_PERIOD-hTimePhB) > TW_AFTER)
                {
                  hTimePhD = PWM_PERIOD - 1;
                }
                else
                {
                  hDeltaDuty = (u16)(hTimePhB - hTimePhA);
                  
                  // Definition of crossing point
                  if (hDeltaDuty > (u16)(PWM_PERIOD-hTimePhB)*2) 
                  {
                    hTimePhD = hTimePhB - TW_BEFORE; // Ts before Phase B 
                  }
                  else
                  {
                    hTimePhD = hTimePhB + TW_AFTER; // DT + Tn after Phase B
                    
                    if (hTimePhD >= PWM_PERIOD)
                    {
                      // Trigger of ADC at Falling Edge PWM4
                      // OCR update
                      
                      //Set Polarity of CC4 Low
                      PWM4Direction=PWM1_MODE;
                      
                      hTimePhD = (2 * PWM_PERIOD) - hTimePhD-1;
                    }
                  }
                }
                
                break;

    case SECTOR_3:
                hTimePhA = (T/8) + ((((T - wX) + wY)/2)/131072);
				        hTimePhC = hTimePhA - wY/131072;
                hTimePhB = hTimePhC + wX/131072;
		
                // ADC Syncronization setting value
                if ((u16)(PWM_PERIOD-hTimePhB) > TW_AFTER)
                {
                  hTimePhD = PWM_PERIOD - 1;
                }
                else
                {
                  hDeltaDuty = (u16)(hTimePhB - hTimePhC);
                  
                  // Definition of crossing point
                  if (hDeltaDuty > (u16)(PWM_PERIOD-hTimePhB)*2) 
                  {
                    hTimePhD = hTimePhB - TW_BEFORE; // Ts before Phase B 
                  }
                  else
                  {
                    hTimePhD = hTimePhB + TW_AFTER; // DT + Tn after Phase B
                    
                    if (hTimePhD >= PWM_PERIOD)
                    {
                      // Trigger of ADC at Falling Edge PWM4
                      // OCR update
                      
                      //Set Polarity of CC4 Low
                      PWM4Direction=PWM1_MODE;
                      
                      hTimePhD = (2 * PWM_PERIOD) - hTimePhD-1;
                    }
                  }
                }
                break;
    
    case SECTOR_4:
                hTimePhA = (T/8) + ((((T + wX) - wZ)/2)/131072);
                hTimePhB = hTimePhA + wZ/131072;
                hTimePhC = hTimePhB - wX/131072;
                
                // ADC Syncronization setting value
                if ((u16)(PWM_PERIOD-hTimePhC) > TW_AFTER)
                {
                  hTimePhD = PWM_PERIOD - 1;
                }
                else
                {
                  hDeltaDuty = (u16)(hTimePhC - hTimePhB);
                  
                  // Definition of crossing point
                  if (hDeltaDuty > (u16)(PWM_PERIOD-hTimePhC)*2)
                  {
                    hTimePhD = hTimePhC - TW_BEFORE; // Ts before Phase C 
                  }
                  else
                  {
                    hTimePhD = hTimePhC + TW_AFTER; // DT + Tn after Phase C
                    
                    if (hTimePhD >= PWM_PERIOD)
                    {
                      // Trigger of ADC at Falling Edge PWM4
                      // OCR update
                      
                      //Set Polarity of CC4 Low
                      PWM4Direction=PWM1_MODE;
                      
                      hTimePhD = (2 * PWM_PERIOD) - hTimePhD-1;
                    }
                  }
                }
                break;  
    
    case SECTOR_5:
                hTimePhA = (T/8) + ((((T + wY) - wZ)/2)/131072);
				hTimePhB = hTimePhA + wZ/131072;
				hTimePhC = hTimePhA - wY/131072;
                
                // ADC Syncronization setting value
                if ((u16)(PWM_PERIOD-hTimePhC) > TW_AFTER)
                {
                  hTimePhD = PWM_PERIOD - 1;
                }
                else
                {
                  hDeltaDuty = (u16)(hTimePhC - hTimePhA);
                  
                  // Definition of crossing point
                  if (hDeltaDuty > (u16)(PWM_PERIOD-hTimePhC)*2) 
                  {
                    hTimePhD = hTimePhC - TW_BEFORE; // Ts before Phase C 
                  }
                  else
                  {
                    hTimePhD = hTimePhC + TW_AFTER; // DT + Tn after Phase C
                    
                    if (hTimePhD >= PWM_PERIOD)
                    {
                      // Trigger of ADC at Falling Edge PWM4
                      // OCR update
                      
                      //Set Polarity of CC4 Low
                      PWM4Direction=PWM1_MODE;
                      
                      hTimePhD = (2 * PWM_PERIOD) - hTimePhD-1;
                    }
                  }
                }

		break;
                
    case SECTOR_6:
                hTimePhA = (T/8) + ((((T - wX) + wY)/2)/131072);
				hTimePhC = hTimePhA - wY/131072;
				hTimePhB = hTimePhC + wX/131072;
                
                // ADC Syncronization setting value
                if ((u16)(PWM_PERIOD-hTimePhA) > TW_AFTER)
                {
                  hTimePhD = PWM_PERIOD - 1;
                }
                else
                {
                  hDeltaDuty = (u16)(hTimePhA - hTimePhC);
                  
                  // Definition of crossing point
                  if (hDeltaDuty > (u16)(PWM_PERIOD-hTimePhA)*2) 
                  {
                    hTimePhD = hTimePhA - TW_BEFORE; // Ts before Phase A 
                  }
                  else
                  {
                    hTimePhD = hTimePhA + TW_AFTER; // DT + Tn after Phase A
                    
                    if (hTimePhD >= PWM_PERIOD)
                    {
                      // Trigger of ADC at Falling Edge PWM4
                      // OCR update
                      
                      //Set Polarity of CC4 Low
                      PWM4Direction=PWM1_MODE;
                      
                      hTimePhD = (2 * PWM_PERIOD) - hTimePhD-1;
                    }
                  }
                }

                break;
    default:
		break;
   }
  
  if (PWM4Direction == PWM2_MODE)
  {
    //Set Polarity of CC4 High
    TIM1->CCER &= 0xDFFF;    
  }
  else
  {
    //Set Polarity of CC4 Low
    TIM1->CCER |= 0x2000;
  }
  
  /* Load compare registers values */ 
	__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1,hTimePhA);
	__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2,hTimePhB);
	__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3,hTimePhC);
	__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_4,hTimePhD);
	
	htimetemp = hTimePhA;
	
}








const s16 hSin_Cos_Table[256] = {\
0x0000,0x00C9,0x0192,0x025B,0x0324,0x03ED,0x04B6,0x057F,\
0x0648,0x0711,0x07D9,0x08A2,0x096A,0x0A33,0x0AFB,0x0BC4,\
0x0C8C,0x0D54,0x0E1C,0x0EE3,0x0FAB,0x1072,0x113A,0x1201,\
0x12C8,0x138F,0x1455,0x151C,0x15E2,0x16A8,0x176E,0x1833,\
0x18F9,0x19BE,0x1A82,0x1B47,0x1C0B,0x1CCF,0x1D93,0x1E57,\
0x1F1A,0x1FDD,0x209F,0x2161,0x2223,0x22E5,0x23A6,0x2467,\
0x2528,0x25E8,0x26A8,0x2767,0x2826,0x28E5,0x29A3,0x2A61,\
0x2B1F,0x2BDC,0x2C99,0x2D55,0x2E11,0x2ECC,0x2F87,0x3041,\
0x30FB,0x31B5,0x326E,0x3326,0x33DF,0x3496,0x354D,0x3604,\
0x36BA,0x376F,0x3824,0x38D9,0x398C,0x3A40,0x3AF2,0x3BA5,\
0x3C56,0x3D07,0x3DB8,0x3E68,0x3F17,0x3FC5,0x4073,0x4121,\
0x41CE,0x427A,0x4325,0x43D0,0x447A,0x4524,0x45CD,0x4675,\
0x471C,0x47C3,0x4869,0x490F,0x49B4,0x4A58,0x4AFB,0x4B9D,\
0x4C3F,0x4CE0,0x4D81,0x4E20,0x4EBF,0x4F5D,0x4FFB,0x5097,\
0x5133,0x51CE,0x5268,0x5302,0x539B,0x5432,0x54C9,0x5560,\
0x55F5,0x568A,0x571D,0x57B0,0x5842,0x58D3,0x5964,0x59F3,\
0x5A82,0x5B0F,0x5B9C,0x5C28,0x5CB3,0x5D3E,0x5DC7,0x5E4F,\
0x5ED7,0x5F5D,0x5FE3,0x6068,0x60EB,0x616E,0x61F0,0x6271,\
0x62F1,0x6370,0x63EE,0x646C,0x64E8,0x6563,0x65DD,0x6656,\
0x66CF,0x6746,0x67BC,0x6832,0x68A6,0x6919,0x698B,0x69FD,\
0x6A6D,0x6ADC,0x6B4A,0x6BB7,0x6C23,0x6C8E,0x6CF8,0x6D61,\
0x6DC9,0x6E30,0x6E96,0x6EFB,0x6F5E,0x6FC1,0x7022,0x7083,\
0x70E2,0x7140,0x719D,0x71F9,0x7254,0x72AE,0x7307,0x735E,\
0x73B5,0x740A,0x745F,0x74B2,0x7504,0x7555,0x75A5,0x75F3,\
0x7641,0x768D,0x76D8,0x7722,0x776B,0x77B3,0x77FA,0x783F,\
0x7884,0x78C7,0x7909,0x794A,0x7989,0x79C8,0x7A05,0x7A41,\
0x7A7C,0x7AB6,0x7AEE,0x7B26,0x7B5C,0x7B91,0x7BC5,0x7BF8,\
0x7C29,0x7C59,0x7C88,0x7CB6,0x7CE3,0x7D0E,0x7D39,0x7D62,\
0x7D89,0x7DB0,0x7DD5,0x7DFA,0x7E1D,0x7E3E,0x7E5F,0x7E7E,\
0x7E9C,0x7EB9,0x7ED5,0x7EEF,0x7F09,0x7F21,0x7F37,0x7F4D,\
0x7F61,0x7F74,0x7F86,0x7F97,0x7FA6,0x7FB4,0x7FC1,0x7FCD,\
0x7FD8,0x7FE1,0x7FE9,0x7FF0,0x7FF5,0x7FF9,0x7FFD,0x7FFE};

/**********************************************************************************************************
Clarke变换,输入Ia,Ib,得到Ialpha和Ibeta
**********************************************************************************************************/ 
Curr_Components Clarke(Curr_Components Curr_Input)         
{
  Curr_Components Curr_Output; 
  s32 qIa_divSQRT3_tmp;
  s32 qIb_divSQRT3_tmp;    //定义32位有符号数,用来暂存Q30格式  
  s16 qIa_divSQRT3;
  s16 qIb_divSQRT3 ;
 
  Curr_Output.qI_Component1 = Curr_Input.qI_Component1;     //Ialpha = Ia
 
  qIa_divSQRT3_tmp = divSQRT_3 * Curr_Input.qI_Component1;  //计算Ia/√3
  qIa_divSQRT3_tmp /=32768;                                 //两个Q15数相乘,会变成Q30,因此要右移15位,变回Q15	    
  qIb_divSQRT3_tmp = divSQRT_3 * Curr_Input.qI_Component2;  //计算Ib/√3
  qIb_divSQRT3_tmp /=32768;
  
  qIa_divSQRT3=((s16)(qIa_divSQRT3_tmp));	                //s32赋值给s16	 		
  qIb_divSQRT3=((s16)(qIb_divSQRT3_tmp));				
     
  Curr_Output.qI_Component2=(-(qIa_divSQRT3)-(qIb_divSQRT3)-(qIb_divSQRT3));  //Ibeta = -(2*Ib+Ia)/sqrt(3) 
  return(Curr_Output); 
}
 
	
/*******************************************************************************
* Function Name  : Trig_Functions 
* Description    : 本函数返回输入角度的cos和sin函数值
* Input          : angle in s16 format
* Output         : Cosine and Sine in s16 format
*******************************************************************************/
Trig_Components Trig_Functions(s16 hAngle)  //hAngle=0,转子电角度=0度。hAngle=S16_MAX,转子电角度=180度。hAngle=S16_MIN,转子电角度=-180度
{
  u16 hindex;
  Trig_Components Local_Components;
  
  /* 10 bit index computation  */  
  hindex = (u16)(hAngle + 32768);  
  hindex /= 64;      
  
  switch (hindex & SIN_MASK) 
  {
  case U0_90:
    Local_Components.hSin = hSin_Cos_Table[(u8)(hindex)];
    Local_Components.hCos = hSin_Cos_Table[(u8)(0xFF-(u8)(hindex))];
    break;
  
  case U90_180:  
     Local_Components.hSin = hSin_Cos_Table[(u8)(0xFF-(u8)(hindex))];
     Local_Components.hCos = -hSin_Cos_Table[(u8)(hindex)];
    break;
  
  case U180_270:
     Local_Components.hSin = -hSin_Cos_Table[(u8)(hindex)];
     Local_Components.hCos = -hSin_Cos_Table[(u8)(0xFF-(u8)(hindex))];
    break;
  
  case U270_360:
     Local_Components.hSin =  -hSin_Cos_Table[(u8)(0xFF-(u8)(hindex))];
     Local_Components.hCos =  hSin_Cos_Table[(u8)(hindex)]; 
    break;
  default:
    break;
  }
  return (Local_Components);
}
 

/**********************************************************************************************************
Park变换,输入电角度、Ialpha和Ibeta,经过Park变换得到Iq、Id
**********************************************************************************************************/ 
Curr_Components Park(Curr_Components Curr_Input, s16 Theta)       
{ 
  Curr_Components Curr_Output;
  s32 qId_tmp_1, qId_tmp_2;
  s32 qIq_tmp_1, qIq_tmp_2;     
  s16 qId_1, qId_2;  
  s16 qIq_1, qIq_2;  
  
  Vector_Components = Trig_Functions(Theta);                      //计算电角度的cos和sin
  
  qIq_tmp_1 = Curr_Input.qI_Component1 * Vector_Components.hCos;  //计算Ialpha*cosθ	
  qIq_tmp_1 /= 32768;
  qIq_tmp_2 = Curr_Input.qI_Component2 *Vector_Components.hSin;   //计算Ibeta*sinθ
  qIq_tmp_2 /= 32768;
 
  qIq_1 = ((s16)(qIq_tmp_1));
  qIq_2 = ((s16)(qIq_tmp_2));
  Curr_Output.qI_Component1 = ((qIq_1)-(qIq_2));	//Iq=Ialpha*cosθ- Ibeta*sinθ
  
  qId_tmp_1 = Curr_Input.qI_Component1 * Vector_Components.hSin;  //计算Ialpha*sinθ
  qId_tmp_1 /= 32768;
  qId_tmp_2 = Curr_Input.qI_Component2 * Vector_Components.hCos;  //计算Ibeta*cosθ
  qId_tmp_2 /= 32768;
  
  qId_1 = (s16)(qId_tmp_1);		 
  qId_2 = (s16)(qId_tmp_2);					
  Curr_Output.qI_Component2 = ((qId_1)+(qId_2));   //Id=Ialpha*sinθ+ Ibeta*cosθ
  
  return (Curr_Output);
}
 
/**********************************************************************************************************
反park变换,输入Uq、Ud得到Ualpha、Ubeta
**********************************************************************************************************/ 
Volt_Components Rev_Park(Volt_Components Volt_Input)
{ 	
  s32 qValpha_tmp1,qValpha_tmp2,qVbeta_tmp1,qVbeta_tmp2;
  s16 qValpha_1,qValpha_2,qVbeta_1,qVbeta_2;
  Volt_Components Volt_Output;
   
  qValpha_tmp1 = Volt_Input.qV_Component1 * Vector_Components.hCos;  //Uq*cosθ
  qValpha_tmp1 /= 32768; 
  qValpha_tmp2 = Volt_Input.qV_Component2 * Vector_Components.hSin;  //Ud*sinθ
  qValpha_tmp2 /= 32768;
		
  qValpha_1 = (s16)(qValpha_tmp1);		
  qValpha_2 = (s16)(qValpha_tmp2);			
  Volt_Output.qV_Component1 = ((qValpha_1)+(qValpha_2));             //Ualpha=Uq*cosθ+ Ud*sinθ
  
  qVbeta_tmp1 = Volt_Input.qV_Component1 * Vector_Components.hSin;   //Uq*sinθ
  qVbeta_tmp1 /= 32768;  
  qVbeta_tmp2 = Volt_Input.qV_Component2 * Vector_Components.hCos;   //Ud*cosθ
  qVbeta_tmp2 /= 32768;
 
  qVbeta_1 = (s16)(qVbeta_tmp1);				
  qVbeta_2 = (s16)(qVbeta_tmp2);  				
  Volt_Output.qV_Component2 = -(qVbeta_1)+(qVbeta_2);                //Ubeta=Ud*cosθ- Uq*sinθ
 
  return(Volt_Output);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

J-TS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值