# LLM-PID-Tuner 项目说明

这份文档面向维护者、二次开发者，以及想快速理解项目内部结构的人。

如果你只是想直接使用打包版，请先看 [README.md](../../README.md)。

> 如果你想看 **最新开发版的内部结构和最新教程入口**，请优先看 `dev` 分支版本：  
> <https://github.com/KINGSTON-115/llm-pid-tuner/blob/dev/docs/zh-CN/PROJECT_DOC.md>

## 1. 项目目标

本项目的核心目标不是跑出好看的 benchmark，而是：

- 用 LLM 帮用户减少 PID 手工整定的试错成本
- 在真实硬件上尽量减少“参数越调越离谱”的情况
- 让系统在可用后尽量早点停，而不是过度调参
- 出现异常时仍然保留一条可继续工作的保底路径

换句话说，项目更偏向“**可落地的调参助手**”，而不是“学术型最优控制框架”。

## 2. 主要组件

### `tuner.py`

真实硬件调参主程序。

职责：

- 读取 `config.json` / 环境变量
- 扫描并连接串口
- 读取 MCU 上报的 CSV 数据
- 计算当前调参指标
- 调用 LLM 获取新的 PID 建议
- 应用 PID 护栏、保底逻辑、最佳结果记录和回退逻辑

### `simulator.py`

本地热系统仿真器，用来验证调参策略，不依赖真实硬件。

职责：

- 模拟被控对象的热惯性和散热过程
- 用与 `tuner.py` 类似的逻辑跑自动调参
- 便于快速验证策略是否明显跑偏

### `pid_safety.py`

稳定性与保底逻辑集中模块。

职责：

- PID 参数护栏
- LLM 失效时的 fallback 建议
- “已经够好”判断
- 最佳结果记录
- 结果恶化时的回退判断

### `firmware.cpp`

单片机侧示例固件。

职责：

- 按固定周期计算 PID
- 通过串口输出 CSV 数据
- 接收上位机下发的新 PID 参数

### `system_id.py`

系统辨识辅助工具。

职责：

- 读取串口或 CSV 文件中的阶跃响应数据
- 估计一阶惯性 + 纯滞后近似参数
- 给出 Ziegler-Nichols 风格的初始 PID 建议

### `doctor.py`

环境诊断与检查工具。

职责：

- 快速验证 `config.json` 格式及必填字段
- 检查串口权限及占用情况
- 测试 LLM API 连通性
- 检测 MATLAB/Simulink 环境及代理配置
- 为用户输出详细的环境体检报告，避免因环境问题带来的启动失败

### `core/i18n.py`

系统语言检测与多语言支持。

职责：

- 自动检测系统语言 (`zh` / `en`)
- 维护全局语言状态，支持启动参数 `--lang` 强制覆盖
- 提供运行时的文本翻译切换机制

### `sim/pre_tuning_dialog.py`

交互式预调参对话模块。

职责：

- 在主调参循环前，向用户收集自然语言描述的控制偏好与约束（例如“不能超调”）
- 调用 LLM 接口，将用户输入的偏好提取并结构化
- 将提取出的硬性与软性约束融合到后续的提示词中，指导 LLM 贴合特定场景进行调参

### `benchmark.py`

固定随机种子的开发验证工具。

职责：

- 对比 `baseline` / `fallback` / `llm` 三条路径
- 用较可复现的方式观察策略变化

它是开发辅助工具，不是项目的核心价值本身。

## 3. 真实硬件工作流

整体流程如下：

1. （可选）启动前，通过 `doctor.py` 诊断环境配置
2. （可选）如果允许交互，进入预调参对话，接收用户的自然语言约束条件
3. MCU 使用 `firmware.cpp` 风格协议输出过程数据
4. `tuner.py` 通过串口读取并缓存数据
5. 累积到一定采样窗口后，计算误差、超调、稳定性等指标
6. 把当前摘要、历史结果及用户的**预设约束**发给 LLM
7. LLM 返回新的 PID 建议
8. 建议先经过 `pid_safety.py` 的护栏与校验
9. 程序把新 PID 发回设备，进入下一轮
10. 如果结果恶化，优先回退到历史最佳结果
11. 如果结果已经够好，则提前停止

## 4. 配置来源与优先级

运行时配置主要来自两个地方：

- `config.json`
- 环境变量

优先级：

1. 默认配置
2. `config.json`
3. 环境变量覆盖

也就是说，环境变量优先级最高。

对小白来说，推荐使用 `config.json`；对自动化脚本来说，环境变量更方便。

## 5. 串口协议约定

当前项目默认 MCU 输出一行 CSV，字段顺序为：

```text
timestamp_ms,setpoint,input,pwm,error,p,i,d
```

其中：

- `timestamp_ms`：毫秒时间戳
- `setpoint`：设定值
- `input`：当前测量值
- `pwm`：控制输出
- `error`：误差
- `p/i/d`：当前使用的 PID 参数

如果你的硬件协议和这个不一致，优先建议从 `firmware.cpp` 同步，而不是在上位机里临时打补丁。

## 6. 关键设计取向

### 6.1 优先可用，而不是盲目激进

项目不是要求每一轮都把参数改得更猛，而是优先：

- 让系统逐步逼近可用状态
- 尽量避免明显震荡和劣化
- 保留回退空间

### 6.2 LLM 是调参助手，不是唯一真理

LLM 的建议很有价值，但模型输出可能不稳定，因此需要：

- JSON 清洗与解析保护
- provider / API 兼容处理
- fallback 逻辑
- best-so-far 和记忆回退

### 6.3 “已经够好”比“继续追分”更重要

在真实控制里，很多时候系统已经满足需求。
继续追求极小误差，可能反而带来更大风险。

因此运行时加入了提前停止和稳定轮次判断。

## 7. 打包说明

Windows 可执行文件由 `PyInstaller` 打包生成，入口是 `launcher.py`。

`launcher.py` 会在启动时分流到两条路径：

- `tuner.py`：真实硬件调参
- `simulator.py`：本地仿真 / TUI

当前发布策略更适合面向终端用户：

- 源码保留给开发者
- `exe` 保留给直接使用者

## 8. 推荐维护原则

后续继续演进时，优先保持这几条原则：

- 每一段逻辑都要有明确目的
- 优先修根因，不堆表面补丁
- 不为了“跑分更好看”牺牲真实可用性
- 不新增体积庞大但价值不高的复杂层
- 优先保证真实硬件调参链路稳定

## 9. 新手文档入口

如果你要把项目交给不熟悉 Python / PID / 串口的人，请优先让对方看：

- [README.md](../../README.md)
- [RELEASE_NOTES.md](RELEASE_NOTES.md)

这两份文档已经按“先下载 exe，再配置，再连接硬件”的顺序写好了。
