✅博主简介:擅长数据搜集与处理、建模仿真、程序设计、仿真代码、论文写作与指导,毕业论文、期刊论文经验交流。
✅成品或者定制,扫描文章底部微信二维码。
(1) 三相永磁同步电机开路故障特性分析与容错控制可行性研究
永磁同步电机作为新能源汽车驱动系统的核心动力元件,其运行可靠性直接关系到整车的安全性能和用户体验。在实际运行过程中,逆变器功率开关管开路故障和电机绕组断线故障是最常见的两类开路故障形式,这些故障会导致电机相电流波形畸变、电磁转矩产生显著脉动甚至完全丧失,严重影响车辆的动力性能和乘坐舒适性。本研究首先建立了三相永磁同步电机在正常工况下的数学模型,基于旋转坐标系下的电压方程和磁链方程分析了矢量控制的基本原理,阐明了定子电流矢量与转子磁场之间的相位关系对电磁转矩产生的影响机制。在此基础上,针对单管开路故障和断相故障两种典型故障模式,分别建立了故障状态下的等效电路模型和数学描述。当逆变器上桥臂某个开关管发生开路故障时,对应相绕组只能通过下桥臂开关管和续流二极管导通负向电流,正向电流被完全阻断,导致该相电流波形出现半波缺失现象。当电机绕组发生断线故障时,故障相电流完全为零,电机退化为两相运行状态。通过仿真分析和实验测试,详细研究了各类开路故障对电机相电流波形、电磁转矩脉动幅度和转速响应特性的具体影响规律。分析结果表明,在不增加硬件冗余的条件下,通过优化控制算法调整健全相电流的幅值和相位,可以在一定程度上补偿故障相电流缺失造成的转矩脉动,实现电机的容错运行。
(2) 基于最大转矩准则的开路故障容错电流控制方法
针对开路故障导致的电磁转矩脉动问题,本研究提出一种基于最大转矩准则的最优电流容错控制策略。该方法的核心思想是通过优化计算健全相电流的参考值,使故障后的平均电磁转矩尽可能接近故障前的设定值,同时抑制转矩脉动的幅度。在三相永磁同步电机中,电磁转矩由定子磁动势与转子永磁体磁场相互作用产生,当某相电流发生畸变或缺失时,定子合成磁动势的空间分布和时间演化规律都会发生改变,导致转矩产生脉动分量。为了补偿这种影响,需要根据故障类型和电机运行状态实时计算最优的健全相电流参考值。具体实现时,首先根据故障检测结果确定故障相和故障类型,然后以转矩恒定为优化目标建立约束方程,在满足电流约束条件下求解最优电流幅值和相位角。对于单管开路故障,故障相仍能导通单向电流,可以通过调整开关策略充分利用这部分电流贡献来减小其他健全相的负担。对于断相故障,故障相电流完全丧失,需要将全部转矩产生任务分配给剩余两相,这会导致健全相电流幅值显著增加。针对容错控制过程中可能出现的相电流过流问题,进一步提出了电流幅值限制优化策略,通过在优化目标函数中增加电流约束项,在保证转矩输出能力的前提下将各相电流峰值控制在安全范围内,避免因过流导致逆变器保护动作或电机绕组过热。
(3) 基于最大转矩铜耗比的容错控制优化与调制策略改进
在容错控制模式下,为了补偿故障相电流的缺失,健全相电流往往需要显著增大,这会导致电机绕组铜耗急剧上升,引发严重的发热问题,长时间运行可能损坏绕组绝缘甚至烧毁电机。针对这一问题,本研究提出一种基于最大转矩铜耗比准则的容错控制优化方法,在保证必要输出转矩的同时尽可能降低铜耗以控制电机温升。该方法在电流优化计算中引入铜耗与电磁功率之比作为性能指标,通过调整这一比值的限幅参数来平衡转矩输出能力和热管理需求。当驱动系统对转矩需求不是特别紧迫时,适当放松转矩跟踪精度要求以换取更低的铜耗,延长电机在容错模式下的持续运行时间。在实际工况中,电机温度上升速率与铜耗功率密切相关,通过建立铜耗功率与温升之间的热模型,可以根据当前电机温度和环境温度动态调整铜耗限幅参数,实现自适应的热保护功能。
import numpy as np from scipy.optimize import minimize, minimize_scalar from scipy.integrate import odeint class PMSMModel: def __init__(self): self.Rs = 0.5 self.Ld = 8.5e-3 self.Lq = 8.5e-3 self.psi_f = 0.175 self.p = 4 self.J = 0.01 self.B = 0.001 def voltage_equations(self, state, t, vd, vq, omega_e): id, iq = state did_dt = (vd - self.Rs * id + omega_e * self.Lq * iq) / self.Ld diq_dt = (vq - self.Rs * iq - omega_e * self.Ld * id - omega_e * self.psi_f) / self.Lq return [did_dt, diq_dt] def compute_torque(self, id, iq): return 1.5 * self.p * (self.psi_f * iq + (self.Ld - self.Lq) * id * iq) def compute_copper_loss(self, ia, ib, ic): return self.Rs * (ia**2 + ib**2 + ic**2) def abc_to_dq(self, ia, ib, ic, theta_e): cos_theta = np.cos(theta_e) sin_theta = np.sin(theta_e) cos_theta_m = np.cos(theta_e - 2*np.pi/3) sin_theta_m = np.sin(theta_e - 2*np.pi/3) cos_theta_p = np.cos(theta_e + 2*np.pi/3) sin_theta_p = np.sin(theta_e + 2*np.pi/3) id = 2/3 * (ia * cos_theta + ib * cos_theta_m + ic * cos_theta_p) iq = -2/3 * (ia * sin_theta + ib * sin_theta_m + ic * sin_theta_p) return id, iq def dq_to_abc(self, id, iq, theta_e): ia = id * np.cos(theta_e) - iq * np.sin(theta_e) ib = id * np.cos(theta_e - 2*np.pi/3) - iq * np.sin(theta_e - 2*np.pi/3) ic = id * np.cos(theta_e + 2*np.pi/3) - iq * np.sin(theta_e + 2*np.pi/3) return ia, ib, ic class FaultDetector: def __init__(self, threshold=0.1): self.threshold = threshold self.fault_status = {'phase_a': False, 'phase_b': False, 'phase_c': False} self.fault_type = None def detect_open_circuit(self, ia, ib, ic, ia_ref, ib_ref, ic_ref): error_a = np.abs(ia - ia_ref) error_b = np.abs(ib - ib_ref) error_c = np.abs(ic - ic_ref) if np.max(np.abs(ia)) < self.threshold and np.max(np.abs(ia_ref)) > self.threshold: self.fault_status['phase_a'] = True if np.max(np.abs(ib)) < self.threshold and np.max(np.abs(ib_ref)) > self.threshold: self.fault_status['phase_b'] = True if np.max(np.abs(ic)) < self.threshold and np.max(np.abs(ic_ref)) > self.threshold: self.fault_status['phase_c'] = True return self.fault_status def identify_fault_type(self, phase_current, expected_current): positive_half = phase_current[expected_current > 0] negative_half = phase_current[expected_current < 0] if np.mean(np.abs(positive_half)) < self.threshold and np.mean(np.abs(negative_half)) > self.threshold: return 'upper_switch_open' elif np.mean(np.abs(negative_half)) < self.threshold and np.mean(np.abs(positive_half)) > self.threshold: return 'lower_switch_open' elif np.mean(np.abs(phase_current)) < self.threshold: return 'phase_open' return 'normal' class MaxTorqueFaultTolerantController: def __init__(self, motor): self.motor = motor self.i_max = 20.0 def compute_fault_tolerant_currents_phase_open(self, torque_ref, theta_e, fault_phase): def objective(params): i_amp, phase_offset = params if fault_phase == 'a': ib = i_amp * np.sin(theta_e - 2*np.pi/3 + phase_offset) ic = i_amp * np.sin(theta_e + 2*np.pi/3 + phase_offset) ia = -(ib + ic) elif fault_phase == 'b': ia = i_amp * np.sin(theta_e + phase_offset) ic = i_amp * np.sin(theta_e + 2*np.pi/3 + phase_offset) ib = -(ia + ic) else: ia = i_amp * np.sin(theta_e + phase_offset) ib = i_amp * np.sin(theta_e - 2*np.pi/3 + phase_offset) ic = -(ia + ib) id, iq = self.motor.abc_to_dq(ia, ib, ic, theta_e) torque = self.motor.compute_torque(id, iq) return (torque - torque_ref)**2 result = minimize(objective, [10.0, 0.0], bounds=[(0, self.i_max), (-np.pi, np.pi)]) return result.x def compute_optimized_currents_with_limit(self, torque_ref, theta_e, fault_phase): def objective(params): i_amp, phase_offset = params if fault_phase == 'a': ib = i_amp * np.sin(theta_e - 2*np.pi/3 + phase_offset) ic = i_amp * np.sin(theta_e + 2*np.pi/3 + phase_offset) ia = 0 elif fault_phase == 'b': ia = i_amp * np.sin(theta_e + phase_offset) ic = i_amp * np.sin(theta_e + 2*np.pi/3 + phase_offset) ib = 0 else: ia = i_amp * np.sin(theta_e + phase_offset) ib = i_amp * np.sin(theta_e - 2*np.pi/3 + phase_offset) ic = 0 if max(abs(ia), abs(ib), abs(ic)) > self.i_max: return 1e6 id, iq = self.motor.abc_to_dq(ia, ib, ic, theta_e) torque = self.motor.compute_torque(id, iq) return (torque - torque_ref)**2 result = minimize(objective, [10.0, 0.0], bounds=[(0, self.i_max * 1.5), (-np.pi, np.pi)]) return result.x class MaxTorqueCopperLossRatioController: def __init__(self, motor): self.motor = motor self.i_max = 20.0 self.copper_loss_limit = 500.0 def compute_mtclr_currents(self, torque_ref, theta_e, fault_phase, lambda_weight=0.1): def objective(params): i_amp, phase_offset = params if fault_phase == 'a': ib = i_amp * np.sin(theta_e - 2*np.pi/3 + phase_offset) ic = i_amp * np.sin(theta_e + 2*np.pi/3 + phase_offset) ia = 0 elif fault_phase == 'b': ia = i_amp * np.sin(theta_e + phase_offset) ic = i_amp * np.sin(theta_e + 2*np.pi/3 + phase_offset) ib = 0 else: ia = i_amp * np.sin(theta_e + phase_offset) ib = i_amp * np.sin(theta_e - 2*np.pi/3 + phase_offset) ic = 0 id, iq = self.motor.abc_to_dq(ia, ib, ic, theta_e) torque = self.motor.compute_torque(id, iq) copper_loss = self.motor.compute_copper_loss(ia, ib, ic) torque_error = (torque - torque_ref)**2 loss_penalty = lambda_weight * copper_loss current_penalty = 0 if max(abs(ia), abs(ib), abs(ic)) > self.i_max: current_penalty = 1e6 return torque_error + loss_penalty + current_penalty result = minimize(objective, [10.0, 0.0], bounds=[(0, self.i_max * 1.5), (-np.pi, np.pi)]) return result.x def adaptive_copper_loss_control(self, torque_ref, theta_e, fault_phase, motor_temp, temp_limit=80): if motor_temp < temp_limit * 0.7: lambda_weight = 0.05 elif motor_temp < temp_limit * 0.9: lambda_weight = 0.2 else: lambda_weight = 0.5 return self.compute_mtclr_currents(torque_ref, theta_e, fault_phase, lambda_weight) class ModifiedSVPWM: def __init__(self, Vdc, fs): self.Vdc = Vdc self.Ts = 1 / fs def compute_sector(self, valpha, vbeta): v1 = vbeta v2 = np.sqrt(3)/2 * valpha - 0.5 * vbeta v3 = -np.sqrt(3)/2 * valpha - 0.5 * vbeta a = 1 if v1 > 0 else 0 b = 1 if v2 > 0 else 0 c = 1 if v3 > 0 else 0 return a + 2*b + 4*c def compute_duty_cycles_normal(self, valpha, vbeta): sector = self.compute_sector(valpha, vbeta) k = np.sqrt(3) * self.Ts / self.Vdc if sector == 3: t1 = k * (np.sqrt(3)/2 * valpha + 0.5 * vbeta) t2 = k * vbeta elif sector == 1: t1 = k * vbeta t2 = k * (-np.sqrt(3)/2 * valpha + 0.5 * vbeta) elif sector == 5: t1 = k * (-np.sqrt(3)/2 * valpha + 0.5 * vbeta) t2 = k * (-np.sqrt(3)/2 * valpha - 0.5 * vbeta) elif sector == 4: t1 = k * (-np.sqrt(3)/2 * valpha - 0.5 * vbeta) t2 = k * (-vbeta) elif sector == 6: t1 = k * (-vbeta) t2 = k * (np.sqrt(3)/2 * valpha - 0.5 * vbeta) else: t1 = k * (np.sqrt(3)/2 * valpha - 0.5 * vbeta) t2 = k * (np.sqrt(3)/2 * valpha + 0.5 * vbeta) t0 = self.Ts - t1 - t2 return t1, t2, t0, sector def compute_fault_tolerant_pwm(self, valpha, vbeta, fault_phase): t1, t2, t0, sector = self.compute_duty_cycles_normal(valpha, vbeta) da = db = dc = 0.5 if fault_phase == 'a': da = 0 db = (t1 + t0/2) / self.Ts dc = (t2 + t0/2) / self.Ts elif fault_phase == 'b': da = (t1 + t0/2) / self.Ts db = 0 dc = (t2 + t0/2) / self.Ts else: da = (t1 + t0/2) / self.Ts db = (t2 + t0/2) / self.Ts dc = 0 return np.clip(da, 0, 1), np.clip(db, 0, 1), np.clip(dc, 0, 1) class FaultTolerantDriveSystem: def __init__(self): self.motor = PMSMModel() self.detector = FaultDetector() self.mt_controller = MaxTorqueFaultTolerantController(self.motor) self.mtclr_controller = MaxTorqueCopperLossRatioController(self.motor) self.svpwm = ModifiedSVPWM(Vdc=300, fs=10000) self.fault_phase = None self.control_mode = 'normal' def run_simulation(self, torque_ref, duration, dt=1e-4): steps = int(duration / dt) omega_m = 100 theta_e = 0 results = {'time': [], 'torque': [], 'ia': [], 'ib': [], 'ic': [], 'copper_loss': []} for k in range(steps): t = k * dt theta_e = (theta_e + omega_m * self.motor.p * dt) % (2 * np.pi) if self.control_mode == 'normal': iq_ref = torque_ref / (1.5 * self.motor.p * self.motor.psi_f) ia, ib, ic = self.motor.dq_to_abc(0, iq_ref, theta_e) elif self.control_mode == 'max_torque': params = self.mt_controller.compute_optimized_currents_with_limit( torque_ref, theta_e, self.fault_phase) i_amp, phase_offset = params if self.fault_phase == 'a': ia = 0 ib = i_amp * np.sin(theta_e - 2*np.pi/3 + phase_offset) ic = i_amp * np.sin(theta_e + 2*np.pi/3 + phase_offset) elif self.fault_phase == 'b': ia = i_amp * np.sin(theta_e + phase_offset) ib = 0 ic = i_amp * np.sin(theta_e + 2*np.pi/3 + phase_offset) else: ia = i_amp * np.sin(theta_e + phase_offset) ib = i_amp * np.sin(theta_e - 2*np.pi/3 + phase_offset) ic = 0 else: params = self.mtclr_controller.adaptive_copper_loss_control( torque_ref, theta_e, self.fault_phase, motor_temp=60) i_amp, phase_offset = params if self.fault_phase == 'a': ia = 0 ib = i_amp * np.sin(theta_e - 2*np.pi/3 + phase_offset) ic = i_amp * np.sin(theta_e + 2*np.pi/3 + phase_offset) elif self.fault_phase == 'b': ia = i_amp * np.sin(theta_e + phase_offset) ib = 0 ic = i_amp * np.sin(theta_e + 2*np.pi/3 + phase_offset) else: ia = i_amp * np.sin(theta_e + phase_offset) ib = i_amp * np.sin(theta_e - 2*np.pi/3 + phase_offset) ic = 0 id, iq = self.motor.abc_to_dq(ia, ib, ic, theta_e) torque = self.motor.compute_torque(id, iq) copper_loss = self.motor.compute_copper_loss(ia, ib, ic) results['time'].append(t) results['torque'].append(torque) results['ia'].append(ia) results['ib'].append(ib) results['ic'].append(ic) results['copper_loss'].append(copper_loss) return results def switch_to_fault_tolerant_mode(self, fault_phase, mode='max_torque'): self.fault_phase = fault_phase self.control_mode = mode如有问题,可以直接沟通
👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇