项目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()

相关推荐
我带你来这儿就是为了告诉你我2 小时前
C++23新特性前瞻
开发语言·c++·算法
jinanwuhuaguo2 小时前
OpenClaw安全使用实践全景深度指南:从“裸奔龙虾”到“可信数字堡垒”的体系化构建
开发语言·php
2501_908329852 小时前
C++安全编程指南
开发语言·c++·算法
计算机安禾2 小时前
【C语言程序设计】第39篇:预处理器与宏定义
c语言·开发语言·c++·vscode·算法·visual studio code·visual studio
巧妹儿2 小时前
Python 配置管理封神技:pydantic_settings+@lru_cache,支持优先级,安全又高效,杜绝重复加载!
开发语言·python·ai·配置管理
独隅2 小时前
Python AI 全面使用指南:从数据基石到智能决策
开发语言·人工智能·python
胡耀超2 小时前
Web Crawling 网络爬虫全景:技术体系、反爬对抗与全链路成本分析
前端·爬虫·python·网络爬虫·数据采集·逆向工程·反爬虫
m0_569881472 小时前
C++中的装饰器模式变体
开发语言·c++·算法
小陈的进阶之路2 小时前
Selenium元素定位
python·selenium