固定翼无人机自主飞行仿真:级联PID、GWO/PSO调参与BMS集成
发布时间:2026/10/1 20:34:56来源:尧图网络
1. 固定翼无人机自主飞行的控制难点到底在哪固定翼无人机的自主飞行和四旋翼那种“原地悬停、想停就停”的逻辑完全不是一回事。固定翼一旦升空就必须保持一定的空速才能产生升力没有“悬停”这个选项这意味着它的姿态控制、高度控制、航向控制之间存在极强的耦合关系。你拉杆抬头速度会掉你加油门高度又会飘你压坡度转弯升力分量被分走高度又往下掉。这种“牵一发动全身”的特性决定了固定翼的控制系统不能靠一个单回路PID打天下。我最早接触固定翼仿真的时候犯过一个很典型的错误把俯仰、滚转、偏航三个通道各用一个PID独立控制结果飞机在空中像喝醉了酒一样来回振荡。后来才明白固定翼的姿态回路和位置回路之间存在时间尺度上的巨大差异——姿态回路的响应在几十毫秒级别而位置回路的响应在秒级别。如果把它们放在同一个回路里用同一个PID去调要么姿态响应太慢导致飞机失控要么位置响应太快导致超调振荡。这就是级联PID控制要解决的核心问题。级联PID的思路其实很朴素把控制任务按响应速度分成内外两层。外环负责“慢”的任务比如高度保持、航向跟踪、速度控制内环负责“快”的任务比如俯仰角速率、滚转角速率、偏航角速率的稳定。外环的输出不作为最终舵面指令而是作为内环的期望值传给内环。内环再根据当前角速率与期望值的偏差快速输出舵面偏转量。这样一来慢的任务不会拖累快的任务快的任务也不会因为外环的抖动而频繁动作。但级联PID带来一个很现实的问题参数太多了。一个典型的固定翼级联PID控制系统俯仰通道有外环角度PID和内环角速率PID滚转通道同样有内外两环偏航通道还有协调转弯的耦合项再加上高度回路和速度回路需要整定的参数轻松超过十五个。手工调参我试过一个下午能调出一组“勉强能飞”的参数就算运气好了而且换一个飞行条件比如从巡航速度换到爬升速度参数就得重新调。这就是为什么GWO灰狼优化算法和PSO粒子群优化算法会被引入到这个问题里——用启发式优化算法自动搜索PID参数把人从反复试错中解放出来。再往下想一层固定翼无人机的自主飞行不只是“飞得稳”还要“飞得久”。续航能力直接取决于电池管理系统的效率。BMS电池管理系统在无人机上的角色远不止“看个电压”那么简单。它要实时监控每一片电芯的电压、温度、放电电流要做均衡管理防止某片电芯过放要估算剩余电量SOC让飞控知道还能飞多久还要在异常时触发保护逻辑。如果BMS和飞控之间的数据交互没做好飞控可能拿到一个滞后甚至错误的电量信息导致返航决策失误。把这四件事——级联PID控制、BMS集成、GWO调参、PSO调参——放在一个MATLAB仿真框架里就是一套完整的固定翼无人机自主飞行验证平台。下面我按自己实际搭建这套仿真的顺序把每个环节的关键细节拆开讲。2. 级联PID回路的架构设计与通道分配2.1 为什么固定翼必须用级联结构而不是单回路单回路PID在固定翼上的根本问题是时间尺度不匹配。固定翼的俯仰角速率响应时间常数通常在0.05到0.1秒之间而高度响应的时间常数在2到5秒之间两者差了将近两个数量级。如果你用一个PID同时控制高度和俯仰角PID的输出既要快速抑制俯仰振荡又要平滑地跟踪高度指令这两个需求在频域上是矛盾的。快速抑制振荡需要高带宽平滑跟踪高度需要低带宽一个PID不可能同时满足。级联结构把这个矛盾拆开了。外环高度回路用低带宽PID输出一个“期望俯仰角”这个期望值变化很平缓不会引起内环的剧烈反应。内环俯仰角速率回路用高带宽PID快速跟踪外环给的期望俯仰角同时抑制外界扰动比如阵风引起的角速率波动。两层各司其职互不干扰。我在Simulink里搭这套结构的时候习惯把每个通道的内外环分别封装成子系统这样调试的时候可以单独把内环拎出来做阶跃响应测试确认内环带宽足够之后再把外环接上去。这个顺序很重要——如果内环还没调好就接外环外环的输出会被内环的振荡放大整个系统直接发散。2.2 俯仰、滚转、偏航三个通道的级联细节俯仰通道的级联结构是高度外环 → 俯仰角中环 → 俯仰角速率内环。注意这里其实是三层但通常说的“级联PID”在固定翼上至少是两层俯仰通道因为要控制高度所以多了一层。高度外环的输入是期望高度与实际高度的偏差输出是期望俯仰角俯仰角中环的输入是期望俯仰角与实际俯仰角的偏差输出是期望俯仰角速率俯仰角速率内环的输入是期望角速率与实际角速率的偏差输出是升降舵偏转量。滚转通道相对简单一些航向外环 → 滚转角中环 → 滚转角速率内环。航向外环根据期望航向与实际航向的偏差输出期望滚转角滚转角中环输出期望滚转角速率滚转角速率内环输出副翼偏转量。这里有一个容易忽略的点固定翼转弯靠的是压坡度产生侧向力而不是像四旋翼那样直接偏航。所以航向控制本质上是通过滚转来实现的偏航通道主要做协调转弯消除侧滑。偏航通道的级联结构是侧滑角外环 → 偏航角速率内环。侧滑角外环的输入是期望侧滑角通常为零与实际侧滑角的偏差输出是期望偏航角速率偏航角速率内环输出方向舵偏转量。偏航通道在正常飞行中动作量很小但在起飞爬升和着陆进近阶段侧风修正全靠它。通道外环中环内环最终输出俯仰高度PID俯仰角PID俯仰角速率PID升降舵滚转航向PID滚转角PID滚转角速率PID副翼偏航侧滑角PID无偏航角速率PID方向舵速度速度PID无无油门2.3 内环带宽与外环带宽的比例关系级联PID有一个经验法则内环带宽至少是外环带宽的5到10倍。这个比例不是随便定的它来自频域分析中的“奇异值分离”原则。如果内外环带宽太接近两个回路的动态会相互耦合导致系统在某些频率上出现谐振峰表现为飞机在特定飞行状态下出现持续振荡。我在Simulink里验证带宽比例的方法是先单独给内环做频率响应扫描找到内环的-3dB带宽然后接上外环再扫一次外环的-3dB带宽确认两者比值在5以上。如果比值不够要么提高内环增益但要注意舵面饱和要么降低外环增益但会影响跟踪速度。实际调下来俯仰内环带宽设在5到8 rad/s比较合适外环设在0.5到1 rad/s滚转内环可以稍快一些设在8到12 rad/s外环设在1到2 rad/s。注意带宽比例不是越大越好。内环带宽过高会导致舵机频繁动作加速舵机磨损同时会放大传感器噪声。我在一次仿真中把滚转内环带宽设到了20 rad/s结果舵面指令里全是高频抖动虽然飞机姿态看起来“很稳”但舵机模型里的电流已经爆表了。3. GWO与PSO在PID参数自动整定中的实战对比3.1 把PID调参转化为优化问题的数学建模手工调参的本质是“试”而优化算法的本质是“搜”。要把PID调参交给GWO或PSO第一步是定义一个目标函数让算法知道什么样的参数算“好”。固定翼级联PID的目标函数通常由三部分组成跟踪误差的积分ITAE或ISE、控制量的变化率防止舵面抖动、超调量惩罚。我常用的目标函数形式是这样的function J pid_objective(x) % x [Kp_pitch, Ki_pitch, Kd_pitch, Kp_roll, Ki_roll, Kd_roll, ...] assignin(base, pid_params, x); sim(fixed_wing_cascade_pid.slx); error logsout.get(tracking_error).Values.Data; control_rate logsout.get(control_signal).Values.Data; overshoot max(abs(error)) - abs(error(end)); w1 1.0; % 跟踪误差权重 w2 0.1; % 控制量变化率权重 w3 0.5; % 超调惩罚权重 J w1 * trapz(abs(error)) w2 * trapz(abs(diff(control_rate))) w3 * max(0, overshoot); end这个目标函数里ITAE项让算法倾向于快速消除误差控制量变化率项让算法避免产生剧烈抖动的控制信号超调惩罚项让算法不要为了追求快速响应而牺牲稳定性。三个权重系数的选取需要根据具体机型调整我一般先把w2和w3设小一点让算法先找到能稳定跟踪的解再逐步增大w2和w3来优化控制品质。3.2 GWO的搜索机制与参数设置GWO灰狼优化模拟的是灰狼群体的等级制度和狩猎行为。算法里有四类狼Alpha最优解、Beta次优解、Delta第三优解、Omega其余候选解。每次迭代中Omega狼根据Alpha、Beta、Delta的位置来更新自己的位置逐步向猎物最优解逼近。GWO的核心参数只有两个种群规模N和最大迭代次数T。我一般设N30T100。这个规模对于15到20维的PID参数优化问题足够了。GWO的收敛因子a从2线性递减到0控制着搜索范围从全局探索逐步过渡到局部开发。GWO在PID调参上的优势是收敛速度快通常在前20次迭代就能找到一个不错的解。但它的缺点是容易早熟——如果初始种群分布不好可能很快收敛到一个局部最优。我的应对方法是跑三次GWO每次用不同的随机种子然后取三次结果中目标函数最小的那组参数。% GWO主循环核心代码 for t 1:max_iter a 2 - 2 * t / max_iter; for i 1:pop_size for j 1:dim r1 rand(); r2 rand(); A1 2 * a * r1 - a; C1 2 * r2; D_alpha abs(C1 * alpha_pos(j) - positions(i,j)); X1 alpha_pos(j) - A1 * D_alpha; r1 rand(); r2 rand(); A2 2 * a * r1 - a; C2 2 * r2; D_beta abs(C2 * beta_pos(j) - positions(i,j)); X2 beta_pos(j) - A2 * D_beta; r1 rand(); r2 rand(); A3 2 * a * r1 - a; C3 2 * r2; D_delta abs(C3 * delta_pos(j) - positions(i,j)); X3 delta_pos(j) - A3 * D_delta; positions(i,j) (X1 X2 X3) / 3; end end % 边界处理与适应度更新 end3.3 PSO的搜索机制与参数设置PSO粒子群优化模拟的是鸟群觅食行为。每个粒子有自己的位置和速度位置代表一组PID参数速度代表参数更新的方向和步长。粒子根据两个“经验”来更新自己个体历史最优位置pbest和群体历史最优位置gbest。PSO的核心参数有三个惯性权重w、个体学习因子c1、群体学习因子c2。我常用的配置是w从0.9线性递减到0.4c1c22.0。惯性权重递减是为了让算法前期侧重全局探索后期侧重局部开发。PSO在PID调参上的优势是搜索覆盖面广因为粒子之间共享信息不容易陷入局部最优。但它的收敛速度通常比GWO慢需要更多迭代次数。我一般设N40T150。% PSO主循环核心代码 for t 1:max_iter w 0.9 - 0.5 * t / max_iter; for i 1:pop_size % 更新速度 velocities(i,:) w * velocities(i,:) ... c1 * rand() * (pbest(i,:) - positions(i,:)) ... c2 * rand() * (gbest - positions(i,:)); % 限制速度 velocities(i,:) max(min(velocities(i,:), v_max), -v_max); % 更新位置 positions(i,:) positions(i,:) velocities(i,:); % 边界处理 positions(i,:) max(min(positions(i,:), ub), lb); % 评估适应度 fitness(i) pid_objective(positions(i,:)); % 更新pbest和gbest if fitness(i) pbest_fitness(i) pbest(i,:) positions(i,:); pbest_fitness(i) fitness(i); end if fitness(i) gbest_fitness gbest positions(i,:); gbest_fitness fitness(i); end end end3.4 两种算法在同一组PID参数上的实测表现我在同一套固定翼模型上跑了GWO和PSO各十次每次独立运行记录目标函数收敛值和最终PID参数下的阶跃响应指标。结果如下指标GWO均值PSO均值收敛迭代次数2347最终目标函数值0.8470.812俯仰超调量8.2%6.5%滚转超调量11.4%9.1%高度跟踪稳态误差0.32 m0.28 m单次运行耗时18 min35 min从数据上看GWO收敛更快但PSO最终找到的解略优。我的实际做法是先用GWO快速找到一个可行解把这个解作为PSO的初始种群中心再用PSO做精细搜索。这种混合策略比单独用任何一种算法都好收敛时间比纯PSO少一半最终解的质量比纯GWO高一个档次。提示优化算法跑出来的PID参数一定要做鲁棒性验证。我习惯在标称模型上跑完之后把气动系数扰动±20%、质量扰动±10%、舵机时间常数扰动±30%再跑一遍看目标函数退化多少。如果退化超过50%说明这组参数过拟合了得重新调目标函数的权重。4. BMS集成从电芯监控到飞控决策的数据链路4.1 无人机BMS和地面BMS的本质区别地面储能系统的BMS工作环境相对稳定温度变化慢负载变化也慢所以它的均衡策略和SOC估算算法可以做得比较“重”——用复杂的卡尔曼滤波、用高精度的开路电压查表都没问题。但无人机BMS完全是另一回事。无人机BMS面临三个地面系统不会遇到的挑战第一放电倍率高巡航时可能3C到5C爬升时瞬间能到10C以上电芯电压在负载突变时会剧烈波动SOC估算如果只靠电压查表误差能到20%以上第二温度变化剧烈起飞前电池可能在30度爬升到高空后环境温度可能降到零下电芯内阻变化很大第三重量敏感BMS硬件不能做太重采样精度和采样频率都要在重量和性能之间做取舍。我在仿真里搭建BMS模型的时候用的是二阶RC等效电路模型。这个模型把电芯分成三个部分开路电压源、欧姆内阻R0、两个RC并联环节分别模拟电化学极化和浓度极化。相比一阶RC模型二阶模型在高倍率放电时的电压预测精度能提高5%到8%。% 二阶RC等效电路模型的核心方程 % 状态变量: SOC, V_RC1, V_RC2 function [dV_dt, V_terminal] battery_model(I, SOC, V_RC1, V_RC2, params) R0 params.R0; R1 params.R1; C1 params.C1; R2 params.R2; C2 params.C2; Q params.Q; % 额定容量 dSOC_dt -I / (3600 * Q); dV_RC1_dt -V_RC1 / (R1 * C1) I / C1; dV_RC2_dt -V_RC2 / (R2 * C2) I / C2; OCV lookup_ocv(SOC); % 开路电压查表 V_terminal OCV - I * R0 - V_RC1 - V_RC2; dV_dt [dSOC_dt; dV_RC1_dt; dV_RC2_dt]; end4.2 SOC估算安时积分与开路电压的融合策略SOC估算是BMS最核心的功能也是最容易出问题的环节。安时积分法简单直接但有两个致命缺点初始SOC不知道而且电流传感器的零漂会随时间累积误差。开路电压法在静置时很准但无人机飞行中根本没有静置的机会。我的做法是安时积分为主开路电压为辅用扩展卡尔曼滤波EKF做融合。具体来说把SOC作为状态变量端电压作为观测变量用EKF在线估计SOC。当无人机在地面待命时电流为零用开路电压查表修正SOC初值飞行中则完全依赖EKF的预测-更新循环。在Simulink里实现EKF的时候需要注意噪声协方差矩阵Q和R的整定。Q太小会导致滤波器对模型误差不敏感SOC估计滞后Q太大会导致SOC估计噪声大。我一般设Q的对角元素在1e-6到1e-4之间R根据电压传感器的实际噪声水平设通常在1e-3到1e-2之间。4.3 电池均衡策略在仿真中的实现无人机电池组通常是4S到6S4到6片电芯串联电芯之间的不一致性会导致木桶效应——最弱的那片电芯先到截止电压整组电池就得停止放电其他电芯还有电但用不了。均衡管理就是要把强电芯的电量“搬”一部分给弱电芯或者至少把强电芯的多余电量消耗掉。仿真里我实现的是被动均衡模型每片电芯并联一个均衡电阻和开关当某片电芯电压高于组内最低电压超过阈值比如50mV时开关闭合该电芯通过电阻放电。被动均衡的优点是电路简单、可靠性高缺点是能量全部变成热耗散了效率低。主动均衡用电感或电容把电量从强电芯搬到弱电芯效率高但电路复杂在小型无人机上用得少。% 被动均衡逻辑 function balance_switch passive_balance(cell_voltages, threshold) min_v min(cell_voltages); balance_switch zeros(size(cell_voltages)); for i 1:length(cell_voltages) if cell_voltages(i) - min_v threshold balance_switch(i) 1; end end end4.4 BMS数据如何影响飞控的返航决策BMS给飞控提供的不只是“还剩多少电”而是一个综合的续航能力评估。飞控需要知道当前剩余电量下以巡航速度还能飞多少公里如果遇到逆风续航会缩短多少返航点距离当前位置多远这些信息综合起来才能决定是继续执行任务还是立即返航。我在仿真里设计了一个简单的返航决策逻辑BMS每秒给飞控发送一次SOC和可用容量飞控根据当前巡航速度估算剩余航程如果剩余航程小于返航距离的1.3倍30%安全余量就触发返航。这个1.3的系数不是拍脑袋定的它考虑了风速变化、电池老化、温度影响等因素。实际飞行中我建议这个系数不要低于1.2否则遇到突发逆风可能回不来。注意BMS和飞控之间的通信延迟在仿真里很容易被忽略。我一开始没加通信延迟BMS数据直接进飞控结果仿真里返航决策很准。后来加了50ms的通信延迟发现SOC估计的相位滞后导致返航触发晚了将近10秒在高速巡航下就是几百米的距离差。所以仿真里一定要加通信延迟模型哪怕只是一个简单的传输延迟环节。5. 在Simulink里把四个模块串起来的工程细节5.1 仿真步长与求解器的选择固定翼级联PID仿真里内环角速率回路的带宽在5到12 rad/s对应的周期在0.5到1.2秒。但舵机模型的响应时间常数通常在0.02到0.05秒BMS模型的RC环节时间常数在10到100秒。整个系统的动态范围跨越了三个数量级这对求解器是个考验。我试过用变步长求解器ode45结果在舵机动作剧烈的时候步长被压到1e-5秒仿真跑10秒实际花了3分钟。后来改用定步长求解器ode4步长设1ms仿真速度提升了将近20倍精度也够用。1ms的步长对于舵机模型时间常数20ms以上和BMS模型时间常数10s以上都足够对于内环角速率回路周期0.5s以上也绰绰有余。如果你的模型里包含了电力电子开关比如BMS主动均衡里的MOSFET开关那步长得进一步降到10微秒级别这时候建议把电力电子部分单独用一个高速求解器跑和飞控动力学部分做联合仿真。5.2 模块间的数据接口与单位统一Simulink仿真里最常见的低级错误就是单位不统一。飞控输出的舵面指令是角度度舵机模型期望的输入是弧度BMS输出的电流是安培但电芯模型里的容量是毫安时高度指令是米但气压计模型输出的是帕斯卡。这些单位问题在单独测试每个模块的时候不会暴露一旦串起来就各种发散。我的做法是在Simulink模型的最顶层定义一套全局单位制所有模块的输入输出都标注单位用Simulink的Unit属性做检查。具体来说角度统一用弧度电流统一用安培容量统一用安时高度统一用米速度统一用米每秒。BMS的SOC用0到1的小数不用百分比。这样虽然写模型的时候麻烦一点但后期调试省了大量时间。5.3 用MATLAB脚本批量跑仿真的技巧GWO和PSO调参需要跑几百次仿真如果每次都手动打开Simulink点运行效率太低。我用的是sim命令配合parsim做并行批量仿真。% 批量仿真配置 simIn Simulink.SimulationInput(fixed_wing_cascade_pid); simIn simIn.setVariable(pid_params, candidate_params); simIn simIn.setModelParameter(StopTime, 30); simIn simIn.setModelParameter(SaveOutput, on); % 并行跑多个候选参数 params_list cell(1, pop_size); for i 1:pop_size params_list{i} simIn.setVariable(pid_params, positions(i,:)); end simOut parsim(params_list, ShowProgress, on);用parsim的时候要注意每个并行worker都需要独立加载Simulink模型如果模型里有To Workspace模块数据会冲突。我的做法是把所有需要记录的数据通过logsout输出然后在parsim的postSimFcn里统一提取。5.4 仿真结果的可视化与自动报告生成跑完几百次仿真之后如果只看目标函数值很难判断哪组参数真的好。我习惯把每次仿真的关键曲线俯仰角响应、高度响应、SOC变化、舵面指令自动保存成图片然后生成一个HTML报告把所有候选参数的曲线放在一起对比。% 自动生成对比图 figure(Position, [100, 100, 1200, 800]); subplot(2,2,1); for i 1:num_runs plot(time{i}, pitch_angle{i}); hold on; end legend(Run 1, Run 2, Run 3); title(俯仰角响应对比); xlabel(时间 (s)); ylabel(俯仰角 (deg));这个报告在调参后期特别有用。当目标函数值接近的时候曲线形态的差异就成了决策依据。我遇到过两组参数目标函数值只差0.01但一组在爬升阶段有轻微振荡另一组没有最后选了没有振荡的那组。6. 仿真跑通之后实飞前必须做的几项验证6.1 蒙特卡洛扰动测试仿真里跑得再好实飞环境也有大量不确定性。我在实飞前一定会做蒙特卡洛测试在标称模型上叠加随机扰动跑100次以上看系统的失效概率。扰动源包括气动系数±20%均匀分布、质量与惯量±10%、舵机时间常数±30%、传感器噪声按实际传感器手册的噪声密度、风扰动Dryden风模型风速5到15 m/s。每次跑完记录是否出现姿态角超过安全边界、舵面是否饱和、SOC估计误差是否超过10%。如果100次测试里有超过5次出现异常说明参数鲁棒性不够得回到优化环节重新调目标函数把鲁棒性惩罚项加进去。6.2 传感器故障注入测试BMS和飞控的传感器都可能故障。我在仿真里会注入几种典型故障电压传感器零漂、电流传感器增益误差、温度传感器断线、IMU陀螺仪偏置突变。看系统能不能在故障发生后保持稳定或者至少能安全返航。有一次测试中我注入了电流传感器增益误差20%的故障结果SOC估计在10分钟后偏高了15%飞控以为还能飞实际上电池已经快没电了。后来在BMS里加了电流传感器在线校准逻辑当无人机在地面待命、电流为零时自动校准电流传感器的零偏当电池静置超过5分钟时用开路电压反推SOC和安时积分的结果对比如果偏差超过5%就修正安时积分的累积误差。6.3 从仿真参数到飞控代码的移植注意事项仿真里用的PID参数是连续域的但飞控代码里跑的是离散PID。移植的时候要做离散化我一般用Tustin变换双线性变换采样周期和飞控主循环周期一致通常400Hz即2.5ms。离散化之后积分项和微分项的实现方式也要注意。积分项要用抗积分饱和clamping或back-calculation微分项要用不完全微分加一个低通滤波器否则实飞时积分饱和和微分噪声会让你怀疑人生。// 离散PID实现示例抗积分饱和 不完全微分 typedef struct { float Kp, Ki, Kd; float integral; float prev_error; float prev_derivative; float integral_max; float derivative_filter_coeff; } PID_Controller; float PID_Update(PID_Controller *pid, float setpoint, float measurement, float dt) { float error setpoint - measurement; // 比例项 float P pid-Kp * error; // 积分项抗饱和 pid-integral pid-Ki * error * dt; if (pid-integral pid-integral_max) pid-integral pid-integral_max; if (pid-integral -pid-integral_max) pid-integral -pid-integral_max; float I pid-integral; // 微分项不完全微分 float derivative (error - pid-prev_error) / dt; float filtered_derivative pid-derivative_filter_coeff * pid-prev_derivative (1 - pid-derivative_filter_coeff) * derivative; float D pid-Kd * filtered_derivative; pid-prev_error error; pid-prev_derivative filtered_derivative; return P I D; }移植完之后一定要做半实物仿真HIL把飞控代码烧到真实飞控板上和Simulink里的飞机模型做闭环。HIL能发现很多纯仿真发现不了的问题比如代码执行时间超限、浮点精度不够、通信协议解析错误。7. 个人在实际搭建这套仿真中的几点体会这套仿真我从头到尾搭了三遍第一遍用纯手工调参第二遍加了GWO第三遍才把BMS和PSO都集成进来。踩过的坑不少说几个印象最深的。第一个坑是级联PID的初始化。Simulink里如果内外环同时使能而内环的初始状态和外环的初始输出不匹配仿真第一步就会发散。我的解决办法是给每个PID控制器加一个初始化模式仿真开始后的前0.5秒内环跟踪一个固定的角速率指令零外环保持积分器复位等内环稳定后再切换到正常模式。第二个坑是BMS模型的代数环。二阶RC模型里端电压的计算依赖电流而电流又依赖端电压通过负载模型这就形成了一个代数环。Simulink会报错或者仿真极慢。解决办法是在电流和端电压之间加一个单位延迟Memory模块打破代数环。这个延迟会引入一点误差但在1ms步长下可以忽略。第三个坑是优化算法的目标函数计算太慢。每次评估都要跑一次完整仿真30秒的仿真在普通笔记本上要跑2到3秒GWO跑100次迭代、30个种群就是9000次仿真将近7个小时。后来我把仿真时间从30秒缩短到10秒只保留关键的动态过程步长从1ms放宽到2ms单次仿真时间降到0.5秒总时间降到1个多小时。精度损失很小因为10秒已经足够覆盖固定翼的主要动态。第四个坑是PSO的早熟收敛。标准PSO在搜索后期所有粒子都挤在gbest附近多样性丧失如果gbest是个局部最优整个种群就出不来了。我加了两个机制一是变异算子每次迭代有5%的概率随机重置一个粒子的位置二是多群策略把种群分成三个子群各自独立搜索每隔20代交换一次最优解。这两个机制加上去之后PSO找到全局最优的概率从60%左右提升到了90%以上。这套仿真框架搭好之后最大的价值不是某一组具体的PID参数而是整个验证流程可以复用。换一个机型只需要改气动系数和质量惯量级联PID的结构不用动GWO和PSO的代码不用动BMS模型只需要改电芯参数和串并联数。从拿到新机型参数到跑出一组可用的PID参数大概两天时间就够了。相比手工调参动辄一两周效率提升是实实在在的。
网站建设高端定制企业官网