电路笔记 控制(PID):Proportional–integral–derivative controller 比例-积分-微分控制器与仿真

  • PID控制(Proportional-Integral-Derivative Control)是一种常用的反馈控制算法,广泛应用于自动控制系统中。PID控制器通过对比例、积分和微分三项的计算,生成控制输出来调节系统的行为,以使其达到期望的目标值。

PID控制器的三个组成部分

  1. 比例控制(P - Proportional Control):

    • 比例控制部分根据当前误差值 e ( t ) e(t) e(t) 进行调节。它产生的控制输出与误差成正比:
      P ( t ) = K p ⋅ e ( t ) P(t) = K_p \cdot e(t) P(t)=Kpe(t)
    • K p K_p Kp比例增益,决定了系统对误差的响应速度和幅度。
    • 优点:能够快速响应误差变化。
    • 缺点:仅使用比例控制可能导致稳态误差,即系统可能无法完全达到目标值。
  2. 积分控制(I - Integral Control):

    • 积分控制部分根据误差的累积来调节控制输出,目的是消除稳态误差:
      I ( t ) = K i ⋅ ∫ 0 t e ( τ ) d τ I(t) = K_i \cdot \int_0^t e(\tau) d\tau I(t)=Ki0te(τ)dτ
    • K i K_i Ki积分增益,决定了系统对累积误差的修正力度。
    • 优点:可以消除稳态误差,使系统达到目标值。
    • 缺点:积分控制可能导致系统反应过慢或产生积分饱和(即积分项积累过多,导致输出过大)。
  3. 微分控制(D - Derivative Control):

    • 微分控制部分根据误差的变化率来调节控制输出,主要用于预测误差的变化趋势并进行提前修正:
      D ( t ) = K d ⋅ d e ( t ) d t D(t) = K_d \cdot \frac{de(t)}{dt} D(t)=Kddtde(t)
    • K d K_d Kd微分增益,决定了系统对误差变化速度的响应程度。
    • 优点:可以提高系统的稳定性,减小振荡和过冲。
    • 缺点:对噪声敏感,如果误差信号中存在噪声,微分控制可能会放大这些噪声,导致不稳定。

PID控制器的总体公式

将比例、积分和微分控制结合起来,PID控制器的控制输出为:
u ( t ) = K p ⋅ e ( t ) + K i ⋅ ∫ 0 t e ( τ ) d τ + K d ⋅ d e ( t ) d t u(t) = K_p \cdot e(t) + K_i \cdot \int_0^t e(\tau) d\tau + K_d \cdot \frac{de(t)}{dt} u(t)=Kpe(t)+Ki0te(τ)dτ+Kddtde(t)
其中:

  • u ( t ) u(t) u(t)控制器的输出,用于调节系统。
  • e ( t ) = r ( t ) − y ( t ) e(t) = r(t) - y(t) e(t)=r(t)y(t)系统的误差 r ( t ) r(t) r(t) 是目标值, y ( t ) y(t) y(t) 是实际输出。

调节PID控制器的参数

  • K p K_p Kp(比例增益):
    • 增大 K p K_p Kp会使系统对误差更加敏感,响应更快,但可能导致系统不稳定和振荡。
  • K i K_i Ki(积分增益):
    • 增大 K i K_i Ki 可以消除稳态误差,但可能导致系统过调,反应变慢。
  • K d K_d Kd(微分增益):
    • 增大 K d K_d Kd 可以减小系统的振荡和过冲,但对噪声敏感,需要谨慎设置。

c语言代码实现

  • PID控制器的C代码示例
#include <stdio.h>

// 定义PID结构体
typedef struct {
    float Kp;          // 比例增益
    float Ki;          // 积分增益
    float Kd;          // 微分增益
    float prev_error;  // 上一次的误差
    float integral;    // 误差的积分
} PIDController;

// 初始化PID控制器
void PID_Init(PIDController *pid, float Kp, float Ki, float Kd) {
    pid->Kp = Kp;
    pid->Ki = Ki;
    pid->Kd = Kd;
    pid->prev_error = 0;
    pid->integral = 0;
}

// 计算PID控制输出
float PID_Compute(PIDController *pid, float setpoint, float measured_value, float dt) {
    // 计算误差
    float error = setpoint - measured_value;

    // 计算比例项
    float P_out = pid->Kp * error;

    // 计算积分项
    pid->integral += error * dt;
    float I_out = pid->Ki * pid->integral;

    // 计算微分项
    float derivative = (error - pid->prev_error) / dt;
    float D_out = pid->Kd * derivative;

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

    // 计算最终的控制输出
    float output = P_out + I_out + D_out;

    return output;
}

int main() {
    // 创建一个PID控制器
    PIDController pid;
    
    // 初始化PID控制器参数(Kp, Ki, Kd)
    PID_Init(&pid, 1.0, 0.1, 0.01);

    // 设定目标值(setpoint)
    float setpoint = 100.0;

    // 当前测量值
    float measured_value = 90.0;

    // 时间步长(假设为0.1秒)
    float dt = 0.1;

    // 计算PID控制器的输出
    float output = PID_Compute(&pid, setpoint, measured_value, dt);

    // 输出结果
    printf("PID Output: %f\n", output);

    return 0;
}

python仿真

# 代码来自:https://ethanr2000.medium.com/using-pid-to-cheat-an-openai-challenge-f17745226449
# 系统建模方程 https://ctms.engin.umich.edu/CTMS/index.php?example=InvertedPendulum&section=SystemModeling
# sudo apt-get install python-opengl
# pip install gym==0.16.0
# pip install pillow==9.0.0 原因:https://github.com/MannLabs/alphapept/issues/561
# pip install imagio # 用于保存结果,使用的numpy版本为1.20.1
import imageio
import gym

env = gym.make("CartPole-v1")
observation = env.reset()

Kp = 135
Ki = 96.5
Kd = 47.5

force = 0
integral = 0

writer = writer = imageio.get_writer('output.gif',  mode='?') # https://imageio.readthedocs.io/en/stable/reference/userapi.html
for _ in range(100):
    img = env.render(mode = "rgb_array")  # 捕捉当前帧的图像
    writer.append_data(img)

    env.render()
    observation, reward, done, info = env.step(force)

    velocity = observation[1]
    angle = observation[2]
    angular_velocity = observation[3]

    integral = integral + angle

    F = Kp*(angle) + Kd*(angular_velocity) + Ki*(integral)

    force = 1 if F > 0 else 0
    if done:
      observation = env.reset()
      integral = 0

env.close()
writer.close()

效果

  • 实际运行比这个gif展示的更稳定,摆动速度也是不同的
    在这里插入图片描述

CG

  • https://github1s.com/m-lundberg/simple-pid/blob/master/simple_pid/pid.py#L101-L161
  • pip install mujoco # mujoco是和gym同类的仿真工具
  • https://mujoco.readthedocs.io/en/latest/python.html
  • https://github.com/openai/mujoco-py?tab=readme-ov-file
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值