别再死记硬背公式了!用Python+NumPy手把手带你复现SVPWM算法(附完整代码)

张开发
2026/4/14 14:26:31 15 分钟阅读

分享文章

别再死记硬背公式了!用Python+NumPy手把手带你复现SVPWM算法(附完整代码)
用PythonNumPy实战SVPWM从数学推导到PWM波形生成在电机控制领域空间矢量脉宽调制SVPWM算法因其高电压利用率和优异的控制性能已成为永磁同步电机PMSM驱动系统的核心技术。传统教材往往聚焦于理论推导而实际工程实现时工程师们常陷入公式都懂代码难写的困境。本文将打破这一僵局使用Python和NumPy库带您从零构建完整的SVPWM实现流程每个步骤都配有可运行的代码片段和物理意义解析。1. 理解SVPWM的物理本质与数学模型1.1 三相电压的空间矢量表示三相电压的瞬时值可以表示为import numpy as np def three_phase_voltage(Um, theta): 生成三相电压瞬时值 return np.array([ Um * np.sin(theta), Um * np.sin(theta - 2*np.pi/3), Um * np.sin(theta 2*np.pi/3) ])通过Clarke变换将其转换为静止α-β坐标系def clarke_transform(ua, ub, uc): Clarke变换到α-β坐标系 alpha 2/3 * (ua - 0.5*ub - 0.5*uc) beta 2/3 * (np.sqrt(3)/2*ub - np.sqrt(3)/2*uc) return alpha, beta注意这里采用2/3变换系数保持幅值不变而非功率不变变换1.2 逆变器的基本电压矢量两电平三相逆变器可产生8种开关状态组合对应6个非零矢量和2个零矢量开关状态矢量名称α分量β分量000U000100U42/30110U61/3√3/3010U2-1/3√3/3011U3-2/30001U1-1/3-√3/3101U51/3-√3/3111U700在Python中实现矢量定义# 基本电压矢量定义 U { 0: np.array([0, 0]), # U0 1: np.array([-1/3, -np.sqrt(3)/3]), # U1 2: np.array([-1/3, np.sqrt(3)/3]), # U2 3: np.array([-2/3, 0]), # U3 4: np.array([2/3, 0]), # U4 5: np.array([1/3, -np.sqrt(3)/3]), # U5 6: np.array([1/3, np.sqrt(3)/3]), # U6 7: np.array([0, 0]) # U7 }2. SVPWM算法实现步骤详解2.1 扇区判断算法判断目标矢量Uref所在扇区的关键步骤计算Uref在α-β坐标系的分量确定参考矢量所在的60°扇区def determine_sector(Ualpha, Ubeta): 判断参考矢量所在扇区(1-6) angle np.arctan2(Ubeta, Ualpha) if angle 0: angle 2*np.pi sector int(angle // (np.pi/3)) 1 return min(sector, 6) # 确保不超过6扇区更高效的实现方式避免三角函数计算def determine_sector_fast(Ualpha, Ubeta): 无三角函数的高效扇区判断 # 计算中间变量 v1 Ubeta v2 np.sqrt(3)/2 * Ualpha - 0.5 * Ubeta v3 -np.sqrt(3)/2 * Ualpha - 0.5 * Ubeta # 判断条件 if v1 0: a 1 else: a 0 if v2 0: b 1 else: b 0 if v3 0: c 1 else: c 0 # 扇区映射表 sector_map [0, 4, 6, 2, 3, 1, 5, 0] index a 2*b 4*c return sector_map[index]2.2 作用时间计算基于伏秒平衡原理计算相邻两个基本矢量的作用时间def calculate_time(Uref, sector, Udc, Ts): 计算相邻矢量和零矢量的作用时间 # 根据扇区选择相邻矢量 if sector 1: Ux, Uy U[4], U[6] elif sector 2: Ux, Uy U[6], U[2] elif sector 3: Ux, Uy U[2], U[3] elif sector 4: Ux, Uy U[3], U[1] elif sector 5: Ux, Uy U[1], U[5] elif sector 6: Ux, Uy U[5], U[4] # 计算作用时间 Tx (Uref[0]*Uy[1] - Uref[1]*Uy[0]) / (Ux[0]*Uy[1] - Ux[1]*Uy[0]) * Ts Ty (Uref[0]*Ux[1] - Uref[1]*Ux[0]) / (Uy[0]*Ux[1] - Uy[1]*Ux[0]) * Ts # 处理过调制情况 if Tx Ty Ts: Tx Tx * Ts / (Tx Ty) Ty Ty * Ts / (Tx Ty) T0 Ts - Tx - Ty return Tx, Ty, T02.3 七段式PWM波形生成七段式SVPWM通过对称分配零矢量时间可有效降低谐波含量。各扇区的开关序列如下扇区开关序列10-4-6-7-7-6-4-020-6-2-7-7-2-6-030-2-3-7-7-3-2-040-3-1-7-7-1-3-050-1-5-7-7-5-1-060-5-4-7-7-4-5-0实现代码def generate_pwm(sector, Tx, Ty, T0, Ts): 生成三相PWM占空比 # 零矢量时间均分 T0_2 T0 / 2 T7_2 T0 / 2 # 假设使用U0和U7各一半 # 各扇区时间分配 if sector 1: Ta T0_2 Tx Ty Tb T0_2 Ty Tc T0_2 elif sector 2: Ta T0_2 Tx Tb T0_2 Tx Ty Tc T0_2 elif sector 3: Ta T0_2 Tb T0_2 Tx Ty Tc T0_2 Ty elif sector 4: Ta T0_2 Tb T0_2 Tx Tc T0_2 Tx Ty elif sector 5: Ta T0_2 Ty Tb T0_2 Tc T0_2 Tx Ty elif sector 6: Ta T0_2 Tx Ty Tb T0_2 Tc T0_2 Tx # 转换为占空比 duty_a Ta / Ts duty_b Tb / Ts duty_c Tc / Ts return duty_a, duty_b, duty_c3. 完整SVPWM实现与可视化3.1 完整算法封装将上述步骤整合为完整的SVPWM类class SVPWM: def __init__(self, Udc300, fs10e3): self.Udc Udc # 直流母线电压 self.fs fs # 开关频率 self.Ts 1/fs # 开关周期 # 基本电压矢量定义 self.U { 0: np.array([0, 0]), 1: np.array([-1/3, -np.sqrt(3)/3]), 2: np.array([-1/3, np.sqrt(3)/3]), 3: np.array([-2/3, 0]), 4: np.array([2/3, 0]), 5: np.array([1/3, -np.sqrt(3)/3]), 6: np.array([1/3, np.sqrt(3)/3]), 7: np.array([0, 0]) } def clarke_transform(self, ua, ub, uc): 三相到α-β变换 alpha 2/3 * (ua - 0.5*ub - 0.5*uc) beta 2/3 * (np.sqrt(3)/2*ub - np.sqrt(3)/2*uc) return alpha, beta def determine_sector(self, Ualpha, Ubeta): 判断参考矢量所在扇区 v1 Ubeta v2 np.sqrt(3)/2 * Ualpha - 0.5 * Ubeta v3 -np.sqrt(3)/2 * Ualpha - 0.5 * Ubeta a 1 if v1 0 else 0 b 1 if v2 0 else 0 c 1 if v3 0 else 0 sector_map [0, 4, 6, 2, 3, 1, 5, 0] return sector_map[a 2*b 4*c] def calculate_time(self, Uref, sector): 计算作用时间 if sector 1: Ux, Uy self.U[4], self.U[6] elif sector 2: Ux, Uy self.U[6], self.U[2] elif sector 3: Ux, Uy self.U[2], self.U[3] elif sector 4: Ux, Uy self.U[3], self.U[1] elif sector 5: Ux, Uy self.U[1], self.U[5] elif sector 6: Ux, Uy self.U[5], self.U[4] Tx (Uref[0]*Uy[1] - Uref[1]*Uy[0]) / (Ux[0]*Uy[1] - Ux[1]*Uy[0]) * self.Ts Ty (Uref[0]*Ux[1] - Uref[1]*Ux[0]) / (Uy[0]*Ux[1] - Uy[1]*Ux[0]) * self.Ts if Tx Ty self.Ts: Tx Tx * self.Ts / (Tx Ty) Ty Ty * self.Ts / (Tx Ty) T0 self.Ts - Tx - Ty return Tx, Ty, T0 def generate_pwm(self, sector, Tx, Ty, T0): 生成PWM占空比 T0_2 T0 / 2 if sector 1: Ta T0_2 Tx Ty Tb T0_2 Ty Tc T0_2 elif sector 2: Ta T0_2 Tx Tb T0_2 Tx Ty Tc T0_2 elif sector 3: Ta T0_2 Tb T0_2 Tx Ty Tc T0_2 Ty elif sector 4: Ta T0_2 Tb T0_2 Tx Tc T0_2 Tx Ty elif sector 5: Ta T0_2 Ty Tb T0_2 Tc T0_2 Tx Ty elif sector 6: Ta T0_2 Tx Ty Tb T0_2 Tc T0_2 Tx return Ta/self.Ts, Tb/self.Ts, Tc/self.Ts def run(self, Ualpha, Ubeta): 执行完整SVPWM算法 sector self.determine_sector(Ualpha, Ubeta) Tx, Ty, T0 self.calculate_time(np.array([Ualpha, Ubeta]), sector) return self.generate_pwm(sector, Tx, Ty, T0)3.2 算法测试与波形可视化测试圆形旋转矢量的SVPWM生成import matplotlib.pyplot as plt # 参数设置 f 50 # 参考矢量频率(Hz) fs 10e3 # 开关频率(Hz) T 1/f # 周期(s) Udc 300 # 直流母线电压(V) Um 0.8 * Udc * np.sqrt(3)/3 # 参考矢量幅值(80%调制比) # 生成时间序列 t np.linspace(0, T, int(T*fs)) theta 2*np.pi*f*t # 初始化SVPWM svpwm SVPWM(Udc, fs) # 存储结果 duties [] # 运行仿真 for angle in theta: # 生成参考电压 Ualpha Um * np.cos(angle) Ubeta Um * np.sin(angle) # 执行SVPWM duty svpwm.run(Ualpha, Ubeta) duties.append(duty) duties np.array(duties) # 绘制结果 plt.figure(figsize(12, 6)) plt.plot(t, duties[:, 0], labelPhase A) plt.plot(t, duties[:, 1], labelPhase B) plt.plot(t, duties[:, 2], labelPhase C) plt.xlabel(Time (s)) plt.ylabel(Duty Cycle) plt.title(SVPWM Duty Cycles Over One Period) plt.legend() plt.grid(True) plt.show()4. 高级话题与性能优化4.1 过调制处理策略当参考电压矢量超出逆变器能输出的最大六边形边界时需要进行过调制处理线性过调制区参考矢量位于六边形内切圆与外接圆之间六边形模式参考矢量超出外接圆实现代码def overmodulation_handle(Ualpha, Ubeta, Udc): 过调制处理 Umax Udc * np.sqrt(3)/3 # 线性区最大幅值 Uhex Udc * 2/3 # 六边形顶点幅值 Uref np.array([Ualpha, Ubeta]) Uamp np.linalg.norm(Uref) angle np.arctan2(Ubeta, Ualpha) if Uamp Umax: return Ualpha, Ubeta # 线性区无需处理 elif Uamp Uhex: # 线性过调制区 k (Uhex - Umax) / (Uhex**2 - Umax**2) new_amp Umax k * (Uamp**2 - Umax**2) return new_amp * np.cos(angle), new_amp * np.sin(angle) else: # 六边形模式 sector int(angle // (np.pi/3)) 1 if sector 6: sector 1 # 找到最近的六边形顶点 vertex_angle (sector - 1) * np.pi/3 return Uhex * np.cos(vertex_angle), Uhex * np.sin(vertex_angle)4.2 死区时间补偿实际硬件中需要插入死区时间防止上下管直通这会导致输出电压畸变。补偿方法预测电流方向根据电流方向调整PWM占空比def deadtime_compensation(duty_a, duty_b, duty_c, current_sign, Tdead, Ts): 死区时间补偿 compensated_duty np.zeros(3) for i in range(3): if current_sign[i] 0: compensated_duty[i] duty[i] - Tdead/Ts else: compensated_duty[i] duty[i] Tdead/Ts # 限制在0-1之间 compensated_duty[i] np.clip(compensated_duty[i], 0, 1) return compensated_duty4.3 数字实现优化技巧查表法预计算常用参数减少实时计算量定点数运算在微控制器上使用定点数提高效率对称性利用利用扇区对称性减少计算量# 预计算扇区边界角度 sector_angles np.array([i * np.pi/3 for i in range(7)]) # 预计算基本矢量坐标 U_alpha np.array([0, 2/3, 1/3, -1/3, -2/3, -1/3, 1/3]) U_beta np.array([0, 0, np.sqrt(3)/3, np.sqrt(3)/3, 0, -np.sqrt(3)/3, -np.sqrt(3)/3])

更多文章