PID 控制策略及计算广告中的应用

定义

PID, Proportional, Integral and Derivative, 比例-积分-微分 控制系统.
一种 “控制-观察-调整控制-再观察” 的迭代方法. 每轮迭代中, 得到系统的输出后,计算与预定目标的误差, 包括 {比例,积分,微分} 3种表达,将其叠加到输入中,从而控制系统的行为.

直接上公式.
u ( t ) = P + I + D = K p ∗ e ( t ) + K i ∗ ∫ 0 t e ( t ) d t + K d ∗ d e ( t ) d t (1) u(t)=P+I+D \\ = K_p*e(t)+K_i*\int_0^t e(t)\mathrm dt+K_d*\frac{\mathrm d\ e(t)}{\mathrm dt} \tag 1 u(t)=P+I+D=Kpe(t)+Ki0te(t)dt+Kddtd e(t)(1)

适用场景

自动驾驶中, 希望汽车提速并稳定到100Km/h, 应该怎么控制动力输出(油门)?
整个系统中有 {风向风力, 地面摩擦力(干燥/湿滑), 汽车载重, 轮胎温度} 等多个影响因素. 控制变量为汽车油门, 即前进动力.
当一切都已知, 自然可以直接计算出来最优的动力分配函数f(t). 但这个假设太理想了, 并且计算难以完成, 所以需要 “控制-观察反馈-调整控制” 这样迭代去完成任务.

工作原理举例

同上汽车加速的任务.
e ( t ) = 100 − v t e(t)=100-v_t e(t)=100vt, 表示当前车速与目标的差值.
u(t)表示各策略叠加后的当前动力输出.

proportional-比例部分

一开始e最大, 乘以固定的系数 P 后也较大.
随着速度的提升, 该控制项的输出会逐步减弱.
但因为风力, 地面摩擦力等原因, 会在某个时刻与 该控制项输出 相等, 速度再也提不上去, 形成稳态误差.

integral-积分部分

离散情况下, 积分就是求和, 把历史上近几轮迭代的 e(t) 相加.
功用:

  1. 达到稳态误差后, 该控制项的和继续增大, 叠加到动力上可以消除稳态误差, 最终达到目标.
  2. p部分力量较弱时, 方便加速提前达到目标.

derivative-微分部分

离散情况下, 微分就是 Δ e = e ( t ) − e ( t − 1 ) \Delta e=e(t)-e(t-1) Δe=e(t)e(t1),
汽车加速中, 离目标值越来越近, 所以 Δ e \Delta e Δe为负, 与一个整数D相乘后依旧为负数.
功用:

  1. 如果动力足够大, 离散的间隔也大, 就会超速, 此控制项用于避免超速, 避免震荡.

可视化仿真

见参考[1]文末.

调参经验

Kp,Ki,Kd 三个参数是 task-specific 的, 通常通过仿真系统人工寻参而得.
Kp 是基础部分, 可先控制 Ki, Kd 两项为0, 二分法迭代.
继续 调整 Ki 与 Kd. 当一个系统没有稳态误差时, Ki 可以置0.

python简易实现

import matplotlib
import matplotlib.pyplot as plt
import matplotlib.axes
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签class Car:"""被控制系统是一辆汽车新的速度=原有速度+加速度-阻力"""def __init__(self):self.mass = 100self.velocity = 0self.accelerated_velocity_arr = []def get_current_speed(self, force):force_accelerated_velocity = force / self.masswind_accelerated_velocity = - self.velocity * 0.1 / self.massself.velocity = self.velocity + force_accelerated_velocity + wind_accelerated_velocityself.accelerated_velocity_arr.append(force_accelerated_velocity + wind_accelerated_velocity)return self.velocityclass PIDController:"""输出"""def __init__(self, target_val, kp, ki, kd):self.target_val = target_valself.controlled_system = Car()self.kp = kpself.ki = kiself.kd = kdself.out_put_arr = [0]self.observed_val_arr = []self.now_val = 0self.sum_err = 0self.now_err = 0self.last_err = 0def iterate(self):self.observed_val_arr.append(self.controlled_system.get_current_speed(self.out_put_arr[-1]))self.now_err = self.target_val - self.observed_val_arr[-1]# 这一块是严格按照公式来写的out_put = self.kp * self.now_err \+ self.ki * self.sum_err \+ self.kd * (self.now_err - self.last_err)self.out_put_arr.append(out_put)self.last_err = self.now_errself.sum_err += self.last_errreturn out_put# 对pid进行初始化,目标值是1000 ,Kp=0.1 ,Ki=0.15, Kd=0.1
controller = PIDController(100, 3, 0.1, 0.2)
# 然后循环100次把数存进数组中去
for i in range(0, 300):controller.iterate()
print('controller.out_put_arr,', controller.out_put_arr)
print('car.ccelerated_velocity_arr,', controller.controlled_system.accelerated_velocity_arr)
print('controller.observed_val_arr,', controller.observed_val_arr)
fig, ax1 = plt.subplots()
ax1 = ax1  # type: matplotlib.axes.Axes
ax1.set_xlabel('iterations')
ax1.set_ylabel('force_out_put   (N)', color='red')
# ax1.set_ylim()
ax1.plot(controller.out_put_arr, color="red", label='force_out_put')
ax1.legend(loc=2)ax2 = ax1.twinx()
ax2.plot(controller.observed_val_arr, color='blue', label='car_speed')
ax2.set_ylabel('car_speed   (Km/h)',color='blue')
ax2.legend(loc=1)
plt.title('PID 控制系统示意')
plt.show()

在这里插入图片描述

参考

  1. 知乎, PID控制算法原理
  2. 知乎, 广告出价–如何使用PID控制广告投放成本
  3. mathworks 无人机例子视频讲解, What is PID Control?


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部