前言
本文为学习st的电机库MCSDK
笔记,实际输出的PWM波形之间的区别。
关键词:MCSDK
,SPWM
,SVPWM
,Over modulation
,Discontinuous PWM
,
标准波形输出
对应Modulation flags
为None
可以看到,输出波形为马鞍波,即生成波形为SVPWM。
对比逆克拉克变换生成的SPWM,生成的波形两者幅值相同。
对比SPWM零序注入的SVPWM,可以看到生成的波形相同,幅值不同,相差(1848 - 1416)/(1790 - 1416) * 100% = 115.5% = 2 3 \frac{2}{\sqrt{3}} 32。
注:SPWM(七段式)零序分量为:
e ( t ) = − ( m a x ( u ( A , s i n ) , u ( B , s i n ) , u ( C , s i n ) ) + m i n ( u ( A , s i n ) , u ( B , s i n ) , u ( C , s i n ) ) ) 2 e(t) = -\frac{(max(u(A,sin),u(B,sin),u(C,sin)) + min(u(A,sin),u(B,sin),u(C,sin)))}{2} e(t)=−2(max(u(A,sin),u(B,sin),u(C,sin))+min(u(A,sin),u(B,sin),u(C,sin)))
因此通过分扇区计算输出的SVPWM和零序注入的SVPWM实际上是相同的,在线性区间内,SVPWM带来了更大的调制比。
参考文章《零序分量注入SPWM等效为SVPWM - 知乎 (zhihu.com)》
总结
分扇区计算和零序注入,后者更便于实现,不需要考虑各种情况;但是前者可以同时获取当前所在扇区信息,在无传感器的情况下,前者带来了更大的信息量。
过调制
对应Modulation flags
为Over modulation
可以看到,输出波形为马鞍波,但是幅值大于标准的马鞍波,为 2 3 \frac{2}{\sqrt3} 32倍。
将Vq设置为满幅值输出时,此时为了避免输出超出正六边形,将波形调制为了梯形波。
参考ST的wiki,实际上是将调制范围扩大到了非线性区间。
参考文章:《STM32 MC SDK Overmodulation (new in V5.Y) - stm32mcu (stmicroelectronics.cn)》
过调制总结
一张图对比过调制效果:
过调制即最大幅值SVPWM,本质上是平滑的将FOC控制转变为六步换向控制(个人猜的),以获得最大的电压利用效率。
DPWM
对应Modulation flags
为Discontinuous PWM
看波形,DPWM本质也是SVPWM,只是无论任何时候总有一路输出始终为0,MOS管开关频率要低于SVPWM。标准SVPWM(又称CPWM)在一个扇区内有7次电压变换,DPWM有5次,因此又分别称为七段式SVPWM和五段式SVPWM。
参考文章:什么是DPWM调制方式? - 知乎 (zhihu.com)
DPWM总结
由于DPWM的调制方式,使得MOS管的切换频率降低,因此在调制比较高时,可以降低开关MOS管带来的损耗,获得更高的效率。
相关测试代码
void usb_printf(const char *format, ...)
{
static char buffer[128];
va_list args;
va_start(args, format);
vsnprintf(buffer, 127, format, args);
va_end(args);
CDC_Transmit_FS((uint8_t *)buffer,strlen(buffer));
}
/**
* @brief Trigonometrical functions type definition
*/
typedef struct
{
int16_t hCos;
int16_t hSin;
} Trig_Components;
/* CORDIC FUNCTION: COSINE q1.15 */
#define CORDIC_CONFIG_COSINE (LL_CORDIC_FUNCTION_COSINE | LL_CORDIC_PRECISION_6CYCLES | LL_CORDIC_SCALE_0 |\
LL_CORDIC_NBWRITE_1 | LL_CORDIC_NBREAD_1 |\
LL_CORDIC_INSIZE_16BITS | LL_CORDIC_OUTSIZE_16BITS)
__weak Trig_Components MCM_Trig_Functions(int16_t hAngle)
{
union u32toi16x2 {
uint32_t CordicRdata;
Trig_Components Components;
} CosSin;
WRITE_REG(CORDIC->CSR, CORDIC_CONFIG_COSINE);
LL_CORDIC_WriteData(CORDIC, ((uint32_t)0x7FFF0000) + ((uint32_t)hAngle));
CosSin.CordicRdata = LL_CORDIC_ReadData(CORDIC);
return (CosSin.Components);
}
#define SECTOR_1 0U
#define SECTOR_2 1U
#define SECTOR_3 2U
#define SECTOR_4 3U
#define SECTOR_5 4U
#define SECTOR_6 5U
typedef struct
{
int16_t alpha;
int16_t beta;
} alphabeta_t;
typedef struct
{
int16_t q;
int16_t d;
} qd_t;
typedef struct PWMC_Handle
{
uint16_t hT_Sqrt3;
uint16_t PWMperiod;
uint8_t Sector;
uint8_t DPWM_Mode;
uint16_t CntPhA;
uint16_t CntPhB;
uint16_t CntPhC;
}PWMC_Handle_t;
#define SQRT3FACTOR ((uint16_t)0xDDB4) /* = (16384 * 1.732051 * 2)*/
PWMC_Handle_t pwmc_handle =
{
.hT_Sqrt3 = (MAX_PERIOD*SQRT3FACTOR)/16384u,
.PWMperiod = MAX_PERIOD,
.DPWM_Mode = 1,
};
alphabeta_t Vab =
{
.alpha = 1,
.beta = 0,
};
qd_t Vqd =
{
.q = 32767,
.d = 0,
};
int vrefff = 0;
__weak uint16_t PWMC_SetPhaseVoltage(PWMC_Handle_t *pHandle, alphabeta_t Valfa_beta)
{
uint16_t returnValue;
int32_t wX;
int32_t wY;
int32_t wZ;
int32_t wUAlpha;
int32_t wUBeta;
int32_t wTimePhA;
int32_t wTimePhB;
int32_t wTimePhC;
wUAlpha = Valfa_beta.alpha * (int32_t)pHandle->hT_Sqrt3;
wUBeta = -(Valfa_beta.beta * ((int32_t)pHandle->PWMperiod)) * 2;
wX = wUBeta;
wY = (wUBeta + wUAlpha) / 2;
wZ = (wUBeta - wUAlpha) / 2;
/* Sector calculation from wX, wY, wZ */
if (wY < 0)
{
if (wZ < 0)
{
pHandle->Sector = SECTOR_5;
wTimePhA = (((int32_t)pHandle