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

相关推荐
计算机毕业编程指导师4 分钟前
【计算机毕设选题推荐】基于Hadoop+Spark的白鹿抖音评论大数据分析与可视化系统源码 毕业设计 选题推荐 毕设选题 数据分析 机器学习 深度学习
大数据·hadoop·python·计算机·spark·毕业设计·抖音评论
谢亮_vipxieliang13 分钟前
Spring 事务失效的常见场景
java·开发语言·数据库·spring boot
Zootopia62614 分钟前
飞行力学知识梳理1|飞行性能与稳定性
人工智能·python·算法·机器学习·无人机·学习方法·信息与通信
Y38153266222 分钟前
搜索 API 延迟优化:并发数、超时与超时的真实代价
python·搜索引擎
时间的拾荒人26 分钟前
Qt 多线程详解:从 QThread 到实战
开发语言·qt·面试
郑州光合科技余经理35 分钟前
海外版外卖加盟:总站与分站配送规则怎么分开管
java·开发语言·前端·后端·uni-app·php·ai编程
2601_9620715736 分钟前
类变量和全局变量的生命周期有什么区别?
java·开发语言·jvm
wangqiaowq1 小时前
PII 脱敏指的是:把个人身份信息(PII)中能识别到具体个人的敏感部分,用替换、遮蔽、变形等方式处理掉,使得数据在保留可用性的同时,不再直接暴露个人身份。
python
Wang's Blog1 小时前
Java 项目实战: 外卖平台优化-前后端分离开发模式与工程拆分
java·开发语言
风早爽太1 小时前
Python 学习笔记:SQLModel 使用外键关联查询数据
python·fastapi·sqlmodel