多阶段批式反应器¶
背景¶
许多批式生产过程会针对连续反应采用不同的催化剂或操作工况。本例先将原料 \(A\) 转化为中间体 \(B\),更换催化剂后再将 \(B\) 转化为产品 \(P\)。切换过早会导致中间体不足,切换过晚则没有足够时间生成产品。提高温度强度可以加速两个反应,但也会增加操作代价。
因此,该过程是一个真正的多阶段问题:动力学在优化得到的事件时刻发生变化,而所有浓度在事件处保持连续。
问题定义¶
每个阶段的归一化浓度向量为 \(x_j=(A_j,B_j,P_j)\)。在第一阶段 \(0\le t\le t_s\) 内,
在第二阶段 \(t_s\le t\le2\ \mathrm h\) 内,
初始条件、事件连接条件和控制边界为
终端浓度自由。目标函数在产品产率与温度代价之间进行权衡:
变量与单位¶
| 符号 | 含义 | 单位 |
|---|---|---|
| \(t\) | 批次时间 | h |
| \(A,B,P\) | 归一化原料、中间体和产品浓度 | - |
| \(u_1,u_2\) | 归一化温度强度 | - |
| \(k_1,k_2\) | 有效一级反应速率常数 | h\(^{-1}\) |
| \(t_s\) | 催化剂切换时刻 | h |
| \(\eta\) | 被消耗中间体生成产品的收率 | - |
建模选择¶
每种催化剂工况分别使用一个 Lobatto 阶段,每个阶段包含 24 个网格区间,每个区间有两个插值点。这样可使浓度和温度重构保持分段线性,避免节点间边界过冲,同时不会比原先的高阶网格增加决策点数量。共享静态参数保存事件两侧的三个浓度;第一阶段终端边界和第二阶段初始边界使用相同参数,从而严格施加连续性。切换时刻也是共享参数,与两个控制轨迹一同优化。
收率 \(\eta<1\) 表示进入未建模副产物的物料损失。温度代价权重使两个阶段都得到内部最优控制,而不是缺乏信息量的全程温度上限解。
运行示例¶
保存图片且不打开窗口:
关键实现¶
system = System(["a_switch", "b_switch", "p_switch",
"a_final", "b_final", "p_final", "t_switch"])
a_s, b_s, p_s, a_f, b_f, p_f, t_s = system.s
phase_1.set_boundary_condition(
[1.0, 0.0, 0.0], [a_s, b_s, p_s], 0.0, t_s
)
phase_2.set_boundary_condition(
[a_s, b_s, p_s], [a_f, b_f, p_f], t_s, BATCH_TIME
)
system.set_phase([phase_1, phase_2])
system.set_objective(
-p_f + EFFORT_WEIGHT * (phase_1.I[0] + phase_2.I[0])
)
已验证结果¶
Ipopt 成功终止,目标函数值为 \(-0.45376749\)。最优催化剂切换时刻为 \(t_s=1.092691\ \mathrm h\),终端产品比例为 \(0.658482\)。按 \((t_f-t_0)^{-1}\int u\,\mathrm dt\) 计算的第一、第二阶段时间平均温度强度分别为 \(0.796591\) 和 \(0.860164\)。事件两侧的最大浓度误差小于 \(2\times10^{-6}\),每个阶段上的 2,001 点检查在所列精度下没有发现路径边界超限。

源码¶
完整可运行示例见 examples/multiphase_batch_reactor.py。