任务与对象模块使用说明
注意: 我们对各种任务的处理的差异化实际上是体现在模型而非任务类型,以温度和压强为例,若都用的FOPDT,任务对象模型也是相同的,那么20度升温到100度和20kPa增压到100kPa实际上是同一个任务,当然这里只是举个例子,实际操作的时候有其他的复杂限定
一、先弄清"任务"和"对象"有什么区别
这是本模块最重要的概念:
- 对象(Plant/Process):真实设备或其数学模型,描述"改变加热功率/阀门开度后,温度、压力、流量等会如何变化"。
- 任务(Task):你希望控制器完成什么,例如"把水箱从 30℃ 加热到 100℃"。
- 执行器(Actuator):控制器实际能调节的东西,例如加热功率 0~100%、阀门开度 0~100%。
比如同一个水箱,今天要求升到 80℃,明天要求升到 100℃,对象模型可能不变,任务目标变了 。但如果换了一个更大的水箱,升温速度和散热特性不同,就需要重新检查对象模型。
text
任务:SP=100℃,初温=30℃
↓
PID 控制器
↓ 输出 u
执行器:加热功率 0%~100%
↓
对象:水箱 + 加热过程(K、τ、θ)
↓
测量值 PV:当前水温
└────────反馈给 PID
**典型工作顺序:**选被控量 → 选模型类型 → 选模型来源 → 填模型或辨识数据 → 设任务 → 设执行器 → 到"控制器与评价"配置 PID 和合格标准 → test 仿真。
二、被控量定义(process)
2.1 被控量类型:kind
仓库支持以下类型:
| 类型 | 选项值 | 示例 |
|---|---|---|
| 温度 | temperature |
水箱加热 |
| 压力 | pressure |
管道压力控制 |
| 流量 | flow |
调节阀控制流量 |
| 液位 | level |
储罐液位控制 |
| 转速 | speed |
电机转速 |
| 自定义 | custom |
浓度、pH 等 |
怎么用:先选你真正要控制的物理量。切换类型不会自动生成正确的物理模型,也不会自动把摄氏度换算成 MPa。
2.2 显示名称:name
默认是"温度"。主要用于界面、图表和报告显示。可以改成"反应釜温度""蒸汽压力""储罐液位"等。它不是系统辨识参数。
2.3 单位:unit
默认是 ℃。压力可用 MPa,流量可用 m³/h,液位可用 m 等。
非常重要:单位必须一致。
例如选择压力 MPa:
- 初始压力和目标压力使用 MPa;
- 历史 CSV 的压力列使用 MPa;
- 模型过程增益
K的被控量部分使用 MPa; - 评价偏差带和绝对限值使用 MPa。
程序不会因为把标签从 ℃ 改为 MPa,就自动换算数值。
三、对象模型(model)
对象模型决定仿真器如何根据控制输出计算下一时刻的被控量。
3.1 模型类型:type
仓库提供:
| 模型类型 | 配置值 | 含义与适用场景 |
|---|---|---|
| 一阶惯性加纯滞后 | fopdt |
常见温度、压力、流量等可近似为一阶响应的过程 |
| 积分加滞后 | integrating |
某些液位等持续积累型过程 |
| 两节点加热 | heating |
分别模拟加热器与被加热对象的热动态 |
| 自定义 | custom |
内置模型无法描述的过程,由用户提供 Python 模型 |
不能认为所有工业对象都适合 FOPDT。 对象类型需要依据数据和机理选择。尤其是液位,某些液位系统是积分型,某些则能表现出自衡特性。
3.2 模型来源:source
这是决定"程序从哪里得到对象参数"的设置。
| 来源 | 配置值 | 实际作用 |
|---|---|---|
| 已知参数 | parameters |
直接使用你填写的 K、τ、θ 或对应模型参数 |
| 历史 CSV | csv |
从已有阶跃响应数据辨识 FOPDT |
| 离线探测 | probe |
在软件模型上做阶跃,估计模型参数 |
| 手动 | manual |
从用户提供的初始 PID 进入仿真/可选 LLM 路线,不套用常规辨识公式 |
怎么选:
- 已知模型参数:选
parameters。 - 有真实的阶跃 CSV:选
csv。 - 想在软件内测试模型辨识:选
probe。 - 不想按辨识公式生成初始 PID,想测试手动初始 PID 路线:选
manual。
特别注意: probe 是离线模型探测 ,不是给真实设备自动发送阶跃命令。manual 也不是一种新的辨识算法。
3.3 FOPDT 模型的 K、τ、θ
FOPDT(一阶惯性加纯滞后)公式:
G(s)=\\frac{K e\^{-\\theta s}}{\\tau s+1}
这三个参数是对象参数,不是 PID 的 Kp、Ki、Kd。
K:过程增益(K)
默认 1.0。描述输出改变一个单位,最终被控量大约变化多少。
K=\\frac{\\Delta PV_{\\text{稳态}}}{\\Delta u}
例如加热器输出从 20% 增加到 30%,温度最终从 50℃ 升到 70℃:
K=\\frac{70-50}{30-20}=2\\ \\text{℃/百分点}
即输出增加 1 个百分点,稳态温度增加约 2℃。
K>0:输出增大,被控量通常增大;K<0:输出增大,被控量通常减小,例如某些冷却回路;K=0:不符合该模型对非零过程增益的要求。
**易错点:**K 的单位由被控量和执行器单位共同决定。若输出改用 0~1 的归一化数值,K 也必须相应换算。
τ:时间常数(tau_s)
默认 120s。描述对象响应快慢。
对于理想的一阶阶跃响应,在纯滞后结束后再经过一个 τ,响应达到最终变化量的约 63.2%。
假设水温从 20℃ 最终升到 100℃,总变化 80℃:
20+80\\times0.632\\approx70.6℃
如果纯滞后为 10 秒、τ=120 秒,那么理论上约在阶跃后第 130 秒达到 70.6℃。
τ 越大通常响应越慢;越小通常越快。
θ:纯滞后(theta_s)
默认 10s。指控制输出变化后,到被控量开始出现相应变化之间的延迟。
例如第 0 秒提高加热功率,第 10 秒左右水温才开始响应,则 θ 约为 10 秒。
θ=0:没有额外纯滞后;θ>0:存在等待时间;θ<0:无效。
项目配置说明:传统 Z-N 公式路线需要正的 θ,SIMC 可以处理 θ=0 的情况。
直观理解:
text
第 0 秒:改变加热功率
↓ 等待 θ=10s
第 10 秒:水温开始变化
↓ 再经过 τ=120s
第 130 秒:完成约 63.2% 的最终温升
↓
逐渐接近新的稳态
3.4 工作点温度与工作点输出
字段:
operating_temperature_c:默认20℃;operating_output:默认0。
工作点不是本次任务初温。 它描述模型在某个稳定输出下对应的稳定被控量。
FOPDT 模型的稳态关系:
PV_{\\mathrm{ss}}=PV_{\\mathrm{op}}+K(u-u_{\\mathrm{op}})
例如:
- 工作点温度 20℃;
- 工作点输出 0%;
- K=1℃/百分点;
- 当前输出保持 50%。
那么模型预测的稳态温度是:
20+1\\times(50-0)=70℃
为什么必须填对? 因为它决定同一个控制输出对应的稳态温度。若工作点错误,可能出现"无论怎么整定,目标都很难达到"的现象。
对于压力、流量等非温度变量,工作点的物理意义仍然是"稳定被控量 + 对应稳定输出";界面或配置字段名可能沿用温度命名,但数值单位要遵守所选被控量。
3.5 两节点加热模型(heating)专用参数
这些参数只在选择 heating 模型时才有意义。普通 FOPDT 不使用它们。
| 字段 | 默认值 | 含义 |
|---|---|---|
heater_gain_c_per_output |
3.0 | 加热器每增加一个输出单位,对应的稳态加热器温升 |
heater_tau_s |
10s | 加热器自身响应的时间常数 |
heat_transfer_per_s |
0.5 /s | 加热器向被控对象传热的系数 |
cooling_per_s |
0.05 /s | 被控对象向环境散热的系数 |
**举例:**加热器本身可能几秒内变热,但水箱因为容量较大,要很久才升温。heating 可以把"加热器变热"和"水箱升温"作为两个动态过程,而不是简单用一个 τ 概括。
heater_tau_s越大,加热器本身响应越慢;heat_transfer_per_s越大,模型中的传热越快;cooling_per_s越大,模型中的散热越强。
这些是该模型的数学系数,不能直接当成通用设备铭牌参数。
3.6 自定义模型:custom_factory
默认空字符串 ""。
当内置 FOPDT、积分、加热模型都不适合时,可以通过 模块:函数 的形式指定自定义 Python 模型工厂,例如:
text
examples.custom_model:create_model
这不是输入一段自然语言就能自动生成模型;需要项目能够导入对应 Python 模块,且工厂符合软件约定的接口。
四、历史数据(history):用真实响应辨识模型
这部分只在 model.source=csv 时生效。
4.1 CSV 文件路径:file
默认 "",表示不指定历史文件。
例如:
text
data/step.csv
项目配置说明:相对路径通常相对于配置文件所在目录。
4.2 时间单位:time_unit
可选 s(秒)或 ms(毫秒),默认 s。
这是非常容易出错的设置。
如果 CSV 时间列记录的是毫秒,但程序按秒解释,辨识得到的时间常数和纯滞后可能相差 1000 倍。
例如 CSV 时间戳:
text
0, 1000, 2000, 3000
如果单位是 ms,代表 0、1、2、3 秒;如果设为 s,就会被解释成 0、1000、2000、3000 秒。
4.3 CSV 列名映射:columns
默认映射:
| 程序字段 | 默认 CSV 表头 | 作用 |
|---|---|---|
time |
timestamp |
时间 |
temperature |
input |
被控量测量值 |
output |
pwm |
实际控制输出 |
假设你的 CSV 是:
csv
time_s,water_temp,heater_percent
0,30.0,20
1,30.0,20
2,30.1,40
3,30.2,40
...
就要把列映射改成:
json
{
"time": "time_s",
"temperature": "water_temp",
"output": "heater_percent"
}
这里的 temperature 是项目内部使用的映射键;实际 CSV 列名可以根据被控量自定义。
注意:示例只是展示列名格式,不足以完成可靠辨识。 真正的阶跃数据通常需要阶跃前稳定基线、清晰的输出变化和足够长的后续响应。
4.4 使用 CSV 记录的工作点:use_recorded_operating_point
默认 true。
true:采用 CSV 阶跃前的被控量和输出作为模型工作点;false:使用手动填写的模型工作点。
例如 CSV 中阶跃前温度稳定在 50℃、输出 20%,那么开启后,模型可以用这组观测值作为工作点。
**怎么用:**真实阶跃数据的基线可靠时,建议保留 true;如果基线受干扰、不稳定或需要指定标准工作点,则先检查数据和模型再决定。
五、离线辨识(identification)
5.1 探测总时长:probe_duration_s
默认 960s。
决定软件中的离线阶跃记录观察多久,包含一段阶跃前基线。要足够长,尽量让对象接近新的稳定状态。
**举例:**若对象时间常数 τ=120s,960 秒通常足以观察多倍时间常数的响应;但对于 τ=1000s 的慢对象,960 秒可能明显不足。
**怎么用:**不要机械地固定 960 秒,应该根据对象的 τ、θ 和是否达到稳态来判断。
5.2 探测输出变化幅度:probe_output_change
默认 20,单位与执行器相同。
如果输出单位是 %,则表示阶跃变化 20 个百分点,不是"增加当前值的 20%"。
例如:
- 原输出 30%;
- 阶跃变化 +20;
- 新输出 50%。
变化幅度要能落在执行器允许范围内。过小可能导致响应不明显,过大可能超出模型适用范围。
重要:该字段用于软件的离线探测,不代表允许对真实设备直接做 20% 阶跃。
5.3 最大相对拟合误差:max_relative_rmse
默认 0.05,即 5%。
配置说明中的相对误差定义为:
E_{\\mathrm{rel}}= \\frac{\\mathrm{RMSE}}{\|\\Delta PV_{\\mathrm{step}}\|}
其中 RMSE 是模型预测曲线与实际/参考曲线之间的均方根误差:
\\mathrm{RMSE}= \\sqrt{\\frac{1}{N}\\sum_{i=1}\^{N} (\\hat y_i-y_i)\^2}
例如:
- 阶跃导致温度变化 40℃;
- 拟合 RMSE 为 1℃;
- 相对误差 = 1/40 = 2.5%,低于 5%,满足这一门槛。
若 RMSE 为 3℃,相对误差 = 7.5%,超出门槛。
**怎么用:**超限时先检查阶跃数据是否完整、时间单位是否正确、对象是否适合 FOPDT,以及是否存在扰动。不要为了让辨识"通过"就盲目调大容差。
还要注意:拟合误差低,只代表当前数据下拟合得较好,并不保证模型能覆盖所有工况。
六、控制任务(task)
6.1 初始被控量:initial_temperature_c
默认 30℃。
表示本次仿真开始时的被控量,不是模型工作点。
- 工作点:模型的稳定参考关系;
- 任务初始值:这次控制从哪里开始。
在 use 模式下,项目说明指出该值会由设备读取的实际被控量覆盖,因此不应把手填的测试初值当成设备实时测量值。
6.2 目标被控量:target_temperature_c
默认 100℃。
也就是 PID 的设定值 SP。
例如初始温度 30℃、目标温度 100℃,程序要寻找一组 PID 参数,使温度尽量达到并稳定在 100℃,同时满足评价限制。
**修改目标时要一起检查:**执行器是否有能力达到目标、最高/最低评价限值、仿真停止温度和允许超调范围。
6.3 环境温度:ambient_temperature_c
默认 20℃。
仅 heating 模型使用。 它用于两节点加热模型中的环境散热/加热计算;FOPDT 使用自己的工作点,不额外叠加环境温度。
例如环境从 20℃ 改为 5℃,在有散热的 heating 模型里,保持同样水温可能需要更多加热输出。
6.4 加热器初始温度:initial_heater_temperature_c
默认 30℃,仅 heating 使用。
加热器自身温度可以与水箱温度不同。
例如水箱温度 30℃,加热器初温 80℃,即使控制器暂时不提高功率,加热器也可能继续向水箱传热。
6.5 初始输出:initial_output
默认 0,单位与执行器一致。
表示任务开始时加热功率/阀门开度是多少;在 FOPDT 模型中,也用于描述纯滞后期间的初始输入历史。
例如:
- 初始温度 30℃;
- 初始输出 20%;
- 目标温度 100℃。
它不等于 PID 最终输出,也不等于模型的工作点输出。
use 模式下,项目说明指出该值会从设备读取。
七、执行器(actuator)
PID 计算出的控制输出不能无限大,执行器会受到物理限制。
7.1 输出单位:unit
默认 %。
例如加热器功率百分比、阀门开度百分比、kW 或步进电机步数。
更换单位必须同步检查模型 K、历史 CSV、初始输出和设备接口。改显示标签不会自动换算。
7.2 最小输出:min
默认 0。
例如加热器不能输出负功率,最小为 0%。
7.3 最大输出:max
默认 100。
例如加热器最大为 100%。
如果 PID 理论计算出 130%,实际执行器也只能输出到配置上限;此时可能发生饱和。
7.4 最大输出变化率:max_rate_per_s
默认 10,单位是"输出单位/秒"。
假设输出单位是 %:
- 当前输出 20%;
- 每秒最大变化量 10 个百分点;
- 采样周期为 1 秒。
那么下一次输出最多只能升到 30%,不能直接跳到 80%。
采样周期与变化率的关系:
\|\\Delta u_{\\max}\|=r_{\\max}\\Delta t
如果采样周期改为 0.5 秒,则单次更新允许的最大变化量为 5 个百分点。
这个参数能模拟执行器动作速度限制,但不代表所有设备都可以按这个速度安全动作。
八、把各项设置串起来:完整温控例子
假设你要研究一个水箱从 30℃ 升温到 100℃。
| 模块 | 参数 | 示例值 |
|---|---|---|
| 被控量 | 类型 / 单位 | temperature / ℃ |
| 模型 | 类型 / 来源 | fopdt / parameters |
| 模型 | K | 1.0 ℃/百分点 |
| 模型 | τ | 120s |
| 模型 | θ | 10s |
| 模型 | 工作点温度 | 20℃ |
| 模型 | 工作点输出 | 0% |
| 任务 | 初始温度 | 30℃ |
| 任务 | 目标温度 | 100℃ |
| 任务 | 初始输出 | 0% |
| 执行器 | 范围 | 0~100% |
| 执行器 | 最大变化率 | 10 百分点/s |
| 运行 | 模式 | test |
先检查一个物理问题:执行器够不够用?
这个 FOPDT 模型的稳态关系是:
PV_{\\mathrm{ss}}=20+1\\times u
要达到 100℃,稳态所需输出大约是:
u_{\\mathrm{required}}=\\frac{100-20}{1}=80%
执行器允许 0~100%,所以从稳态能力看,100℃ 可达到。但这并不保证 PID 不超调、能在 600 秒内稳定,也不保证模型真实可靠------这些需要后续仿真评价。
如果你把目标改成 150℃,模型要求稳态输出约 130%,超过执行器上限。此时不能单靠增大 Kp、Ki、Kd 解决物理输出能力不足的问题。
九、四个建议亲手做的实验
实验 1:只改变 K,观察整定参数
固定 τ=120s、θ=10s,分别设置 K=0.5、1.0、2.0,其他条件不变。
观察 Z-N、SIMC 算出的 PID 参数和仿真效果。
**理解重点:**过程增益变化,意味着相同输出会造成不同幅度的被控量变化,因此合理的 PID 增益也可能变化。
实验 2:只改变 τ,观察响应速度
固定 K=1、θ=10s,分别设置 τ=60、120、240s。
**理解重点:**时间常数越大,过程越慢;需要同时检查仿真时长是否足够,否则可能因为观察时间太短而误判不合格。
实验 3:只改变 θ,观察滞后的影响
固定 K=1、τ=120s,分别设置 θ=0、10、30s。
**理解重点:**纯滞后增加通常让控制更困难。θ=0 时,不应强行套用需要正滞后的 Z-N 公式。
实验 4:改变执行器最大值,观察"不可达目标"
先把输出上限设为 100%,再改成 60%,保持工作点 20℃、K=1、目标 100℃。
输出上限 60% 时,模型预测最高稳态温度约为 80℃,目标 100℃ 从稳态能力上不可达。
**理解重点:**有些"PID 整定失败"其实是对象和执行器条件决定的,不是整定算法算错。
十、常见问题
Q1:K、τ、θ 是不是程序要整定的 PID 参数?
不是。它们描述对象。程序根据对象模型计算或搜索 PID 的 Kp、Ki、Kd。
Q2:我已经知道 K、τ、θ,还需要 CSV 吗?
不一定。选择 parameters 就可以直接使用已知参数。CSV 主要用于从真实阶跃数据估计模型。
Q3:probe 是不是会给真实设备加一个 20% 阶跃?
不是。仓库说明它是离线模型探测,不会向真实装置发阶跃命令。
Q4:工作点温度与初始温度为什么可以不同?
工作点描述某个稳定输出下的稳定被控量;初始温度描述本次仿真的起点。二者物理意义不同。
Q5:把 process.kind 从 temperature 改为 pressure,就能直接做压力 PID 吗?
不能只改类型标签。还需要压力对象模型、单位、目标、执行器范围及评价门槛全部一致。
Q6:为什么辨识 RMSE 合格,PID 仍可能控制不好?
拟合质量和闭环控制质量是两件事。模型可能只在当前阶跃附近准确,也可能存在执行器饱和、控制器设置或任务不可达等问题。
Q7:改成 use 后,还使用我填写的初始温度和输出吗?
按仓库说明,使用模式会读取设备实际被控量与输出,覆盖任务中的测试初值。实际应用前还需要核对设备接口、单位与安全条件。
Q8:为什么任务目标设为 100℃,程序却始终无法达到?
先检查模型预测的稳态可达范围、执行器输出上限、输出变化率、仿真时长,再检查 PID 整定与评价,不要直接把 Kp 调得越来越大。
十一、使用前检查清单
- 被控量名称、类型和单位正确。
- 模型类型符合对象动态特性。
- 模型来源选对(已知参数 / CSV / 离线探测 / 手动)。
- K 的符号、量纲和数值合理。
- τ、θ 的时间单位都是秒,且符合对象特性。
- 工作点输出与工作点被控量对应。
- 若使用 CSV,时间单位、列名、阶跃前基线和响应末段均已检查。
- 若使用离线辨识,探测时长足够,误差阈值合理。
- 任务初值、目标值、初始输出合理。
- 执行器最大最小值和变化率正确。
- 先在
test模式完成仿真,再考虑设备接入。
十二、最重要的使用原则
对象决定"系统会怎么变化",任务决定"你想让它变成什么",执行器决定"你最多能做什么"。
PID 整定并不能改变对象的物理极限。正确使用本模块的关键,不是随便填一组 K、τ、θ 后点击开始,而是确保模型、任务、执行器三者一致,再交给后面的「控制器与评价」模块寻找并验证合格的 PID 参数。
模型与历史数据模块使用说明
一、这个模块究竟负责什么?
一句话:告诉程序"被控制的设备有什么动态特性",以及"这些特性是从哪里得到的"。
例如要把水箱从 30℃ 加热到 100℃,PID 需要知道:提高 10% 加热功率,温度最终大约提高多少?升温有多慢?改变功率后要等多久才看到温度变化?
这些属于对象模型的问题。模型可以来自你已知的参数,也可以从历史阶跃数据中估计出来。
text
模型来源
├─ parameters:已知模型参数,直接填写
├─ csv:读取历史阶跃 CSV,辨识 FOPDT
├─ probe:在离线模型上施加阶跃,辨识 FOPDT
└─ manual:使用初始 PID 仿真,不套用辨识公式
↓
对象模型(例如 K、τ、θ)
↓
Z-N / SIMC 计算 PID 候选
↓
参数护栏 → 闭环仿真 → 性能评价
这里一定要分清两组参数:
| 对象模型参数 | PID 控制器参数 |
|---|---|
K、τ、θ |
Kp、Ki、Kd |
| 描述设备本身怎么响应 | 描述控制器怎么调节 |
| 通过建模或系统辨识得到 | 通过整定算法或调优得到 |
模型参数不是 PID 参数。 改变 K、τ、θ,等于改变软件所假设的设备动态;改变 Kp、Ki、Kd,才是调整控制器。
二、模型类型:model.type
模型类型决定程序用什么数学结构描述对象。仓库提供四种:
| 选项 | 中文含义 | 适用情况 |
|---|---|---|
fopdt |
一阶惯性加纯滞后 | 可近似为一阶自衡响应的温度、压力、流量等过程 |
integrating |
积分加滞后 | 某些液位等积累型过程 |
heating |
两节点加热模型 | 需要区分加热器温度和被加热物温度 |
custom |
自定义模型 | 内置模型无法描述的动态 |
2.1 fopdt:最常用的入门模型
FOPDT(First Order Plus Dead Time):
G(s)=\\frac{K e\^{-\\theta s}}{\\tau s+1}
可以理解为:
- 改变输出;
- 等待一段纯滞后时间
θ; - 被控量开始按照一阶惯性逐渐变化;
- 最后接近新的稳定值。
**推荐:**第一次学习 Z-N、SIMC 或系统辨识,先选 fopdt,因为参数物理意义直观。
2.2 integrating:积分型过程
典型形式可写为:
G(s)=\\frac{K e\^{-\\theta s}}{s}
与 FOPDT 的关键区别:在输入持续偏离平衡值时,被控量可能持续上升或下降,而不是自然趋于一个新的稳态。
**例子:**某个储罐的进水量长期大于出水量,液位会持续升高。
注意:不是所有液位系统都是积分型,存在自衡液位过程。应根据实际数据选择。仓库配置说明中,integrating 使用积分过程增益 K 和滞后 θ;不要把 FOPDT 的 τ 直接当成积分型模型的时间常数。
2.3 heating:两节点加热模型
将加热器和被加热对象看成两个相互传热的节点。
text
加热功率 u
↓
加热器温度(响应较快)
↓ 传热
水箱温度(响应较慢)
↓ 散热
环境温度
适合模拟"加热器已经很热,但水箱还没升到目标温度"的情况。它有专用的加热器增益、时间常数、传热与散热系数。
2.4 custom:自定义 Python 模型
当 FOPDT、积分型和两节点加热都不能描述设备时,使用自定义模型。
需在 custom_factory 中填写 模块:函数,并提供与程序接口匹配的 Python 实现。它不是直接输入一段描述就自动生成模型。
**选择原则:**先根据过程物理特性与响应数据判断模型类型,不要只因为被控量叫"温度"就一定选 heating,也不要因为叫"液位"就一定选 integrating。
三、模型来源:model.source
这个设置决定模型数据怎么获得。
| 选项 | 数据从哪里来 | 初学者何时使用 |
|---|---|---|
parameters |
手动填写已知参数 | 最容易上手、便于验证公式 |
csv |
读取历史阶跃数据 | 手上已有实验或设备记录 |
probe |
在软件模型上做离线阶跃 | 想理解辨识过程 |
manual |
从初始 PID 进行仿真/可选 LLM 调优 | 不希望使用常规辨识公式作为初值 |
3.1 parameters:直接填模型参数
假设你已经知道:
K=1.0;τ=120s;θ=10s。
选 parameters 后,程序直接使用这些对象参数作为整定依据,不需要读取 CSV。
**适合:**学习 SIMC、Z-N;复现一组已知模型;研究 K、τ、θ 对整定结果的影响。
3.2 csv:历史数据辨识
选 csv 后,程序从 CSV 读取时间、实际被控量、实际输出,利用阶跃响应估计 FOPDT 参数。
配置说明特别强调:CSV 应包含一次清晰的阶跃、阶跃前基线、阶跃后基本稳定的末段。
此时模型中的 τ 会由 CSV 辨识结果覆盖;不要把手填的 τ 误当成最后使用的辨识结果。
**适合:**你已经从设备、PLC、采集系统或实验平台导出了阶跃响应。
3.3 probe:离线阶跃探测
选 probe 后,程序在软件模型上施加一次输出阶跃,观察响应并估计 FOPDT 参数。
例如:
- 模型已设置
K=1, τ=120s, θ=10s; - 离线阶跃幅度设为 20 个百分点;
- 程序生成模型响应并做辨识。
它适合验证"辨识程序能否从响应曲线找回合理的模型参数"。
**非常重要:**这不是自动向真实工业设备发送阶跃指令。
3.4 manual:不走常规辨识公式初值
这个名字容易让人误解成"手动输入 K、τ、θ"。实际上仓库注释定义为:从用户提供的初始 PID进入仿真,并可选 LLM 调优,不套用常规辨识公式。
如果你想手动填写已知的 K、τ、θ ,应优先选 parameters,而不是 manual。
四、FOPDT 的三个核心参数
4.1 K:过程增益
此前默认:1.0。
表示执行器输出变化一个单位,最终被控量变化多少。
K=\\frac{\\Delta PV_{\\mathrm{稳态}}}{\\Delta u}
例如:
- 阀门/加热功率从 20% 调到 30%;
- 水温从稳定的 50℃ 变到稳定的 70℃。
则:
K=\\frac{70-50}{30-20}=2\\ \\mathrm{℃/百分点}
含义:输出每增加 1 个百分点,温度最终约增加 2℃。
注意:
K>0:输出增大,被控量增大;K<0:输出增大,被控量减小,例如某些冷却过程;K=0:此配置不允许,过程方向无法正常定义。
单位尤其重要。 如果输出从百分数 0~100 改成归一化 0~1,K 的数值要对应变化;不能只修改输出单位标签。
4.2 tau_s:时间常数 τ
此前默认:120s,必须大于 0。
对于理想一阶阶跃响应,经过纯滞后后再经过一个 τ,被控量完成最终变化幅度的约 63.2%。
假设:
- 初温 20℃;
- 最终稳态温度 100℃;
θ=10s;τ=120s。
总变化是 80℃,63.2% 对应:
20+80\\times0.632\\approx70.6℃
因此理论上在阶跃后约 10+120=130s 达到 70.6℃。
**怎么理解:**τ 越大,过程通常越慢;τ 越小,通常越快。
4.3 theta_s:纯滞后 θ
此前默认:10s,不能为负。
例如第 0 秒提高功率,约第 10 秒温度才开始对该变化作出响应,则纯滞后约 10 秒。
text
0 秒:加热输出阶跃
│
├── 10 秒:纯滞后结束,温度开始响应
│
└── 130 秒:约完成 63.2% 的最终变化
**容易混淆:**θ 是"开始响应之前的等待时间",τ 是"开始响应之后的惯性快慢",二者不是一回事。
仓库注释说明:传统 Z-N 公式路线需要 θ>0,SIMC 可处理 θ=0。因此 θ=0 并不意味着对象无法控制,只是某些公式不适用。
五、工作点参数:不要和任务初值混淆
5.1 operating_temperature_c
此前默认:20℃。
表示模型在某个稳定输出下,对应的稳定温度。虽然字段名带 temperature_c,对其他被控量使用时也要保持数值和单位一致。
5.2 operating_output
此前默认:0。
表示与上面工作点温度相对应的稳定执行器输出。必须落在执行器允许范围内。
FOPDT 的稳态关系:
PV_{\\mathrm{ss}}=PV_{\\mathrm{op}}+K(u-u_{\\mathrm{op}})
例如:
- 工作点温度 20℃;
- 工作点输出 0%;
- K=1℃/百分点;
- 当前输出 60%。
则新的预测稳态温度:
PV_{\\mathrm{ss}}=20+1\\times(60-0)=80℃
为什么它很重要? 你可能把 K、τ、θ 都填对了,但工作点填错,模型预测的稳定温度就会整体偏移,导致目标看起来"怎么调都达不到"。
工作点 vs 初始温度:
- 工作点:某个稳定输出对应的稳态参考关系;
- 任务初值:这次仿真从哪个状态开始。
它们可以不同。
六、两节点加热模型的专用参数
以下字段仅 model.type=heating 时使用:
| 字段 | 此前默认 | 作用 |
|---|---|---|
heater_gain_c_per_output |
3.0 | 输出每增加一个单位,加热器稳态温升的模型增益 |
heater_tau_s |
10s | 加热器自身温度响应的时间常数 |
heat_transfer_per_s |
0.5 /s | 加热器向被控对象传热的系数 |
cooling_per_s |
0.05 /s | 被控对象向环境散热的系数 |
**举例:**加热器自身可能 10 秒内明显升温,但水箱因热容量大,升温速度较慢。
- 加大
heater_tau_s:加热器本身反应更慢; - 加大
heat_transfer_per_s:模型中的传热更快; - 加大
cooling_per_s:模型中的散热更强。
不要把这些参数误填到 FOPDT 模型里,也不要把它们直接理解成设备铭牌上的物理常数。
6.1 自定义工厂:custom_factory
此前默认:空字符串。
只有选择 custom 时才需要填写,例如:
text
examples.custom_model:create_model
这表示 Python 模块和函数入口;实际代码必须满足项目规定的接口。
七、历史数据模块:CSV 怎么准备?
关键规则:只有 model.source=csv 时,history 配置才会被读取。
7.1 文件路径:history.file
此前默认:""(空)。
例如:
text
data/step.csv
仓库说明:相对路径相对于当前配置文件所在目录。文件必须真实存在、可读取。
7.2 时间单位:history.time_unit
此前默认:s。 还支持 ms。
| 设置 | 表示 | CSV 数字 1000 的含义 |
|---|---|---|
s |
秒 | 1000 秒 |
ms |
毫秒 | 1 秒 |
这是必须检查的项目。 毫秒误当秒,会把时间尺度错认约 1000 倍,从而严重影响 τ、θ 的辨识结果。
7.3 CSV 列名映射:history.columns
此前默认:
| 程序字段 | 默认 CSV 表头 | 对应内容 |
|---|---|---|
time |
timestamp |
时间 |
temperature |
input |
被控量测量值 |
output |
pwm |
实际执行器输出 |
特别注意:默认 CSV 表头 input 在这里是测得的温度/被控量 ,不是控制器输出;默认表头 pwm 才是实际输出。不要只看英文单词就把两列反过来。
例如你的 CSV 表头为:
csv
time_s,water_temp,heater_percent
0,50.0,20
1,50.0,20
2,50.0,20
3,50.0,40
4,50.1,40
5,50.3,40
...
那么映射应写为:
json
{
"time": "time_s",
"temperature": "water_temp",
"output": "heater_percent"
}
上面仅用于展示 CSV 结构和列名。真正用于辨识的数据应记录足够长的阶跃前稳定段和阶跃后基本稳定段,不能只有这几行。
7.4 使用历史数据中的工作点:use_recorded_operating_point
此前默认:true。
true:把 CSV 阶跃前测得的温度与输出作为模型工作点;false:使用model.operating_temperature_c和model.operating_output中手动填写的工作点。
例子:
- CSV 阶跃前温度稳定在 50℃;
- 输出稳定在 20%。
设置为 true,就让模型以这组记录值为工作点。
**怎么选:**若历史数据的阶跃前基线可靠,通常保持 true。如果基线不稳定或有明显扰动,应该先处理数据,而不是随意切换来"凑"结果。
八、怎样采集一份适合辨识的阶跃数据?
这部分是通用系统辨识实践建议,并非仓库保证自动完成的功能。
8.1 一份合格的阶跃数据应长什么样?
假设加热器初始输出为 20%,温度稳定在 50℃,之后把输出调整到 40%。
理想的采集过程:
- 阶跃前基线:先保持 20% 一段时间,确认温度基本稳定;
- 清晰阶跃:在一个明确时刻,把输出从 20% 改为 40%;
- 记录真实输出:不能只记录"指令是 40%",还要确认实际执行器输出;
- 持续采样:记录温度从开始响应到逐渐接近新稳态的过程;
- 稳定末段:留出足够长的后段,帮助估计最终温度变化;
- 记录环境与异常:尽量避免同时发生其他大扰动,否则辨识可能把扰动误认为过程响应。
**真实设备实验提醒:**现场阶跃测试需要操作权限、工艺风险评估、保护措施和人员监护。本文不建议未经授权直接改变工业设备输出。
8.2 为什么一定要有阶跃前基线?
没有基线,就难以判断:
- 改变输出之前温度是多少;
- 原来的输出是多少;
- 响应是否已经稳定;
- 变化究竟来自阶跃还是本来就在升温。
如果只截取"温度开始上升之后"的数据,可能把 θ 估计得过小。
8.3 为什么需要阶跃后稳定末段?
过程增益需要:
K=\\frac{\\Delta PV_{\\mathrm{稳态}}}{\\Delta u}
如果你在温度还没稳定时就结束记录,可能把最终温升估小,继而把 K 估小,影响整定结果。
8.4 为什么不要在同一份数据里连续乱改输出?
仓库注释明确要求的是单次阶跃数据。如果在一个记录里连续改变输出,原先的一次阶跃辨识假设就可能不成立。
如果必须处理多次阶跃或复杂工况,可能需要另用更适合的辨识方法,不能直接假设当前 CSV 辨识器支持。
九、离线辨识参数:identification
这些参数与历史数据紧密相关,建议一起理解。
9.1 离线探测总时长:probe_duration_s
此前默认:960s。
作用:决定软件离线阶跃记录观察多久,包括短暂的阶跃前基线。仓库说明已知模型做原辨识对照时也使用它。
**怎么用:**如果对象很慢,例如 τ 已达到 1000 秒,那么 960 秒可能不足以观察到稳定末段;需要延长记录时间。
9.2 探测输出变化幅度:probe_output_change
此前默认:20。
单位与 actuator.unit 一致。如果输出是 %,表示改变 20 个百分点。
例如原输出 30%,变化幅度 +20,新输出为 50%。
**注意:**阶跃后输出仍需处于执行器最小值与最大值之间。它是离线模型探测设置,不是对真实设备的操作授权。
9.3 最大相对拟合误差:max_relative_rmse
此前默认:0.05,即 5%。
仓库说明中采用:
\\text{相对拟合误差} =\\frac{\\mathrm{RMSE}}{\|\\Delta PV_{\\mathrm{step}}\|}
其中:
\\mathrm{RMSE} =\\sqrt{\\frac{1}{N}\\sum_{i=1}\^{N}(\\hat y_i-y_i)\^2}
y_i:记录的被控量;ŷ_i:模型预测的被控量;N:参与评价的数据点数量。
例子:
- 阶跃后温度总变化 40℃;
- 模型拟合 RMSE 为 1℃。
则:
1/40=2.5%
低于 5%,满足这一拟合误差门槛。
如果 RMSE 为 3℃:
3/40=7.5%
超过门槛,按仓库配置说明应拒绝继续,先检查数据质量或模型适用性。
**很重要:**拟合误差合格,不代表真实系统在所有工况下都准确,也不代表后续 PID 一定满足控制要求。
十、完整操作案例一:我已经知道 K、τ、θ
目标:研究一个 30℃ → 100℃ 的温控任务。
| 设置 | 填写值 |
|---|---|
model.type |
fopdt |
model.source |
parameters |
model.K |
1.0 |
model.tau_s |
120 |
model.theta_s |
10 |
model.operating_temperature_c |
20 |
model.operating_output |
0 |
task.initial_temperature_c |
30 |
task.target_temperature_c |
100 |
actuator.min/max |
0/100 |
| 运行模式 | test |
第一步:检查稳态能不能达到目标
根据模型:
PV_{\\mathrm{ss}}=20+1\\times u
要达到 100℃,稳态所需输出为:
u=\\frac{100-20}{1}=80%
输出范围 0~100%,从稳态能力看可以达到。
第二步:让程序计算 PID 候选
使用 Z-N、SIMC 等算法计算 Kp、Ki、Kd。注意算法输出仍需通过参数护栏与仿真评价。
第三步:看结果
主要观察:
- 辨识/模型参数是否与你填写的一致;
- 哪条整定路线生成了候选;
- 是否有护栏拒绝;
- 是否出现超调、振荡、输出饱和;
- 是否达到评价模块中的末段误差和调节时间要求。
十一、完整操作案例二:我只有一份历史 CSV
假设已经有一次合法、安全采集的阶跃响应记录:
- 阶跃前输出约 20%;
- 阶跃后输出约 40%;
- 温度从约 50℃ 逐渐接近 70℃;
- CSV 有时间、温度、实际输出三列。
第一步:选择模型和来源
| 设置 | 值 |
|---|---|
model.type |
fopdt |
model.source |
csv |
第二步:填写 CSV 配置
json
{
"file": "data/step.csv",
"time_unit": "s",
"columns": {
"time": "time_s",
"temperature": "water_temp",
"output": "heater_percent"
},
"use_recorded_operating_point": true
}
这段是 history 子对象示例,不是完整项目配置。路径和列名必须与真实文件一致。
第三步:检查数据是否适合辨识
- 时间是否单调、单位是否正确;
- 阶跃前是否稳定;
- 是否只有一次主要阶跃;
- 阶跃后的末段是否接近稳定;
- 实际输出是否记录完整;
- 温度和输出单位是否与项目设置一致。
第四步:运行辨识并查看结果
关注辨识得到的 K、τ、θ,以及相对 RMSE 是否小于阈值。
不要预先假设结果一定等于"温升 20℃/输出变化 20%=K=1",因为真实数据还会受到噪声、扰动、未稳定、传感器延迟和模型误差影响。
第五步:再进行整定与仿真
辨识合格后,才将模型交给 Z-N、SIMC 等路线计算候选 PID;候选还要经过护栏和完整闭环评价。
十二、四个推荐对照实验
实验 A:固定 K、θ,只改变 τ
设置 K=1、θ=10s,分别使用 τ=60s、120s、240s。
**观察:**过程响应快慢和整定参数如何变化。注意 τ 很大时应适当延长仿真时长。
实验 B:固定 K、τ,只改变 θ
设置 K=1、τ=120s,分别使用 θ=0s、10s、30s。
**观察:**纯滞后对控制难度、超调和调节时间的影响,以及某些 Z-N 路线的适用性变化。
实验 C:固定 K、τ、θ,改变工作点
将工作点温度从 20℃ 改为 40℃,工作点输出仍为 0%,其他不变。
**观察:**相同输出对应的稳态温度如何变化。这个实验用于理解工作点,而不是证明真实设备可以随意改变工作点。
实验 D:用离线 probe 观察辨识质量
选择 FOPDT + probe,固定模型参数,分别调整探测时长,例如 300s、960s、1500s。
**观察:**辨识得到的 K、τ、θ 和相对 RMSE 是否随记录长度变化。
十三、常见问题
Q1:我想直接输入 K、τ、θ,应该选 manual 吗?
不是。选 parameters。manual 指从用户初始 PID 进入仿真和可选 LLM 路线,不使用常规辨识公式作为初值。
Q2:为什么 CSV 里 input 对应温度,pwm 才是输出?
因为它们是仓库示例使用的 CSV 表头名称。程序内部固定键是 temperature 和 output,你可以按自己 CSV 的实际表头映射,不能根据英文直觉判断列含义。
Q3:只要 CSV 能读取,辨识就一定正确吗?
不一定。时间单位、单次阶跃、基线、稳定末段、噪声、扰动以及模型结构都会影响结果。
Q4:拟合 RMSE 很小,为什么 PID 还是可能不合格?
模型拟合和闭环控制是两个不同环节。PID 还会受到执行器限制、控制目标、采样周期和整定算法等因素影响。
Q5:probe 会自动操作真实设备吗?
不会。仓库配置明确将其定义为离线模型阶跃辨识。
Q6:模型 K、τ、θ 超出合理范围,要自动重新辨识吗?
要先区分问题:数据或模型不可信时才考虑补充数据/重新辨识;如果只是 Z-N/SIMC 计算出的 PID 参数超出护栏,不能因此直接断言模型错误。
Q7:模型中的工作点与历史 CSV 的工作点冲突怎么办?
先核对历史数据基线是否可靠。use_recorded_operating_point=true 时使用 CSV 的阶跃前工作点;关闭时使用手填工作点。两者不应在未经检查时混用。
Q8:我能直接把这个模型用于压力和流量吗?
只有对象的动态特性适合该模型时才可以。还要同步核对被控量单位、执行器单位、模型增益、任务目标和评价限制,不能只更换显示名称。
十四、使用前检查清单
- 选对模型类型:FOPDT / 积分 / 两节点加热 / 自定义。
- 选对模型来源:已知参数 / CSV / 离线探测 / 手动初始 PID。
- K 的符号、单位和数量级合理。
- τ、θ 的时间单位是秒。
- 工作点被控量与工作点输出对应。
- 使用 heating 时,专用传热参数有合理依据。
- 使用 CSV 时,文件路径存在,时间单位正确。
- CSV 的温度列与输出列没有填反。
- CSV 包含阶跃前基线、单次阶跃和基本稳定末段。
-
use_recorded_operating_point选择符合数据实际情况。 - probe 时长足够、输出阶跃幅度在执行器范围内。
- 相对 RMSE 门槛不是为了"让结果通过"而随意放宽。
- 先在
test模式下完成离线辨识和 PID 仿真。
十五、最重要的使用原则
先弄清对象是什么,再决定怎样辨识,最后才是 PID 整定。
model.type决定用什么数学结构描述对象;model.source决定模型参数从哪里来;K、τ、θ决定 FOPDT 对象怎样响应;history决定历史 CSV 如何被正确读取;identification决定离线探测和拟合质量要求;- 辨识结果进入整定与评价,但辨识合格不等于 PID 合格;
- PID 候选超限不等于模型错误,二者应分开处理。
对于刚入门的使用者,推荐依次完成 parameters → probe → csv 三个阶段:先理解已知模型,再观察软件辨识,最后尝试处理真实历史数据。
设备接入模块使用说明
前面几个模块解决的是:
- 任务与对象:要控制什么、目标是什么?
- 模型与历史数据:对象的动态特性是什么?
- 控制器与评价:哪一组 PID 参数在离线仿真中表现合格?
设备接入模块 解决的是:怎样把已经离线验证的参数,在满足条件时写入指定设备,并确认写入结果、短时间观察设备状态。
这里必须分清两种运行模式:
| 模式 | 做什么 | 是否连接/写入设备 |
|---|---|---|
test |
辨识、整定、LLM 可选建议、完整仿真评价 | 不创建设备接口,不写入 |
use |
完成离线验证后,读取设备、核对状态、条件写入、读回、限时监测 | 可能写入真实设备,取决于适配器及写入开关 |
重要:use 不代表程序取代 PLC/DCS 做持续闭环控制。 项目负责一次受控的参数部署流程;后续连续采样、PID 计算和执行器输出,仍由设备控制器承担。
text
PID Workbench
模型辨识 / Z-N / SIMC / LLM
↓
参数护栏检查
↓
完整闭环仿真
↓
选出合格参数
↓
读取设备当前状态与版本
↓
检查单位/控制律/工况变化
↓
条件写入 PID 和目标
↓
独立读回核验
↓
有限时间监测
↓
保存审计记录
实时闭环控制仍由 PLC / DCS / 设备控制器执行
安全边界:仓库已验证模拟适配器和本机 TCP 演示流程,但这不等于任何工业 PLC/DCS 接入后即可投产。真实装置仍需要厂商协议映射、单位核对、现场验证和独立安全保护。
二、接口类型:device.adapter
默认:disabled。
这是本模块最重要的下拉选项,决定程序通过什么方式与设备通信。
| 选项 | 中文解释 | 适用情况 |
|---|---|---|
disabled |
禁用设备接入 | 默认离线测试 |
simulated |
内存模拟设备 | 第一次练习 use 模式,推荐 |
tcp |
TCP JSONL 网关 | 已有符合项目协议的 TCP 网关 |
serial |
串口 JSONL 网关 | 已有符合项目协议的串口网关 |
custom |
自定义 Python 适配器 | 需要对接 Modbus、OPC UA 或厂商 SDK |
2.1 disabled:关闭接入
这是默认值。用于只做离线整定和仿真,不需要真实设备。
**建议:**刚开始学习时,保持 mode=test、adapter=disabled、write_enabled=false。
2.2 simulated:本机模拟设备
程序创建一个内存中的模拟对象,用它练习读取设备、写入 PID、读回、监测和记录审计。
**适合:**在没有 PLC、加热器或现场网关时,理解完整的设备部署流程。
**注意:**模拟适配器不控制真实设备。即使模拟流程通过,也不能据此断言真实现场已经安全。
2.3 tcp:TCP 网关
通过 host 和 port 连接一个已经实现项目 JSONL 协议的网关。
例如本机演示网关使用:
text
host = 127.0.0.1
port = 9100
这里的 127.0.0.1 指本机;9100 是示例网关端口,不是工业设备的通用端口。
关键:填了 PLC 的 IP 地址,不等于程序就会自动识别 PLC。 当前 TCP 适配器使用的是项目定义的 JSONL 消息格式,不能直接假定任何 PLC 的原生协议都兼容。
2.4 serial:串口网关
通过串口连接实现了同一 JSONL 协议的设备/网关。
例如:
text
serial_port = COM3
baud = 115200
需要安装串口依赖。串口名称、波特率必须与实际设备一致。
**注意:**这里是"串口上的 JSONL 网关",不是所有串口设备都能直接连接。设备如果只输出普通 CSV 或自定义二进制帧,需要另外适配。
2.5 custom:自定义适配器
如果设备使用 Modbus TCP、OPC UA、厂商 SDK 或其他协议,可以自己实现适配器,再让程序通过 custom_factory 加载。
这不是"选择 custom 后自动兼容所有工业协议",而是由你或设备开发人员实现协议转换。
三、写入开关:device.write_enabled
默认:false。
这是显式的设备写入许可开关。
mode |
write_enabled |
实际含义 |
|---|---|---|
test |
false |
离线测试,不连接设备 |
test |
true |
仍然不连接设备;test 模式优先 |
use |
false |
不具备写入许可,不能完成设备参数部署 |
use |
true |
允许在通过全部检查后尝试写入 |
重点:write_enabled=true 不等于"立刻写入成功"。
实际还需要:有合格候选、设备协议正确、设备状态新鲜、对象标识匹配、控制器语义一致、写入前工况变化未超限,以及网关接受条件写入。
**怎么用:**初学阶段不要为了"看看效果"就把真实设备写入开关打开。先用 simulated 或本机 TCP 演示完成验证。
四、对象标识:device.object_id
默认:temperature-loop-1。
用于标识具体哪一条控制回路,防止把参数写到错误对象。
例如工厂里可能有:
temperature-loop-1:一号水箱温度;temperature-loop-2:二号水箱温度;pressure-loop-1:某条管线压力。
这些只是命名示例。项目要求网关读回的 object_id 与配置一致。
为什么要有它?
假设程序准备给一号水箱写入 Kp=2,但连接到的网关实际返回二号水箱状态。如果没有对象标识核验,就可能把正确参数写到错误回路。
**怎么用:**让设备适配器/网关与项目配置使用完全一致、稳定、唯一的对象标识。
五、网络与串口连接参数
5.1 host:TCP 地址
默认:空字符串。仅 tcp 使用。
填写网关 IP 或主机名,例如本机演示使用 127.0.0.1。
它是网关地址,不一定是 PLC 自身地址。如果 PLC 使用其他协议,需要先由网关完成协议映射。
5.2 port:TCP 端口
默认:9100。仅 tcp 使用。
范围为 1~65535,必须与网关实际监听端口一致。
例如网关监听 9100,客户端填 9101,通常就无法连接。
5.3 serial_port:串口名称
默认:空字符串。仅 serial 使用。
Windows 例子:COM3;Linux 例子:/dev/ttyUSB0。
**怎么用:**先确认操作系统识别的串口名称,并确保没有被其他程序独占。
5.4 baud:波特率
默认:115200。仅 serial 使用。
表示串口传输速率。通信双方必须匹配。
例如网关设为 115200,程序却设成 9600,就可能收不到正确数据。
5.5 custom_factory:自定义适配器入口
默认:空字符串。仅 custom 使用。
格式是:
text
模块名:函数名
例如:
text
my_device_adapter:create_device
该 Python 函数需要返回符合项目设备接口契约的对象,至少支持读取状态、条件写入和关闭连接。详细契约见后面的"自定义适配器"。
六、通信超时与数据新鲜度
这两个参数很容易混淆,但用途完全不同。
6.1 timeout_s:通信超时
默认:5s。
作用:等待设备通信响应最多多久。
例如程序发出 read_state 请求,5 秒内没有收到符合要求的响应,就按超时处理。
它不代表设备采样周期,也不代表 PID 调节时间。
**怎么用:**根据网关正常通信延迟选择;太短容易误判网络抖动,太长会拖慢故障发现。真实设备不应只靠延长超时掩盖通信不稳定。
6.2 max_sample_age_s:数据最大年龄
默认:10s。
作用:判断设备返回的状态是否足够新。
例如现在是 12:00:20,网关返回的数据时间戳是 12:00:05:
\\text{数据年龄}=20-5=15s
15 秒大于允许的 10 秒,这份状态太旧,应被拒绝使用。
为什么重要? 通信成功不代表数据新鲜。网关可能还在返回缓存的温度,实际设备已经变化了。
**怎么用:**根据实际设备采样和网络延迟设置,同时确保网关与客户端时钟同步。
七、设备监测参数
设备写入后,程序会继续观察一段时间,检查温度和状态是否异常。
7.1 monitor_duration_s:监测时长
默认:30s。
表示写入并读回确认后,继续观察设备多久。
30:监测约 30 秒;60:监测约 60 秒;0:只做读回确认,不继续监测。
注意:这不是永久监控服务。 监测时间结束后程序退出,不能替代现场 PLC/DCS/SIS 的连续保护。
7.2 monitor_interval_s:监测间隔
默认:1s。
表示每隔多长时间读取一次设备状态。
例如监测 30 秒、间隔 1 秒,程序会进行一系列周期性状态检查;具体请求次数以实际实现与运行时序为准。
区别:
- 监测时长:一共观察多久;
- 监测间隔:多久检查一次。
模拟适配器会按该间隔推进模拟时间,并可能加速运行。
7.3 monitor_min_temperature_c:监测最低温度
默认:−20℃。
设备监测阶段允许的最低温度;低于该值视为异常。
7.4 monitor_max_temperature_c:监测最高温度
默认:120℃。
设备监测阶段允许的最高温度;超过该值视为异常。
举例:
假设目标温度为 100℃,设备监测上限为 120℃:
- 101℃:未超过该监测上限;
- 119℃:未超过该监测上限;
- 121℃:越界,触发异常处理。
这不代表 119℃ 对你的工艺一定安全。 默认门槛是项目示例,需要根据真实设备、工艺和独立保护策略重新确定。
与评价模块的区别:
| 参数 | 用于哪里 | 默认值 |
|---|---|---|
evaluation.max_temperature_c |
离线仿真是否合格 | 102℃ |
simulation.temperature_stop_max_c |
仿真是否提前停止 | 150℃ |
device.monitor_max_temperature_c |
写入后的设备限时监测 | 120℃ |
三个数值不同、用途不同,不能混为一谈。尤其不能把设备监测阈值当作硬件安全联锁。
八、故障恢复:restore_on_fault
默认:true。
作用:程序确认自己成功写入后,如果监测期间发生异常,尝试恢复原来的 PID 和目标值。
例如:
- 写入前:
Kp=1, Ki=0.01, Kd=0,目标 80℃; - 新参数:
Kp=2, Ki=0.02, Kd=0,目标 100℃; - 写入成功、读回确认;
- 监测时发现温度越界。
如果允许恢复,程序会尝试把原 PID 和目标恢复。
为什么叫"尝试",而不是"保证恢复"?
因为恢复也依赖通信和设备状态:
- 如果网关断线,恢复命令可能发不出去;
- 如果设备被其他操作员修改过,不能擅自覆盖别人最新的设置;
- 如果写入回执丢失,程序可能不知道写入是否真正成功。
因此项目采用**配置版本(revision)**检查:只有确认当前版本仍属于本次程序写入,才尝试恢复旧配置。
重点:恢复旧 PID 不等于设备自动恢复安全。 旧参数也不一定适合当前异常工况;真实安全保护仍由独立设备系统负责。
九、写入前的工况变化限制
这是项目里非常值得理解的两个参数。它们和 PID 增长倍数不是同一种检查。
9.1 max_planning_temperature_change_c
默认:2℃。
作用:从最初读取设备状态,到离线整定计算结束准备写入时,允许设备温度变化的最大幅度。
例如:
- 开始计算时温度为 80℃;
- 计算结束时重新读取为 83℃;
- 温度变化 3℃;
- 允许最大变化为 2℃。
则拒绝本次写入。
为什么? 因为 PID 候选是在之前的设备状态下规划、验证的。如果计算期间设备已经明显变化,原来的部署条件可能不再成立。
9.2 max_planning_output_change
默认:5,单位同执行器。
作用:限制离线规划期间设备实际输出变化的幅度。
例如输出单位为 %:
- 开始计算时输出 30%;
- 计算结束时输出 38%;
- 变化 8 个百分点;
- 允许最大变化为 5 个百分点。
则拒绝写入。
9.3 这两个参数与 Kp 增长倍数有什么区别?
| 限制 | 比较对象 | 目的 |
|---|---|---|
Kp 最大增长倍数 |
新 PID 参数 vs 设备当前 PID 参数 | 限制参数变更幅度 |
| 规划期间温度变化 | 写入前温度 vs 最初读取温度 | 检查设备工况是否改变 |
| 规划期间输出变化 | 写入前输出 vs 最初读取输出 | 检查执行器状态是否改变 |
例如,Kp 从 1 改到 2 可能符合参数增幅限制,但如果计算期间温度从 80℃ 升到了 90℃,仍可能因工况变化过大而拒绝写入。
这两类检查必须分别通过。
十、use 模式实际怎样执行?
根据项目设备协议文档,使用模式的核心流程如下。
第一步:离线辨识、整定与评价
程序先获取对象模型并计算候选 PID。
按你已采用的新版护栏方案:
- 公式候选超限:拒绝整组,记录原因;
- LLM 建议超限:拒绝整组,有限重试;
- 合法参数:完整仿真;
- 无合格候选:不进入写入流程。
第二步:读取设备当前状态
设备应提供:
object_id:回路标识;revision:配置版本;timestamp_s:采样时间;- 当前 PID 参数;
- 当前温度、输出和目标;
- 采样周期、输出单位和范围;
- 微分、滤波、初始化、抗积分饱和等控制器语义。
程序不是只读取温度,而是要确认现场控制器是否能按预期理解即将写入的 PID 参数。
第三步:检查一致性
例如软件使用并联式 Kp/Ki/Kd,设备却使用另一种积分时间、微分时间或增量式 PID 表示法,不能直接把数字照抄过去。
还要检查:
- 单位是否一致;
- 输出上下限是否一致;
- 采样周期是否一致;
- 控制方向与滤波等语义是否匹配;
- 数据是否新鲜;
- 是否连接了正确回路。
第四步:写入前再次读取
因为离线整定可能耗时,程序在写入前重新检查设备:
- 配置版本是否仍然一致;
- 温度变化是否超出允许范围;
- 输出变化是否超出允许范围;
- 最终参数相对设备原参数是否符合增幅约束。
任一必要条件不满足,就应拒绝写入。
第五步:条件写入
项目协议采用 expected_revision,要求网关执行原子版本比较与写入。
意思是:
"只有设备配置版本仍然是我刚才看到的版本,才允许写入新 PID 和目标。"
这能避免程序在不知道的情况下覆盖其他人刚修改的参数。
第六步:独立读回
网关说"写入成功"还不够。
程序还要重新读取设备,核对:
- PID 是否真的变成新参数;
- 目标是否正确;
- 配置版本是否更新;
- 对象标识是否正确。
第七步:限时监测与故障处理
读回确认后,按监测时长和间隔观察设备。
如果发生温度越界、数据过期、通信失败或外部修改,就记录异常;满足恢复条件时尝试恢复原配置。
监测结束后程序退出,不持续接管设备。
十一、JSONL 网关协议是什么?
JSONL = JSON Lines,意思是一行一个 JSON 对象,以换行符结束。
项目的 TCP 和串口适配器使用这一协议。
11.1 读取设备状态
请求示意:
json
{"protocol_version":1,"request_id":"request-123","operation":"read_state","object_id":"temperature-loop-1"}
网关需要返回协议版本、请求 ID、ok 和实际设备状态。
关键状态字段示意:
json
{
"protocol_version": 1,
"request_id": "request-123",
"ok": true,
"state": {
"object_id": "temperature-loop-1",
"revision": 12,
"timestamp_s": 1791432000.0,
"pid": {
"controller_form": "parallel",
"parameter_time_unit": "s",
"Kp": 1.0,
"Ki": 0.01,
"Kd": 0.0
},
"sample_time_s": 1.0,
"output_unit": "%",
"output_min": 0.0,
"output_max": 100.0,
"output_bias": 0.0,
"max_rate_per_s": 10.0,
"derivative_on": "measurement",
"derivative_filter_s": 0.5,
"anti_windup": "conditional",
"initialization": "zero",
"temperature_c": 30.0,
"output": 0.0,
"setpoint_c": 30.0
}
}
注意:时间戳是协议示例值,不能复制成真实设备的当前时间戳。
11.2 写入 PID 参数
请求示意:
json
{
"protocol_version": 1,
"request_id": "request-124",
"operation": "apply_parameters",
"object_id": "temperature-loop-1",
"expected_revision": 12,
"pid": {
"controller_form": "parallel",
"parameter_time_unit": "s",
"Kp": 2.4,
"Ki": 0.02,
"Kd": 0.0
},
"setpoint_c": 100.0,
"initialization": "zero"
}
成功回执示意:
json
{"protocol_version":1,"request_id":"request-124","ok":true,"revision":13}
为什么 expected_revision=12,返回 revision=13?
因为写入前版本为 12;只有版本仍为 12 时,网关才允许修改,并在成功后产生新版本 13。
版本变化是控制配置发生变化,不是每次读取温度都要加 1。
11.3 网关必须遵守哪些要求?
项目协议明确要求:
- 协议版本为 v1;
- 每条请求和响应使用对应
request_id; - 一行一个 JSON 对象;
- 状态带 Unix 秒时间戳;
revision代表控制配置版本;- 条件写入必须原子完成;
ok=true必须代表完整事务成功,不能只表示"收到请求";- 写入后支持独立读回;
- 响应大小有上限,网关与客户端需要同步时钟。
TCP 适配器本身不提供 TLS/认证。 不应将演示 TCP 网关直接暴露到公网;需要安全通信时,应在经过验证的网关或自定义适配器中实现认证、加密和网络访问控制。
十二、自定义适配器:为什么需要自己写代码?
项目没有内置任意 PLC 品牌的寄存器地址或所有厂商协议。
如果现场 PLC 使用 Modbus TCP,你可能需要做这样的转换:
text
PID Workbench
↓ 统一设备接口
自定义 Python 适配器
↓ 厂商协议 / Modbus / OPC UA
PLC / DCS
↓
实际 PID 控制回路
项目协议要求自定义工厂大致实现以下接口:
python
def create_device(config):
return Device(config)
class Device:
def __init__(self, config):
self.config = config
def read_state(self):
# 从真实设备读取当前状态并转换成项目规定的状态结构
raise NotImplementedError
def apply(self, pid, setpoint, expected_revision):
# 实现版本条件检查、完整写入及回执
raise NotImplementedError
def close(self):
# 释放连接资源
pass
这是接口结构示意,不是可以直接驱动 PLC 的完整代码。
实际实现时必须正确处理:
- 寄存器或变量地址映射;
- 参数单位和控制器形式换算;
- 版本一致性;
- 原子写入或等效事务保证;
- 写入确认与独立读回;
- 异常处理和访问权限。
如果设备不支持所需的原子条件写入语义,不能简单地伪造 revision 来宣称兼容。
十三、完整操作案例一:零设备基础,先用模拟设备
这是最推荐的入门方式。
13.1 使用桌面界面
在界面中选择:
| 项目 | 设置 |
|---|---|
| 运行模式 | use |
| 设备接口 | simulated |
| 允许写入 | true |
| 对象标识 | temperature-loop-1 |
| LLM | 先关闭 |
| 监测时长 | 30s |
| 监测间隔 | 1s |
其他模型、任务、控制器、评价参数先采用软件示例配置。
**注意:**这是对模拟设备的写入许可,不是真实设备。
13.2 使用源码运行
项目提供了现成的示例配置:
powershell
.\.venv\Scripts\python.exe pid_project.py --config examples/use_simulated.json --validate
.\.venv\Scripts\python.exe pid_project.py --config examples/use_simulated.json
如果还没有创建 .venv,需要先按照项目 README 完成安装。
13.3 运行后看什么?
查看本次结果目录中的:
report.html:整定与评价报告;pid.json:最终 PID 结果;device_audit.json:设备操作审计。
重点核对:
- 是否读取初始设备状态;
- 是否有合格 PID 候选;
- 是否记录写入请求和回执;
- 是否进行了独立读回;
- 是否记录监测过程;
- 如果拒绝写入,拒绝原因是什么。
十四、完整操作案例二:本机 TCP 网关联调
这个案例测试真正的 TCP 收发和 JSONL 消息处理,但仍然不接真实设备。
14.1 打开两个 PowerShell 终端
两个终端都进入项目根目录。
终端一:启动演示网关
powershell
.\.venv\Scripts\python.exe -m thermal_pid.gateway_demo --config examples/use_tcp_local.json --port 9100
终端二:运行设备接入客户端
powershell
.\.venv\Scripts\python.exe pid_project.py --config examples/use_tcp_local.json --validate
.\.venv\Scripts\python.exe pid_project.py --config examples/use_tcp_local.json
14.2 看什么结果?
检查运行目录中的 device_audit.json,观察:
- TCP 是否建立连接;
read_state是否成功;- 版本条件写入是否被接受;
- 写入后版本是否变化;
- 读回是否与请求一致;
- 监测是否正常结束。
演示网关只监听本机地址,操作内部模拟对象。测试完成后,在网关终端按 Ctrl+C 停止。
十五、真实设备接入前怎么准备?
这不是让你直接连接生产设备的操作步骤,而是上线前必须具备的条件。
15.1 配置应与 test 模式分开
项目建议保留 project.json 作为测试配置,另建本地使用配置,例如:
text
project.use.local.json
这样可以避免测试设置与真实设备设置混淆。
15.2 需要提前确认的条件
| 项目 | 必须确认什么 |
|---|---|
| 设备接口 | 有符合协议的网关或经过验证的自定义适配器 |
| 对象标识 | 对应正确的控制回路 |
| 过程模型 | 已经过足够的辨识与离线验证 |
| PID 形式 | 并联式、理想式等与设备一致或经过正确换算 |
| 参数时间单位 | 秒、分钟等完全一致 |
| 采样周期 | 软件与设备控制器语义匹配 |
| 微分与滤波 | 微分作用位置、滤波方式兼容 |
| 抗积分饱和 | 设备与软件的控制律语义兼容 |
| 输出能力 | 范围、单位、速率限制匹配 |
| 写入事务 | 支持条件写入和独立读回 |
| 安全保护 | 独立联锁、报警、急停等不依赖本软件 |
| 审批与调试 | 已完成现场变更流程和验证 |
仓库 README 明确指出:当前不是面向任意厂商 PLC 的即插即用产品,真实设备必须完成协议映射和现场验证。
十六、报告与审计记录怎么看?
设备接入与离线 PID 仿真最大的区别是:不仅要看参数效果,还要看设备操作是否真实、完整、可追溯。
16.1 report.html
主要看:
- 哪组 PID 参数通过评价;
- 是否有候选被护栏拒绝;
- 是否存在仿真失败或评价不达标;
- 最终参数与原设备参数的关系。
16.2 pid.json
主要看最终是否有合格 PID。若没有合格参数,不能把诊断候选当成可应用参数。
16.3 device_audit.json
主要看设备接入全过程:
| 记录类型 | 应关注的问题 |
|---|---|
| 初始状态 | 连接的是正确回路吗?数据新鲜吗? |
| 写入前检查 | 配置版本与工况是否变化? |
| 写入请求 | 请求写入了哪些 PID 和目标? |
| 写入回执 | 网关是否明确确认成功? |
| 读回确认 | 设备实际值与请求一致吗? |
| 监测记录 | 温度、输出、通信是否正常? |
| 异常与恢复 | 是否尝试恢复?恢复是否得到确认? |
**特别注意:**通信超时、回执丢失时,写入状态可能不确定。不能因为没有收到成功回执,就武断认定设备一定没写入;也不能因为发出了请求,就宣称成功。
十七、常见问题
Q1:为什么我选了 use,程序还是不写入?
可能原因包括:接口禁用、write_enabled=false、没有合格 PID、对象标识不一致、设备状态过旧、配置版本变化、规划期间温度或输出变化超限、控制器语义不兼容等。
Q2:write_enabled=true 是不是危险?
它只是开启"允许尝试写入"的许可。与 mode=use 和真实适配器组合时,就可能实际修改设备参数,因此必须严格管理;在 test 模式不会因此连接设备。
Q3:为什么写入后还要读回?
因为"网关收到命令"和"设备已经正确应用参数"是两回事。独立读回可以核对实际参数与版本。
Q4:为什么设备版本变化会拒绝写入?
防止覆盖其他操作员或控制系统在你计算期间进行的修改。这是并发变更保护。
Q5:restore_on_fault=true 能保证设备恢复安全吗?
不能。恢复依赖设备仍可通信、版本仍匹配,且旧参数本身适用于当前工况。它不能替代现场安全系统。
Q6:监测时间设置为 30 秒,30 秒后谁来控制设备?
设备自己的控制器继续闭环控制。PID Workbench 的设备接入流程不是永久在线控制服务。
Q7:我有一台支持 Modbus TCP 的 PLC,能直接填 IP 使用吗?
通常不能。当前内置 tcp 适配器使用 JSONL 网关协议;需要 Modbus-to-JSONL 网关或经过验证的 custom 适配器。
Q8:LLM 会直接控制真实设备吗?
不会。LLM 只提供参数建议;建议必须通过确定性护栏和完整仿真,最终还要经过设备状态与写入条件检查。实际闭环由设备控制器运行。
Q9:test 和 use 得到的 PID 为什么可能不同?
use 模式会参考设备当前参数和实际状态进行检查,最终候选可能因为设备增幅约束或工况变化被拒绝。按照新版方案,超限应拒绝整组或拒绝写入,而不是自动裁剪成另一组参数。
Q10:TCP 通信是不是已经加密?
项目文档明确说明内置 TCP 适配器没有 TLS 和认证。真实网络环境应使用受管理的网络、网关认证/加密或经过验证的自定义实现。
十八、推荐的学习顺序
| 阶段 | 建议做什么 | 学到什么 |
|---|---|---|
| 1 | test + disabled |
理解离线整定与设备写入的边界 |
| 2 | use + simulated |
理解读取、写入、读回、监测 |
| 3 | use + 本机 TCP 演示 |
理解 JSONL 网关通信 |
| 4 | 阅读 DEVICE_PROTOCOL.md |
理解版本、时间戳和原子条件写入 |
| 5 | 在非生产测试环境开发自定义适配器 | 理解协议映射和现场一致性检查 |
| 6 | 经工程审核后评估真实设备应用 | 理解安全保护与受控变更 |
十九、使用前检查清单
- 明确当前是
test还是use。 - 确认
adapter是disabled、simulated、tcp、serial还是custom。 - 确认
write_enabled与当前任务目的匹配。 - 核对
object_id,避免写错回路。 - TCP 地址、端口或串口名称、波特率正确。
- 网关确实实现项目规定的 JSONL 协议。
- 通信超时和数据最大年龄设置合理。
- 设备与客户端时钟同步。
- PID 形式、时间单位、采样周期、滤波与抗积分饱和语义一致。
- 设备输出范围与速率限制一致。
- 规划期间温度/输出变化阈值合理。
- 设备监测阈值根据工艺确定,不直接照搬默认值。
- 理解
restore_on_fault只是有条件的恢复尝试。 - 先完成模拟设备和本机 TCP 演示测试。
- 真实设备接入经过协议验证、工程审批和独立安全检查。
- 运行后检查
device_audit.json,不能只看最终 PID 数字。
二十、最重要的使用原则
设备接入模块不是"把算出的 Kp、Ki、Kd 发过去"这么简单。
它必须回答:
- 写给谁? ------
object_id。 - 怎么连接? ------
adapter、TCP/串口/自定义协议。 - 有没有权限写? ------
mode=use和write_enabled。 - 设备状态可靠吗? ------ 时间戳、版本、控制器语义。
- 这组参数合格吗? ------ 护栏与完整仿真。
- 写入时设备有没有变化? ------ 写前重新读取与工况检查。
- 真的写成功了吗? ------ 条件写入和独立读回。
- 写入后有没有异常? ------ 限时监测和审计。
- 异常时怎么办? ------ 有条件恢复、现场独立保护。
控制器与评价模块使用说明
一、先理解整个工作流程
使用这个程序时,不是直接输入一组 PID 参数就结束了,而是经过:
text
设置控制目标与对象模型/辨识数据
↓
选择 Z-N、SIMC 等公式候选,或启动 LLM 调优
↓
检查参数护栏(超限 → 拒绝整组,不自动裁剪)
↓
合法候选进入完整闭环仿真
↓
检查超调、误差、调节时间、输出等评价指标
↓
从通过评价的候选中,按 accuracy/smooth/speed 选优
↓
test:生成离线验证结果
use:再检查设备参数变更约束,合格才进入受控应用流程
记住三件事:
- 参数护栏检查"这组 Kp、Ki、Kd 能不能作为候选"。
- 仿真与评价检查"这组合法参数能不能把对象控制好"。
- use 模式应用检查检查"这组已验证参数能不能按当前设备约束进行变更"。
通过第一关,不代表通过第二关;通过离线仿真,也不等于真实设备已经具备安全投用条件。
二、控制器设置
2.1 PID 参数形式:parallel / ideal
**作用:**决定 PID 参数如何表达。常见形式有两种。
并联式(parallel)
u(t)=K_p e(t)+K_i\\int_0\^t e(\\xi),d\\xi+K_d\\frac{de(t)}{dt}
理想式(ideal)
u(t)=K_c\\left\[e(t)+\\frac{1}{T_i}\\int_0\^t e(\\xi),d\\xi+T_d\\frac{de(t)}{dt}\\right
]
理想情况下二者换算为:
K_p=K_c,\\qquad K_i=\\frac{K_c}{T_i},\\qquad K_d=K_cT_d
**怎么用:**学习和纯仿真优先保持 parallel;与 PLC/DCS 对接时,应先核实设备手册中的 PID 形式、控制方向和单位。切换参数形式不代表换了一种整定算法。尤其注意 :当 Ki=0 时,理想式积分时间可视为禁用/无穷大,不能直接做除零换算。
2.2 参数时间单位:s / min
**作用:**决定参数时间量的表示/导出单位,不是 PID 多久计算一次。
s:秒;min:分钟。
例如积分时间 Ti=120s,等价于 2min。如果现场设备以分钟输入积分时间,而你误把 120 当作分钟,会产生严重偏差。
**怎么用:**项目内部仿真先用 s;设备导出时按设备手册核对。并联式 Ki、Kd 的单位变换也要相应处理,不能只替换单位标签。
2.3 采样周期:sample_time_s
此前默认:1.0s。
**作用:**PID 控制器每隔多长时间读取反馈并更新控制输出。
例如设为 1s:0 秒、1 秒、2 秒......各计算一次;设为 0.1s:每秒约计算 10 次。
- 太慢:可能错过快速变化,降低控制效果;
- 太快:增加计算量,也可能让测量噪声影响更明显;
- 温度通常较慢,流量等对象可能更快,但应以实际模型和硬件为准。
**怎么用:**默认温度仿真先保持 1s,换对象时根据过程时间常数、纯滞后、传感器和执行器能力重新选择。
2.4 微分作用位置:derivative_on
选项: measurement / error;此前默认 measurement。
error:对误差SP−PV求微分。设定值突然变化时,容易出现微分冲击;measurement:对测量值 PV 求微分(通常带负号),减少设定值阶跃直接引发的微分冲击。
**例子:**当前温度 80℃,把目标从 80℃ 改到 100℃。如果对误差微分,目标突变会造成瞬时很大的变化率;对 PV 微分时,温度本身没有瞬间变化,微分项不会因为 SP 的突变直接跳变。
**怎么用:**常规温度仿真建议保持 measurement。当 Kd=0 时,该设置基本不会影响 D 项,因为没有微分控制作用。
2.5 微分滤波时间:derivative_filter_s
此前默认:0.5s。
**作用:**减弱温度测量噪声被微分项放大的问题。
例如测量值在 79.9、80.1、80.0℃ 之间跳动,未经滤波的 D 项可能对这些微小变化过度敏感。
- 滤波时间小:响应快,但抑噪弱;
- 滤波时间大:抑噪强,但微分响应更慢;
0:通常表示不启用此滤波,具体以实现为准。
**怎么用:**默认值先不动;只有启用 Kd>0、且观察到 D 项噪声或响应迟缓时,再结合采样周期调整。
2.6 初始化方式:zero / tracking
这是容易误解的一项:初始化的不是 Kp、Ki、Kd,而是 PID 控制器内部的运行状态,尤其是积分累积值。
假设目标和实际温度都为 80℃,设备原本输出 40%,采用简化并联式:
u=K_pe+I+D
此时 e=0,假设 D=0。
zero:清零内部状态。 如果 I=0,在无偏置、前馈等其他机制时,控制器新输出可能从 40% 突然变成 0%。适合从头启动的独立仿真。
tracking:让内部状态尽量跟踪已有输出。 可以把积分状态预置为:
I=u_{\\text{原输出}}-K_pe-D=40
这样控制器接管时,输出可尽量维持 40%。
怎么选:
| 场景 | 建议 |
|---|---|
| 从初始状态运行的离线仿真 | zero |
| 从手动控制切换到自动控制 | 优先考虑 tracking |
| 正在运行的设备更换控制参数 | 需要验证无扰切换机制,不仅仅依赖 tracking |
tracking 不是绝对的无扰保证,仍要处理输出限幅、偏置、执行器状态和抗积分饱和等问题。
2.7 护栏策略:guardrail_policy
此前默认:auto。
注意:auto 是护栏策略 ,而 test / use 是运行模式,两者不是一回事。
按本次约定的新版方案:
| 场景 | 参数检查 | 超限后 |
|---|---|---|
test 中的初始 Z-N/SIMC 公式候选(默认 auto) |
绝对上下限 | 拒绝整组候选,继续尝试其他方法 |
test 中的 LLM 每轮建议 |
绝对上下限 + 本轮相对增幅 | 拒绝整组建议,反馈原因,允许有限重试 |
use 模式 |
绝对上下限 + 相对设备当前参数的增幅 | 拒绝本次写入,设备参数保持不变 |
relative 护栏策略 |
需要按该策略执行相对增幅检查 | 超限拒绝,而不是裁剪 |
为什么 test 的初始公式候选不默认受相对增幅限制? 假设初始 Kp=1、增长倍数 3,但 SIMC 根据模型计算出 Kp=10。如果只因初始值为 1 就强行限制到 3,会把公式结果改掉;而在 test 的公式候选阶段,通常更适合先用绝对范围筛选,再完整仿真。
为什么 use 仍检查相对增幅? 因为真实设备当前可能运行在 Kp=1,一次变更到 10 即使仿真合格,也可能超出现场变更权限。新版做法是拒绝写入并说明原因,而不是改成 3 后擅自应用。
参数超限不代表辨识模型错误。只有数据质量差、单位错误、拟合效果差等证据出现时,才考虑补充数据或重新辨识。
三、初始参数和参数护栏
3.1 初始 PID 参数
此前默认:
| 参数 | 默认值 | 含义 |
|---|---|---|
Kp |
1.0 | 比例增益 |
Ki |
0.01 | 积分增益 |
Kd |
0 | 微分增益 |
它们是起始或参考参数,不是 Z-N、SIMC 必须得到的最终参数。公式整定会依据过程模型计算新候选。
3.2 绝对范围
此前配置:
| 参数 | 最小值 | 最大值 |
|---|---|---|
| Kp | 0 | 5000 |
| Ki | 0 | 500 |
| Kd | 0 | 500 |
绝对范围与参考值无关。例如 Kp 允许 0~5000,那么 Kp=10 在范围内,Kp=6000 超出范围。
新版行为:超出任一项绝对范围,就拒绝整组 候选;不把 6000 自动裁剪成 5000。
注意:默认范围只是软件配置,不能证明范围内的所有参数都安全。
3.3 单项最大增长倍数
此前默认:
| 参数 | 最大增长倍数 |
|---|---|
| Kp | 3 |
| Ki | 4 |
| Kd | 4 |
**作用:**限制某次参数建议相对参考参数增加的幅度。它不是"参数每轮必须增长多少",也不是优化目标。
例如当前参考 Kp=2,倍数为 3,那么相对增长上限为:
K_{p,\\max}\^{rel}=2\\times3=6
建议 Kp=5 可以通过这一项;建议 Kp=10 则会因超过 6 而被拒绝。新版不会自动改成 6。
相对检查只在适用的阶段执行;如果参考参数为 0,不能机械地算出"上限=0",需要遵循程序对零参考值的专门处理规则。
3.4 全局最大增长倍数
此前默认:0,表示不增加额外的全局增长限制。
全局倍数与每个参数自己的倍数共同作用,取更严格的限制。
例如全局设置为 2:
- Kp 自身为 3 倍 → 最终按 2 倍检查;
- Ki 自身为 4 倍 → 最终按 2 倍检查;
- Kd 自身为 4 倍 → 最终按 2 倍检查。
如果全局设置为 5,原来的 3、4、4 倍仍然更严格。
**怎么用:**纯离线研究可以先保持默认 0;如需限制 LLM 每轮修改幅度,可结合单项限制设置。不要把增长倍数误认为参数越小就越安全。
3.5 相对限制和绝对限制为什么都需要?
假设:
- 当前参考
Kp=1; - 相对最大倍数为 3;
- 绝对最大值为 5000;
- 算法提出
Kp=10。
绝对检查:10≤5000,通过。
相对检查:10>1×3,不通过。
两者都是约束,区别在于:
- 绝对范围:定义系统允许的参数数值边界;
- 相对增幅:定义一次变更相对于参考值允许有多大。
在新版中,任一适用约束不通过都拒绝整组候选,而不是对某个参数单独裁剪。
四、评价参数:如何判断控制效果合格?
以下以**初始温度 30℃、目标温度 100℃**为例。先通过参数护栏的候选,才进入这些评价。
4.1 最大允许超调百分比
此前默认:5%。
在此前项目说明中,超调按"目标值与初始值之差"计算:
\\text{超调率}=\\frac{\\max(PV)-SP}{\|SP-PV_0\|}\\times100%
对于 30℃→100℃:
\|100-30\|=70℃
允许超调:
70\\times5%=3.5℃
仅按这一项计算,最高可到 103.5℃。但还必须满足独立的最高温度限制。
4.2 最高温度限制
此前默认:102℃。
这是绝对评价门槛。即使超调百分比允许到 103.5℃,只要最高温度超过 102℃,仍不合格。
**怎么用:**当工艺有明确的温度上限时,应使用独立绝对限值,不要只依赖超调百分比。
4.3 最低温度限制
此前默认:关闭(null)。
用于限制仿真中最低允许的被控量。例如降温过程不能低于某个温度。未设置时,不额外检查该项。
4.4 末段平均绝对误差
此前默认:0.3℃。
它评价仿真结束前一段时间是否足够接近目标。
假设末段测得 99.8、100.1、99.9、100.2℃,对应绝对误差为 0.2、0.1、0.1、0.2℃,平均值:
(0.2+0.1+0.1+0.2)/4=0.15℃
因此符合 0.3℃ 的要求。
注意:末段误差小,并不代表整个升温过程都好。
4.5 稳定偏差带
此前默认:1℃。
目标为 100℃ 时,稳定带是:
99℃\\leq PV\\leq101℃
温度偶然进入一次不代表已经稳定,还需要后续保持在带内。
4.6 最大调节时间
此前默认:600s。
调节时间不是第一次到达目标值的时间,而是响应进入稳定带并在后续持续保持的时间。
例如第 100 秒第一次达到 100℃,随后冲到 105℃;直到第 300 秒才进入 99~101℃ 并持续保持,则调节时间应按后面的稳定时刻判断。
4.7 最小稳定观察时间
此前默认:20s。
用于避免"最后一秒刚进入稳定带就算成功"。
例如仿真 600 秒,到第 599 秒才进入稳定带,就没有足够时间证明它能持续稳定 20 秒。
4.8 末段评价比例
此前默认:0.1,即最后 10%。
假设仿真总长 600 秒,末段评价窗口约为最后 60 秒。
该参数主要与"末段平均绝对误差"配合。它不代表仿真只运行 60 秒。
4.9 最大输出变化总量(TV)
此前默认:关闭。
TV(Total Variation)衡量整个仿真期间控制输出变化的累计幅度:
TV=\\sum_{k=1}\^{N}\|u_k-u_{k-1}\|
例如阀门输出:20% → 40% → 30% → 50%,则:
TV=20+10+20=50
TV 大可能意味着阀门频繁或大幅动作。设置上限可以限制控制输出过于激烈,但阈值需要结合输出量纲、仿真时长和设备特性选择。
4.10 最大饱和时间比例
此前默认:关闭。
假设执行器输出被限制在 0~100%,控制器有一部分时间一直顶在 100% 或 0% 上。
若最大饱和比例设为 0.2,600 秒仿真中允许饱和的累计时间比例最多为 20%,即约 120 秒。
它用于识别长期顶到输出边界的情况。短暂饱和并不一定是故障,长期饱和则值得检查设备能力、整定和工况。
4.11 评价优先级:accuracy / smooth / speed
此前默认:accuracy。
这一项用于在已经通过全部启用评价门槛的候选中择优,而不是放宽硬性条件。
| 选项 | 主要倾向 | 适合的目标 |
|---|---|---|
accuracy |
精度、累计误差(如 IAE) | 希望全过程尽量贴近设定值 |
smooth |
超调与输出平稳程度 | 希望减少振荡和执行器动作 |
speed |
调节时间 | 希望尽快进入稳定带 |
即使选择 speed,超过 102℃ 的候选也不能仅因"速度快"而通过。
五、关联板块:仿真与调优预算
虽然这部分可能在界面上独立成区,但它直接影响「控制器与评价」的运行结果,因此一并说明。
5.1 仿真参数
| 参数 | 此前默认 | 用途 |
|---|---|---|
| 仿真时长 | 600s | 一次完整闭环仿真的长度 |
| 随机种子 | 0 | 复现随机噪声 |
| 测量噪声标准差 | 0℃ | 模拟传感器读数波动 |
| 对象增益倍率 | 1.0 | 模拟辨识模型与真实对象不一致 |
| 扰动开始时间 | null |
关闭持续扰动 |
| 扰动变化率 | 0℃/s | 扰动对温度的持续影响 |
| 仿真最低停止温度 | −20℃ | 跌破后提前终止仿真 |
| 仿真最高停止温度 | 150℃ | 超过后提前终止仿真 |
仿真时长与最大调节时间不同。 前者决定模拟观察多久,后者决定性能是否达标。
随机种子让相同设置下的随机实验更容易复现;它不是噪声大小。
测量噪声标准差 若设为 0.1℃,表示噪声的标准差为 0.1℃,不是每次噪声都被限制在 ±0.1℃。
对象增益倍率 :若辨识模型的过程增益 K=2,倍率设为 0.8,仿真对象增益相当于 1.6。可以分别试 0.8 / 1.0 / 1.2,观察参数对模型偏差的敏感性。
扰动设置 :例如从第 200 秒开始,施加 −0.05℃/s 的持续变化率扰动,观察 PID 能否抵消干扰。它不是第 200 秒瞬间下降 5℃。
仿真停止温度与评价温度限制不同:最高评价限值为 102℃,超过它就不合格;仿真最高停止值若为 150℃,则达到严重越界条件时提前结束仿真。软件中的这两项都不能替代真实设备的安全联锁。
5.2 调优预算
| 参数 | 此前默认 / 新版约定 | 用途 |
|---|---|---|
| 最大正常调优轮数 | 4 | 每条适用路线允许的正常 LLM 调优轮数 |
| 每轮曲线采样点数 | 60 | 发送给 LLM 的曲线摘要规模 |
| 连续达标轮数 | 2 | 满足提前停止条件所需的连续次数 |
| 全程平均误差阈值 | 1.2℃ | 提前停止使用的误差门槛 |
| 每轮超限重试次数 | 2(新版约定) | LLM 给出非法参数时允许重新建议的次数 |
| 每条路线请求总上限 | 新版约定启用 | 防止反复拒绝导致无限请求;具体数值以新版配置为准 |
| 原始公式对比 | true | 显示原辨识 Z-N 公式参考结果 |
| 旧版完整路线 | true | 纳入旧版连续调优路线 |
| 修正 Z-N 混合路线 | true | 使用修正 Z-N 初值接入旧版调优核心 |
正常调优轮数 与超限重试次数要分开理解。
例如最大正常调优轮数为 4,某一轮 LLM 第一次建议超限、第二次仍超限、第三次合法:
- 前两次属于拒绝重试,没有进入完整仿真;
- 第三次合法候选进入仿真与评价;
- 这才算一次有效的候选仿真尝试;
- 同时,三次 LLM 请求都会计入请求总预算。
若某轮重试用尽,应该保留已验证的最佳结果,并记录失败原因;不应自动把超限参数裁剪后强行继续。
每轮曲线采样点数 60:不代表仿真只有 60 个时间点。完整仿真照常执行,只是提供给 LLM 的曲线数据被抽样或摘要化。
连续达标轮数 2:连续两轮达到提前停止条件才可能提前结束,不是说控制器只需要稳定两秒。
全程平均绝对误差可以表示为:
E_{\\mathrm{avg}}=\\frac{IAE}{T},\\qquad IAE=\\int_0\^T\|SP(t)-PV(t)\|,dt
它和前面的末段平均绝对误差不同:一个看全过程,一个看最后一段。提前停止仍需满足其他启用的评价门槛。
六、新版护栏与候选状态:怎么读结果?
按本次约定的修改方案,系统不再把超限候选自动裁剪成另一组参数,而是保留原始建议,拒绝整组候选。
6.1 常见候选状态
| 状态含义 | 表示什么 | 后续动作 |
|---|---|---|
| 护栏拒绝 | Kp、Ki、Kd 有任一项超出适用范围 | 不仿真该组;记录原因 |
| 仿真失败 | 参数合法,但仿真未正常完成 | 记录失败,不选用 |
| 评价不达标 | 仿真完成,但超调、误差等指标不合格 | 保留记录,继续比较 |
| 评价通过 | 参数合法,仿真完成且满足全部启用条件 | 进入合格候选池 |
| use 写入拒绝 | 最终参数不符合设备当前参数变更约束 | 不写入,保持设备参数 |
| 无可用参数 | 所有候选都被拒绝或未通过评价 | 明确提示,不输出可应用参数 |
具体枚举名或界面文字可能与表格不同;这里说明的是状态语义。
6.2 三个例子
例 A:Z-N 公式候选超限
- Z-N 输出
(10, 0.2, 0.5); - 绝对 Kp 上限设为 3;
- 新版处理:拒绝整组 Z-N 候选 ,记录
Kp=10 > 3,继续尝试 SIMC 等其他候选。
这不能证明 Z-N 算法错误,只说明它的本次结果不符合当前护栏。
例 B:LLM 建议超限
- 当前参考 Kp=1;
- 本轮最大增长倍数为 3;
- LLM 建议 Kp=10;
- 新版处理:拒绝整组建议,把"允许上限为 3"等原因反馈给 LLM;允许最多 2 次超限重试,并受请求总预算约束。
如果后续给出合法建议,才进入仿真;如果重试用尽,保留已验证的最佳结果。
例 C:test 合格,但 use 不允许写入
- 离线仿真证明某组参数满足评价指标;
- 设备当前 Kp=1;
- 最终建议 Kp=10;
- use 模式允许的相对上限为 3;
- 新版处理:拒绝本次写入,保留设备当前参数。
这里"离线合格"和"设备允许变更"是两种不同结论,不能混在一起。
6.3 为什么报告必须保留原始参数?
以前若把 (10,0.2,0.5) 裁剪成 (3,0.04,0.5),实际仿真结果属于裁剪后的参数,不能当成原始 Z-N 或 SIMC 公式效果。
新版应能回答:
- 算法或 LLM 原本建议了什么?
- 这组建议有没有通过护栏?
- 如被拒绝,哪一项超限、上限是多少?
- 真正参与仿真的是哪一组参数?
- 最终是否通过评价,是否允许应用?
这些记录有利于公平比较 Z-N、SIMC、LLM 等路线,也方便排查为什么"多个算法结果看起来完全一样"。
七、第一次使用,建议怎样设置?
针对默认的30℃ → 100℃ 离线温度仿真,建议先做一个简单、可复现的基准实验:
| 模块 | 参数 | 起始建议 |
|---|---|---|
| 运行 | 模式 | test |
| 控制器 | PID 形式 | parallel |
| 控制器 | 参数时间单位 | s |
| 控制器 | 采样周期 | 1s |
| 控制器 | 微分位置 | measurement |
| 控制器 | 微分滤波 | 0.5s |
| 控制器 | 初始化方式 | zero |
| 护栏 | 策略 | auto |
| 护栏 | 全局增长倍数 | 0 |
| 初始参数 | Kp / Ki / Kd | 1 / 0.01 / 0 |
| 评价 | 最大超调 | 5% |
| 评价 | 最高温度 | 102℃ |
| 评价 | 末段误差 | 0.3℃ |
| 评价 | 稳定偏差带 | ±1℃ |
| 评价 | 最大调节时间 | 600s |
| 评价 | 最小稳定观察时间 | 20s |
| 评价 | 末段比例 | 0.1 |
| 评价 | 选择优先级 | accuracy |
| 仿真 | 时长 | 600s |
| 仿真 | 噪声 | 0℃ |
| 仿真 | 增益倍率 | 1.0 |
| 仿真 | 扰动 | 关闭 |
| 调优 | 正常轮数 | 4 |
| 调优 | 每轮曲线点数 | 60 |
| 调优 | 每轮超限重试 | 2(新版约定) |
推荐的四组对照实验
实验 1:比较评价优先级。 其他配置不变,分别选择 accuracy、smooth、speed,对比最终参数、超调、IAE、调节时间和 TV。
实验 2:测试模型误差。 保持同一组 PID 参数,分别设置 gain_scale=0.8 / 1.0 / 1.2,观察性能变化。注意要固定参数进行鲁棒性测试,避免每次重新整定造成混淆。
实验 3:测试抗扰能力。 先不加扰动,再设置从第 200 秒开始施加负向持续扰动,对比温度恢复能力和控制输出。
实验 4:测试新版护栏。 暂时把 Kp 绝对上限设得很低,观察超限公式候选是否被拒绝、是否继续尝试其他算法,以及报告是否保留原始建议。测试后恢复正常配置。
八、常见问题
Q1:SIMC 算出 Kp=10,但我的最大增长倍数是 3,为什么 test 还能测试?
因为默认 auto + test 的初始公式候选只检查绝对范围;相对增幅限制主要用于 LLM 每轮建议等适用阶段。若绝对上限允许 10,就可以进入仿真。
Q2:参数超限后,程序会重新辨识 K、τ、θ 吗?
不会仅仅因为参数超限就自动重新辨识。参数超限可能是整定策略激进、参数范围偏紧等原因;只有模型或数据本身有问题,才有必要重新辨识。
Q3:超限拒绝后会不会没有结果?
可能会。如果所有候选都被拒绝或评价不合格,系统应明确显示"本次没有可用参数",而不是硬凑一组参数。
Q4:为什么有些合法 PID 参数仍然评价不合格?
因为合法性检查只保证参数在允许范围内,不保证超调、稳定性和误差满足要求。
Q5:把最大调优轮数设得越大,结果一定越好吗?
不一定。更多轮数意味着更多搜索机会,也增加请求成本;LLM 不保证每次建议都改善控制效果。
Q6:tracking 是否等于自动无扰切换?
不是。它只处理初始化状态的一部分。真实设备还需要输出跟踪、执行器约束、控制方向、抗积分饱和和独立保护。
Q7:软件中的护栏和仿真评价能直接保证现场安全吗?
不能。它们用于筛选和离线验证候选参数。真实设备仍需要现场工程审查、独立安全保护、变更审批和受控投用。
九、最重要的使用原则
先用 test 验证候选,再考虑 use。
- 公式计算结果超限:拒绝整组,不改写算法输出。
- LLM 建议超限:拒绝并有限重试,不占用正常有效仿真轮数,但计入请求预算。
- 参数合法:仍需完整仿真评价。
- 离线仿真合格:不等于允许设备写入。
- 所有候选失败:明确提示无可用参数。
- 发现模型质量问题:再考虑补充数据或重新辨识。
只要分清辨识模型、整定候选、参数护栏、仿真评价和设备应用这五个层次,就能比较清楚地理解整个模块的设置与结果。
参考源码
说明:本文解释的字段和默认值来自公开项目配置。关于物理意义、计算例子和建议实验的内容,是在项目字段基础上补充的控制理论教学说明;不能代替真实设备的模型验证、工程设计和安全审查。