目录
概述
1 电机控制的空间矢量调制 (SVPWM)介绍
2 实现原理
2.1 设计要求
2.2 SVPWM 的实现
3 SVPWM的C语言
3.1 代码文件
3.2 STM32G4平台上验证
4 源代码文件
概述
本文主要介绍电机控制的空间矢量调制 (SVPWM),空间矢量调制 (SVPWM) 是感应电机和永磁同步电机 (PMSM) 磁场定向控制的常用方法。空间矢量调制负责生成脉宽调制信号以控制逆变器的开关,由此产生所需的调制电压,以所需的速度或转矩驱动电机。空间矢量调制也称为空间矢量脉宽调制 (SVPWM)。文中介绍了该部分内容的实现原理,并实现C语言实现其代码。
1 电机控制的空间矢量调制 (SVPWM)介绍
空间矢量调制 (SVPWM) 是感应电机和永磁同步电机 (PMSM) 磁场定向控制的常用方法。空间矢量调制负责生成脉宽调制信号以控制逆变器的开关,由此产生所需的调制电压,以所需的速度或转矩驱动电机。空间矢量调制也称为空间矢量脉宽调制 (SVPWM)。
2 实现原理
2.1 设计要求
试考虑三相逆变器电机控制的空间矢量调制,该逆变器具有六个开关,如以下等效电路所示。注意,有八种有效的开关配置。
用于电机控制的空间矢量调制 (SVPWM)
电机控制的空间矢量调制 (SVM)
每种开关配置都会产生特定的电压,施加于电机端子。电压是基本空间矢量,以空间矢量六边形表示其幅值和方向。
通过对开关区间内的基本空间矢量(方向)和零矢量(幅值)作用时间进行调节,可以近似得到空间矢量六边形内任意位置、任意幅值的电压矢量。
例如: 图中,一个脉宽调制 (PWM) 周期内,选择两个相邻空间矢量(图中的 U3 和 U4)分别作用一段时间、在周期其余时间内由零矢量(U7 或 U8)作用,从而得到近似平均参考矢量 Uref。
通过控制开关序列,即控制脉冲的导通持续时间,就可以在每个 PWM 周期获得具有变化幅值和方向的任何电压矢量。空间矢量调制方法的目标是在每个 PWM 周期生成与参考电压矢量相符的开关序列,以实现连续旋转的空间矢量。
2.2 SVPWM的实现
空间矢量调制方法基于参考电压矢量进行操作,在每个 PWM 周期为逆变器生成适当导通信号,目标是实现连续旋转的空间矢量。
采用空间矢量调制的磁场定向控制架构示意图:
在每个 PWM 周期,以电压矢量作为输入参考,SVM 算法会:
- 基于参考电压矢量计算开关导通时间
- 基于导通时间生成马鞍波
- 基于导通时间为逆变器开关生成适当的导通脉冲
SVPWM算法生成的空间矢量调制电压信号的波形图:
所生成的马鞍波能够最大程度地利用直流总线电压。与正弦脉宽调制 (SPWM) 方法相比,该方法能提供更好的额定电压输出。然后,将生成的导通信号应用于三相逆变器的开关,以所需的速度或转矩驱动电机。
3 SVPWM的C语言
3.1 代码文件
代码84行: 设置SVPWM的采样周期
代码85~87行: 设置象限的电压值
代码91行: 计算扇区
代码97 ~ 111 行: 实现第5扇区的波形
代码116 ~ 129 行: 实现第1扇区的波形
代码130~ 145 行: 实现第3扇区的波形
代码147~ 162行: 实现第2扇区的波形
代码165~ 179行: 实现第6扇区的波形
代码181~ 196行: 实现第4扇区的波形
3.2 STM32G4平台上验证
1)测试代码实现
2)运行代码和查看波形
查看α,β坐标系上的波形图:
经svm转换后的波形图:
4 源代码文件
1) .c文件中的代码
/* USER CODE BEGIN Header */
/**
******************************************************************************
* File Name : foc_ctrl.h
* Description : foc driver base on stm32f446
******************************************************************************
* @attention
*
* COPYRIGHT: Copyright (c) 2024 tangminfei2013@126.com
* DATE: JUL 05th, 2024
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "foc_ctrl.h"
#define SQRT_3 1.7320508f
#define SQRT_3_DIV_2 0.8660254f
#define DIV_1 0.5f
FOC_T FOC;
/*****************************************************************************
Clarke变换 输入三相电流,输出alpha,bate电流
Iα = Ia
Iβ = (Ia + 2Ib) / sqrt(3)
******************************************************************************/
void clarkeTransform(Phase_T *abc, AlphaBeta_T *alphaBeta)
{
alphaBeta->alpha = abc->Ua;
alphaBeta->beta = (abc->Ua + 2 * abc->Ub) * SQRT_3;
}
/****************************************************************************
Park变换,输入电角度、Ialpha和Ibeta,经过Park变换得到Iq、Id
Id = Iα · cosθ + Iβ · sinθ
Iq = Iα · sinθ + Iβ · cosθ
*****************************************************************************/
void parkTransform(const AlphaBeta_T *alphaBeta, float angle, DQ_T *dq)
{
float sinAngle = sin(angle);
float cosAngle = cos(angle);
dq->d = cosAngle * alphaBeta->alpha + sinAngle * alphaBeta->beta;
dq->q = -sinAngle * alphaBeta->alpha + cosAngle * alphaBeta->beta;
}
/***************************************************************************
park逆变换,输入Uq、Ud得到Ualpha、Ubeta
Uα = Ud · cosθ - Uq · sinθ
Uβ = Ud · sinθ + Uq · cosθ
****************************************************************************/
void inverseParkTransform(DQ_T *dq, AlphaBeta_T *alphaBeta, float angle)
{
float cosAngle = cos(angle);
float sinAngle = sin(angle);
alphaBeta->alpha = dq->d * cosAngle - dq->q * sinAngle;
alphaBeta->beta = dq->d * sinAngle + dq->q * cosAngle;
}
/**********************************************************************************************************
Clarke逆变换,输入Ualpha、Ubeta,得到Ua,Ub,Uc
Ua = Uα
Ub = -1/2 * Uα + sqrt(3)/2 * Uβ
Ub = -1/2 * Uα - sqrt(3)/2 * Uβ
**********************************************************************************************************/
void inverseClarkeTransform(AlphaBeta_T *abVoltage, Phase_T *abc)
{
abc->Ua = abVoltage->alpha;
abc->Ub = -DIV_1 * abVoltage->alpha + SQRT_3_DIV_2 * abVoltage->beta;
abc->Uc = -DIV_1 * abVoltage->alpha - SQRT_3_DIV_2 * abVoltage->beta;
}
void SVPWM(SVPWM_T *svpwm, Phase_T *abc)
{
float sum;
float k_svpwm;
// step-1: 设置象限电压值
svpwm->Ts = 1.0f; // SVPWM的采样周期
svpwm->u1 = abc->Ua;
svpwm->u2 = abc->Ub;
svpwm->u3 = abc->Uc;
// step2:扇区判断
// 根据u1、u2和u3的正负情况确定所处的扇区
svpwm->sector = (svpwm->u1 > 0.0f) + ((svpwm->u2 > 0.0f) << 1) + ((svpwm->u3 > 0.0f) << 2); // N=4*C+2*B+A
// step3:计算基本矢量电压作用时间(占空比)
// 根据扇区的不同,计算对应的t_a、t_b和t_c的值,表示生成的三相电压的时间
switch (svpwm->sector)
{
case 5:
// 扇区5
svpwm->t4 = svpwm->u3;
svpwm->t6 = svpwm->u1;
sum = svpwm->t4 + svpwm->t6;
if (sum > svpwm->Ts)
{
k_svpwm = svpwm->Ts / sum; //
svpwm->t4 = k_svpwm * svpwm->t4;
svpwm->t6 = k_svpwm * svpwm->t6;
}
svpwm->t7 = (svpwm->Ts - svpwm->t4 - svpwm->t6) / 2;
svpwm->ta = svpwm->t4 + svpwm->t6 + svpwm->t7;
svpwm->tb = svpwm->t6 + svpwm->t7;
svpwm->tc = svpwm->t7;
break;
case 1:
// 扇区1
svpwm->t2 = -svpwm->u3;
svpwm->t6 = -svpwm->u2;
sum = svpwm->t2 + svpwm->t6;
if (sum > svpwm->Ts)
{
k_svpwm = svpwm->Ts / sum; // 计算缩放系数
svpwm->t2 = k_svpwm * svpwm->t2;
svpwm->t6 = k_svpwm * svpwm->t6;
}
svpwm->t7 = (svpwm->Ts - svpwm->t2 - svpwm->t6) / 2;
svpwm->ta = svpwm->t6 + svpwm->t7;
svpwm->tb = svpwm->t2 + svpwm->t6 + svpwm->t7;
svpwm->tc = svpwm->t7;
break;
case 3:
// 扇区3
svpwm->t2 = svpwm->u1;
svpwm->t3 = svpwm->u2;
sum = svpwm->t2 + svpwm->t3;
if (sum > svpwm->Ts)
{
k_svpwm = svpwm->Ts / sum; //
svpwm->t2 = k_svpwm * svpwm->t2;
svpwm->t3 = k_svpwm * svpwm->t3;
}
svpwm->t7 = (svpwm->Ts - svpwm->t2 - svpwm->t3) / 2;
svpwm->ta = svpwm->t7;
svpwm->tb = svpwm->t2 + svpwm->t3 + svpwm->t7;
svpwm->tc = svpwm->t3 + svpwm->t7;
break;
case 2:
// 扇区2
svpwm->t1 = -svpwm->u1;
svpwm->t3 = -svpwm->u3;
sum = svpwm->t1 + svpwm->t3;
if (sum > svpwm->Ts)
{
k_svpwm = svpwm->Ts / sum;
svpwm->t1 = k_svpwm * svpwm->t1;
svpwm->t3 = k_svpwm * svpwm->t3;
}
svpwm->t7 = (svpwm->Ts - svpwm->t1 - svpwm->t3) / 2;
svpwm->ta = svpwm->t7;
svpwm->tb = svpwm->t3 + svpwm->t7;
svpwm->tc = svpwm->t1 + svpwm->t3 + svpwm->t7;
break;
case 6:
// 扇区6
svpwm->t1 = svpwm->u2;
svpwm->t5 = svpwm->u3;
sum = svpwm->t1 + svpwm->t5;
if (sum > svpwm->Ts)
{
k_svpwm = svpwm->Ts / sum; //
svpwm->t1 = k_svpwm * svpwm->t1;
svpwm->t5 = k_svpwm * svpwm->t5;
}
svpwm->t7 = (svpwm->Ts - svpwm->t1 - svpwm->t5) / 2;
svpwm->ta = svpwm->t5 + svpwm->t7;
svpwm->tb = svpwm->t7;
svpwm->tc = svpwm->t1 + svpwm->t5 + svpwm->t7;
break;
case 4:
// 扇区4
svpwm->t4 = -svpwm->u2;
svpwm->t5 = -svpwm->u1;
sum = svpwm->t4 + svpwm->t5;
if (sum > svpwm->Ts)
{
k_svpwm = svpwm->Ts / sum; //
svpwm->t4 = k_svpwm * svpwm->t4;
svpwm->t5 = k_svpwm * svpwm->t5;
}
svpwm->t7 = (svpwm->Ts - svpwm->t4 - svpwm->t5) / 2;
svpwm->ta = svpwm->t4 + svpwm->t5 + svpwm->t7;
svpwm->tb = svpwm->t7;
svpwm->tc = svpwm->t5 + svpwm->t7;
break;
default:
break;
}
// step4:3路PWM输出
}
void foc_test(void)
{
int run_cnt = 10;
float theta = 0;
float ta,tb,tc;
DQ_T dq_t;
AlphaBeta_T alphaBeta_t;
SVPWM_T svpwm_out;
Phase_T phase_t;
dq_t.d = 0.2f;
dq_t.q = 0.0f;
while( run_cnt--)
{
for ( theta = 0; theta < 6.2831853f; theta += 0.275f )
{
// 逆Park变换
inverseParkTransform(&dq_t,&alphaBeta_t,theta);
// 逆Clark变换
inverseClarkeTransform(&alphaBeta_t, &phase_t);
// swpwm 转换
SVPWM( &svpwm_out,&phase_t );
ta = 100.0f*svpwm_out.ta;
tb = 100.0f*svpwm_out.tb;
tc = 100.0f*svpwm_out.tc;
printf( "%.4f,%.4f,%.4f,%.4f,%.4f\n",
alphaBeta_t.alpha*100.0f ,
alphaBeta_t.beta*100.0f ,ta,tb,tc);
// printf("%.4f,%.4f,%.4f,%.4f,%.4f \n", alphaBeta_t.alpha,alphaBeta_t.beta,
// phase_t.Ua,phase_t.Ub,phase_t.Uc );
}
}
}
/* End of this file */
2) .h文件中的代码
/* USER CODE BEGIN Header */
/**
******************************************************************************
* File Name : foc_ctrl.h
* Description : foc driver base on stm32f446
******************************************************************************
* @attention
*
* COPYRIGHT: Copyright (c) 2024 tangminfei2013@126.com
* DATE: JUL 05th, 2024
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#ifndef __FOC_CTRL_H
#define __FOC_CTRL_H
/*****************************************************************************/
/* Includes */
/*****************************************************************************/
#include "main.h"
#include "utils_types.h"
#ifdef _cplusplus
extern "C" {
#endif
typedef struct
{
float Ia; // Phase A current
float Ib; // Phase B current
float Ic; // Phase C current
float Ua; // Phase A Voltage
float Ub; // Phase B Voltage
float Uc; // Phase C Voltage
} Phase_T;
typedef struct
{
float alpha; // alpha-axis current
float beta; // beta-axis current
} AlphaBeta_T;
typedef struct
{
float d; // d-axis current
float q; // q-axis current
} DQ_T;
typedef struct
{
int sector;
float u1;
float u2;
float u3;
float ta;
float tb;
float tc;
float Ts;
float t0;
float t1;
float t2;
float t3;
float t4;
float t5;
float t6;
float t7;
} SVPWM_T;
typedef struct
{
float U_d;
float U_q;
float theta;
float U_alpha;
float U_bate;
Phase_T Phase_Curr;
AlphaBeta_T AlphaBeta;
DQ_T DQ;
} FOC_T;
extern FOC_T FOC;
void foc_test(void);
#ifdef _cplusplus
}
#endif
#endif /* __FOC_CTRL_H */