本节摘要:把全册兵器装进一个 Python 工作流:SciPy 的 linprog、milp、minimize 对接优化求解,ODE 数值积分与离散事件仿真负责验证,控制模块复用 LQR 与卡尔曼代码。本节演示一条"数据 → 模型 → 求解 → 仿真验证 → 迭代"的完整流水线,并给出工具选型表与工程卫生习惯。
学完各章兵器后,最常见的状态是"每章的代码都跑通过,但串不起来"。实战需要的不是单发子弹,而是一条流水线:业务数据进来,口径统一后进入模型层,求解器给出候选方案,仿真层检验方案在噪声与扰动下的表现,不达标就回到数据层迭代。这条循环在本节用一个小而完整的例子走一遍——工厂能源调度:白天电价高、夜间低,冰蓄冷系统夜间制冰、白天放冷,需求带随机波动。
第一步,数据与口径。电价分时表、冷负荷曲线、蓄冷罐容量与效率——每个量都要写下单位与数据来源。这一步最不起眼,却决定后面所有数字的意义。
第二步,优化层:把它写成线性规划。决策变量是各时段的制冷量与蓄放冷量,目标是最小化电费,约束是冷量平衡与罐容量:
import numpy as np from scipy.optimize import linprog T = 24 price = np.array([0.9 if 8 <= h < 22 else 0.4 for h in range(T)]) # 分时电价 load = np.array([200 + 150*np.sin((h-14)/24*2*np.pi) for h in range(T)]) load = np.clip(load, 80, None) # 冷负荷 eta, cap = 0.95, 800.0 # 蓄冷效率与罐容 # 变量:x[0:T] 直接制冷量, x[T:2T] 蓄冷罐变化量 c = np.concatenate([price, np.zeros(T)]) rows, lo, hi = [], [], [] soc = 0.0 for h in range(T): # 冷量平衡:直接制冷 + 放冷 = 负荷 r = np.zeros(2 * T); r[h] = 1.0; r[T + h] = -1.0 rows.append(r); lo.append(load[h]); hi.append(load[h]) for h in range(T): # 罐容量累积约束 r = np.zeros(2 * T); r[T:T + h + 1] = eta rows.append(r); lo.append(0.0); hi.append(cap) from scipy.optimize import LinearConstraint con = LinearConstraint(np.array(rows), np.array(lo), np.array(hi)) res = linprog(c, constraints=[con], bounds=[(0, None)] * 2 * T, method="highs") print(f"最优电费 {res.fun:.0f} 元,无蓄冷方案电费 {(price*load).sum():.0f} 元")
第三步,仿真验证。优化的解在确定性负荷下成立,但负荷预测有 ±10% 误差——方案还稳吗?把 LP 的调度规则放进随机场景跑仿真:
rng = np.random.default_rng(11) gaps = [] for _ in range(200): real_load = load * rng.uniform(0.9, 1.1, T) supply = np.minimum(res.x[:T] + np.cumsum(res.x[T:]) * 0, res.x[:T]) gaps.append(np.mean(np.maximum(real_load - supply, 0))) print(f"随机负荷下平均缺口 {np.mean(gaps):.1f} kW(0 表示方案稳健)")
第四步,迭代。仿真若暴露缺口,回到第一步:加缓冲容量约束、或引入 4.1 节的机会约束(把缺口概率压到 5% 以内),重新求解。循环往复,直到方案在扰动下站得住——优化给方案,仿真给信心,这是军械库的第一设计原则。
全册兵器到接口的映射表:
| 问题形态 | 首选接口 | 备注 |
|---|---|---|
| 线性规划 | linprog method=highs | 读 marginals 拿影子价格 |
| 整数规划 | milp | 关注 mip_gap 与时间上限 |
| 非线性凸 | minimize SLSQP/trust-constr | 检查 KKT 乘子 |
| ODE 仿真 | solve_ivp | 刚性系统换 Radau/BDF |
| 矩阵方程 | solve_lyapunov 等 | LQR 与稳定性证书 |
| 图算法 | 手写(第5章代码) | 大规模再上专门图库 |

三条工程卫生习惯。可复现:随机种子固定、数据版本留痕,别人拿到同一份输入要能跑出同一份输出。日志即证据:求解器的状态码、迭代数、间隙,仿真的一次收尾统计,都应进入报告——第 3 章说过的"读状态码"在这里是纪律。分段小步:流水线每层留出中间产物(清洗后的表、模型文件、解文件),排查问题时能快速定位是数据病、模型病还是求解病。
⚠️ 常见坑:把求解器当黑盒直接接业务系统。求解失败(不可行、超时、局部最优)是常态而非异常,流水线必须为每种失败准备降级方案——回退上一版方案、切启发式、或转人工。军械库的成熟度不看最好情况多快,看最坏情况多稳。
流水线跑通后,交付物建议固定成三张报表,它们是沙盘的验收单。方案表:最优决策本身(各时段制冷量与蓄放计划),附上每条约束的松紧状态——哪几条顶格、哪几条有余量。证据表:求解器状态码与间隙、目标值与基准方案(现状或简单规则)的对比、扰动仿真下的分位数表现——一张表回答"这个方案比现在好多少、在坏情况下最差多惨"。敏感性表:电价上下浮动两成、负荷预测偏一成、罐容量缩水一成时,方案结构与目标值如何变化——它回答"哪个参数是命门、模型在哪个区间可信"。三张表齐,沙盘推演才算完成从"跑代码"到"做决策支持"的升级;缺任何一张,评审会上都挡不住"如果换一个参数会怎样"的第三轮追问。
工具齐了。最后一节走进真实行业:三个战例的完整复盘,包括它们摔过的跟头。