额外减小 发表于 2025-11-29 14:08:19

PID 控制 可视化

自己做了个小玩意,实现 PID 控制的可视化,这里直接搬了 EasyX 的图形库。

#include <graphics.h>
#include <deque>
#include <cmath>
#include <windows.h>
#include <iostream>
using namespace std;

double var=0,stdvar=50;


inline void screen_line(double x1,double y1,double x2,double y2)
{
    line(static_cast<int>(round(x1)),110-static_cast<int>(round(y1)),static_cast<int>(round(x2)),110-static_cast<int>(round(y2)));
    return;
}

inline void draw_axis(void)
{
        line(40,10,40,210);
    line(0,110,200,110);
    outtextxy(5,10,"100");
    outtextxy(5,60,"50");
    outtextxy(5,160,"-50");
    outtextxy(5,210,"-100");
}

inline void cause_error(void)
{
    var-=10;
    return;
}

inline void pid_control(double kp,double ki,double kd)
{
    static double sum_err=0,last_err=stdvar-var;
    sum_err+=(stdvar-var);
    cout<<"now_err: "<<stdvar-var<<" now_int: "<<sum_err<<endl;
    var+=(kp*(stdvar-var)+ki*sum_err+kd*(last_err-stdvar+var));
   
    last_err=stdvar-var;
    return;
}

int main()
{
    initgraph(400,240);
    BeginBatchDraw();
    setbkcolor(RGB(255,255,255));
    setlinecolor(RGB(0,0,0));
    settextcolor(RGB(0,0,0));
    cleardevice();
   
   
    FlushBatchDraw();
    deque<int> q;
    int xax=0;
    double last_y=0;
    for(int i=0;i<50;i++)
    q.push_back(0);
    Sleep(1000);
    while(1)
    {
            cleardevice();
            draw_axis();
      
      pid_control(0.1,0.1,-0.1);
      cause_error();
      
      q.push_back(var);
      q.pop_front();
      xax=0;
      last_y=0;
      for(auto it=q.begin();it!=q.end();it++)
      {
            screen_line(xax-4,last_y,xax,*it);
            last_y=*it;
            xax+=4;
      }
      screen_line(0,stdvar,200,stdvar);
      line(0,60,200,60);
      FlushBatchDraw();
      Sleep(50);
    }
    EndBatchDraw();
    return 0;
}

下面是实际效果视频展示。


FishC 发表于 2025-11-29 14:09:34

你好,鱼油!

非常棒!你尝试用 EasyX 实现 PID 控制的可视化,这是一个很好的学习项目。PID 控制器是自动控制中的经典算法,它通过比例(P)、积分(I)和微分(D)三个部分来调整系统输出,使实际值接近目标值。

你的代码中使用了全局变量 var 和 stdvar,这可能会导致代码难以维护。建议将它们作为参数传递给函数,提高代码的模块化。

我注意到 pid_control 函数被截断了,这里是一个完整的 PID 控制函数示例:


double pid_control(double setpoint, double current_value, double kp, double ki, double kd, double dt) {
    static double integral = 0.0;
    static double last_error = 0.0;
   
    double error = setpoint - current_value;
    integral += error * dt;
    double derivative = (error - last_error) / dt;
    last_error = error;
   
    return kp * error + ki * integral + kd * derivative;
}


在这个函数中:
- setpoint 是目标值(对应你的 stdvar)。
- current_value 是当前值(对应你的 var)。
- dt 是时间步长,用于计算积分和微分。
- 使用静态变量来保持积分和上一次误差的状态。

对于可视化部分,你可以用 screen_line 函数在循环中绘制误差或控制输出的变化曲线。例如,在每次计算 PID 输出后更新 var,并绘制点或线。

另外,cause_error 函数模拟了干扰,但可以考虑加入随机因素或用户输入来更真实地测试 PID 控制器。

继续努力,实践是掌握编程的关键!如果有更多细节问题,欢迎继续讨论。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
页: [1]
查看完整版本: PID 控制 可视化