项目pid-control-simulation-main 中的 main.py 代码讲解

main.py

python 复制代码
import matplotlib.pyplot as plt
from controller.pid import PID
from system.system_model import ThermalSystem


def run_simulation():
    # Time parameters
    dt = 0.1
    sim_time = 180  # seconds (3 minutes)
    steps = int(sim_time / dt)

    # System + PID
    system = ThermalSystem()  # uses gain=4.0, tau=12.0
    pid = PID(kp=3.0, ki=1.0, kd=0.2, dt=dt)

    # Target temp
    setpoint = 50.0

    # Logging
    times = []
    temps = []
    outputs = []
    setpoints = []

    # Start from current system temp
    measurement = system.temperature

    for i in range(steps):
        current_time = i * dt

        # PID control
        heater_power = pid.compute(setpoint=setpoint, measurement=measurement)
        heater_power = max(0.0, min(1.0, heater_power))  # clamp 0--1

        # Update plant
        measurement = system.update(heater_power=heater_power, dt=dt)

        # Log
        times.append(current_time)
        temps.append(measurement)
        outputs.append(heater_power)
        setpoints.append(setpoint)

    # Plots using a shared figure and axes
    fig, axes = plt.subplots(2, 1, figsize=(12, 8))

    # Temperature subplot
    ax1 = axes[0]
    ax1.plot(times, temps, label="Measured Temperature")
    ax1.plot(times, setpoints, "--", label="Setpoint")
    ax1.set_xlabel("Time (s)")
    ax1.set_ylabel("Temperature (°C)")
    ax1.set_title("PID Temperature Control Simulation")
    ax1.legend()
    ax1.grid(True)

    # Heater power subplot
    ax2 = axes[1]
    ax2.plot(times, outputs, label="Heater Power (0--1)")
    ax2.set_xlabel("Time (s)")
    ax2.set_ylabel("Power")
    ax2.set_title("Heater Output Over Time")
    ax2.set_ylim(0, 1.05)
    ax2.legend()
    ax2.grid(True)

    # Layout fixes so titles do not jump
    fig.tight_layout()
    fig.subplots_adjust(top=0.9, hspace=0.35)

    plt.show()


if __name__ == "__main__":
    run_simulation()

main.py的内容:建一个温度系统 -> 建一个PID控制器 -> 循环控制180秒 -> 记录数据 -> 画图

PART1-导入库
python 复制代码
import matplotlib.pyplot as plt
from controller.pid import PID
from system.system_model import ThermalSystem
  • matplotlib.pyplot:拿来画图
  • PID:导入控制器
  • ThermalSystem:导入温度系统
PART2-定义主函数
python 复制代码
def run_simulation():

把"跑一次完整仿真"这件事打包成一个函数

PART3-时间参数
python 复制代码
dt = 0.1
sim_time = 180  # seconds (3 minutes)
steps = int(sim_time / dt)

dt = 0.1 表示 每次循环代表 0.1 秒。

sim_time = 180 表示 总共模拟 180 秒,也就是 3 分钟。

steps = int(sim_time / dt) 表示 总步数 = 180 / 0.1 = 1800 步,也就是说,这个程序会循环 1800 次。

PART4-创建系统和控制器
python 复制代码
system = ThermalSystem()  # uses gain=4.0, tau=12.0
pid = PID(kp=3.0, ki=1.0, kd=0.2, dt=dt)

这两行是整个项目最核心的初始化。

system = ThermalSystem() 创建一个"温度对象",这个对象是代码里的温度模型,它内部会记住当前温度,并且根据"加热功率"更新温度。这个模型定义在 system_model.py 里。

PART5-设置目标温度
python 复制代码
setpoint = 50.0
PART6-准备记录数据
python 复制代码
times = []
temps = []
outputs = []
setpoints = []
  • times:每个时刻
  • temps:每个时刻的温度
  • outputs:每个时刻的加热功率
  • setpoints:每个时刻的目标值

这四个列表是拿来存数据的,因为最后要画图。

PART7-初始测量值
python 复制代码
measurement = system.temperature

一开始先读取一下当前温度,因为一开始还没开始控制,所以当前温度就是系统初始温度。

根据系统模型,这个初始温度默认就是环境温度 20°C。

PART8-主循环
python 复制代码
for i in range(steps):

接下来开始循环 1800 次,每次代表 0.1 秒

python 复制代码
    current_time = i * dt

记录当前时刻

python 复制代码
    heater_power = pid.compute(setpoint=setpoint, measurement=measurement)

PID控制:把"目标温度"和"当前温度"交给 PID,让它算出应该给多大加热功率。

根据误差,决定控制动作,PID 的具体计算在 pid.py 里,里面核心是 error = setpoint - measurement

python 复制代码
    heater_power = max(0.0, min(1.0, heater_power))  # clamp 0--1

把加热功率强行限制在 0 到 1 之间,这是饱和限制**。**

python 复制代码
    measurement = system.update(heater_power=heater_power, dt=dt)

把刚刚算出的加热功率送给温度系统,让系统往前走 0.1 秒,然后得到新的温度测量值

python 复制代码
    times.append(current_time)
    temps.append(measurement)
    outputs.append(heater_power)
    setpoints.append(setpoint)

这四句就是把这一时刻的数据存起来,这样最后就可以画出完整曲线。

PART9-画图
python 复制代码
fig, axes = plt.subplots(2, 1, figsize=(12, 8))

创建两张子图,画一个窗口,里面放上下两张图,上面画温度,下面画功率

第一张图:温度曲线

python 复制代码
ax1 = axes[0]
ax1.plot(times, temps, label="Measured Temperature")
ax1.plot(times, setpoints, "--", label="Setpoint")
ax1.set_xlabel("Time (s)")
ax1.set_ylabel("Temperature (°C)")
ax1.set_title("PID Temperature Control Simulation")
ax1.legend()
ax1.grid(True)

这段的意思:

  • 横轴:时间
  • 纵轴:温度
  • 蓝线:实际温度
  • 虚线:目标温度 50°C

第二张图:功率曲线

python 复制代码
ax2 = axes[1]
ax2.plot(times, outputs, label="Heater Power (0--1)")
ax2.set_xlabel("Time (s)")
ax2.set_ylabel("Power")
ax2.set_title("Heater Output Over Time")
ax2.set_ylim(0, 1.05)
ax2.legend()
ax2.grid(True)

这段的意思:

  • 横轴:时间
  • 纵轴:加热功率
  • 显示 PID 在每个时刻输出了多大的控制量

最后显示图像

python 复制代码
fig.tight_layout()
fig.subplots_adjust(top=0.9, hspace=0.35)

plt.show()

这几句主要是为了让图排版更整齐,然后弹出窗口显示。

PART10-程序入口
python 复制代码
if __name__ == "__main__":
    run_simulation()

如果这个文件被直接运行,就执行 run_simulation()

相关推荐
2301_795099746 小时前
让 CSS Grid 自适应容器尺寸的动态布局方案
jvm·数据库·python
AI进化营-智能译站6 小时前
ROS2 C++开发系列12-用多态与虚函数构建可扩展的ROS2机器人行为模块
开发语言·c++·ai·机器人
呆萌的代Ma6 小时前
python读取并加载.env的配置文件
python
Muyuan19986 小时前
27.RAG 系统中的上下文充分性判断:从 Chunk 数量、FAISS 距离到 LLM Relevance Gate
python·django·pdf·fastapi·faiss
iCxhust6 小时前
微机原理实践教程(C语言篇)---A002流水灯
c语言·开发语言·单片机·嵌入式硬件·51单片机·课程设计·微机原理
莎士比亚的文学花园6 小时前
Linux驱动开发(3)——设备树
开发语言·javascript·ecmascript
图码6 小时前
如何用多种方法判断字符串是否为回文?
开发语言·数据结构·c++·算法·阿里云·线性回归·数字雕刻
U盘失踪了6 小时前
python curl转python脚本
开发语言·chrome·python
charlie1145141916 小时前
Linux 字符设备驱动:cdev、设备号与设备模型
linux·开发语言·驱动开发·c
handler016 小时前
Linux 内核剖析:进程优先级、上下文切换与 O(1) 调度算法
linux·运维·c语言·开发语言·c++·笔记·算法