PID比例-积分-微分控制算法

详情概述

将比例、积分、微分三种调节规律结合在一起, 只要三项作用的强度配合适当,既能快速调节,又能消除余差,可得到满意的控制效果。

  • 比例(P)控制:根据偏差的大小来产生控制作用,偏差越大,控制作用越强。但单独的比例控制可能存在稳态误差。
  • 积分(I)控制:主要用于消除稳态误差,它对偏差进行积分,随着时间的积累,积分作用逐渐增强,直到消除稳态误差
  • 微分(D)控制:根据偏差的变化率来产生控制作用,能提前预测偏差的变化趋势,从而起到超前控制的作用,改善系统的动态性能。

PID 算法通过合理调整比例系数、积分系数和微分系数,可以实现对系统的精确控制,使系统具有良好的稳定性、准确性和快速性。

比例控制(P)(●’◡’●)

比例控制项是根据当前偏差的大小直接计算出控制量,控制量与偏差成正比。

在这里插入图片描述
作用:比例控制可以快速响应偏差并施加相应的控制力。当偏差较大时,比例控制的输出会较大,能够迅速纠正系统的状态。

缺点:比例控制本身无法完全消除偏差。通常会出现稳态误差,即在系统达到稳定状态后,仍然存在一个小的残留偏差。

积分控制(I)

积分控制项对偏差随时间的积累进行计算。通过累积偏差的面积来消除稳态误差。

在这里插入图片描述
作用:积分控制可以消除比例控制留下的稳态误差。即使偏差很小,随着时间的推移,积分项的作用会不断增加,直到偏差消除为止。

缺点:过高的积分增益可能导致系统过冲(超调)和振荡,特别是在响应速度较快的系统中。

微分控制(D)

微分控制项根据偏差的变化率进行计算。微分项预测偏差的未来变化趋势,并提前采取控制措施。

在这里插入图片描述
作用:微分控制可以减缓系统的超调和振荡。通过对偏差变化率的响应,微分控制能够提前减小控制量,从而使系统更平稳地接近目标值。

缺陷:微分控制对噪声敏感,容易因系统中的小幅波动产生过度反应。

PID数学模型公式🥰

在这里插入图片描述

PID参数调试步骤

  • 先仅设置比例控制,增大 KP 值直到系统开始出现稳定的振荡。此时,系统的响应速度较快,但可能会有显著的稳态误差和超调。
  • 逐步增加积分系数 Ki ,以消除稳态误差。需要注意的是,过高的积分系数会导致系统的响应变慢,并可能引发振荡。
  • 最后,增加微分系数 KD 以减小超调并提高系统的稳定性。微分控制对于噪声较多的系统要谨慎使用,避免放大噪声引发不必要的波动。

可以使用Ziegler-Nichols法,将系统调到临界振荡状态,通过观测振荡周期和增益来确定PID参数。此方法适合线性系统,但可能在非线性系统中表现不佳

代码大致实现

#include <stdio.h>

// PID结构体
typedef struct {
    double kp;   // 比例系数
    double ki;   // 积分系数
    double kd;   // 微分系数
    double prev_error;  // 前一次误差
    double integral;    // 积分值
} PID;

// 初始化PID
void PID_Init(PID *pid, double kp, double ki, double kd) {
    pid->kp = kp;
    pid->ki = ki;
    pid->kd = kd;
    pid->prev_error = 0.0;
    pid->integral = 0.0;
}

// 计算PID输出
// setpoint:目标值、measured_value:测量值、dt:时间间隔
double PID_Compute(PID *pid, double setpoint, double measured_value, double dt) {
    // 计算误差
    double error = setpoint - measured_value;

    // 计算积分
    pid->integral += error * dt;

    // 计算微分
    double derivative = (error - pid->prev_error) / dt;

    // 计算PID输出
    double output = (pid->kp * error) + (pid->ki * pid->integral) + (pid->kd * derivative);

    // 保存当前误差以备下次使用
    pid->prev_error = error;

    return output;
}

int main() {
    // 创建并初始化PID控制器
    PID pid;
    PID_Init(&pid, 1.0, 0.1, 0.01);

    // 假设目标值和初始测量值
    double setpoint = 100.0;
    double measured_value = 50.0;
    double dt = 0.1; // 时间间隔(秒)

    // 进行一次PID计算
    double output = PID_Compute(&pid, setpoint, measured_value, dt);

    printf("PID 输出: %f\n", output);

    return 0;
}

根据不同场景进行不同优化,如有错误,请指正

  • 19
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值