使用MATLAB理解位置PID

0.背景
最近需要用将PID算法移植到FPGA中,对PID算法进行了一个浅浅的学习。看了网上了很多文章,对PID算法的解释都很完美,通俗易懂,也有很多用MATLAB展现出PID算法之美。但是只是显示了PID算法两个位置之间的输出变化,大部分只用了一组PID参数。而现实中的控制,对系统的输出是灵活的,也就是说系统的目标值输出是可控的,这里让我刚开始对PID算法的应用产生了一些困惑,不能很好的理解PID在控制中的具体应用场景。
1.对网上现有的PID程序进行改进
通过对晚上现有的一些代码进行分析,然后利用matlab写出了PID在多个目标值的输出过程,只有一组PID参数,代码如下:

clc
clear all;
close all; 

% PID控制器参数
Kp = 1;  % 比例增益
%Ki = 0;  % 积分增益
Ki = 0.5;  % 积分增益
Kd = 0.1;  % 微分增益

% 设定目标值和时间段
setpoints = [1000, 500, 1500];
durations = [80, 50, 50];

% 初始化变量
target = setpoints(1);
output = 0;
integral = 0;
prev_error = 0;

% 控制时间步长和总时间
dt = 1;
total_time = sum(durations);

% 记录时间、输出值和误差
time = 0;
time_history = [];
output_history = [];
error_history = [];
integral_hisory=[];
control_history=[];
t_history=[];

% PID控制循环
for i = 1:numel(setpoints)
    duration = durations(i);
    for t = 1:(duration/dt)
        % 计算误差和PID控制量
        error = target - output;
        integral = integral + error * dt;
        derivative = (error - prev_error) / dt;
        control = Kp * error + Ki * integral + Kd * derivative;
        
        % 更新输出值
        output = output + control * dt;
        
        % 记录时间、输出值和误差
        time = time + dt;
        time_history = [time_history, time];
        output_history = [output_history, output];
        error_history = [error_history, error];
        integral_hisory=[integral_hisory,integral];
        control_history=[control_history,control];
        t_history=[t_history,t];
        
        % 稳定后更新目标值
        %%{
       % if abs(output - target) < 1e-2 && t*dt >= 1
        if abs(output - target) < 1e-2 && t*dt >= 1
            target = setpoints(min(i+1, numel(setpoints)));
            integral = 0;  % 重置积分项
        end
        %%}
        
        % 更新上一个时间步的误差
        prev_error = error;
    end
end

% 绘制曲线图
figure;
hold on;
plot(time_history, output_history, 'LineWidth', 2);
plot(time_history, error_history, 'LineWidth', 2);
plot(time_history, integral_hisory, 'LineWidth', 2);
plot(time_history, control_history, 'LineWidth', 2);
%plot(time_history, t_history, 'LineWidth', 2);

hold off;
xlabel('时间 (秒)');
ylabel('数值');
title('PID控制器输出曲线');
legend('输出', '误差','积分','控制');
grid on;

%{
% 绘制曲线图
figure(1);
%subplot(2, 1, 1);
plot(time_history, output_history);
xlabel('时间 (秒)');
ylabel('输出');
title('PID控制器输出曲线');
grid on;
figure(2);
%subplot(2, 1, 2);
plot(time_history, error_history);
xlabel('时间 (秒)');
ylabel('误差');
title('PID控制器误差曲线');
grid on;

figure(3);
plot(time_history, integral_hisory);
xlabel('时间 (秒)');
ylabel('积分项');
title('PID控制器积分项曲线');
grid on;

figure(4);
plot(time_history, control_history);
xlabel('时间 (秒)');
ylabel('控制项');
title('PID控制器控制项曲线');
grid on;
%}

该程序主要展示系统输出曲线、误差曲线、积分项曲线以及PID输出曲线,可以改变参数,从而改变PID输出波形,对系统的调参具有一定的积极意义。令参数Ki或者Kd为0,即可观察PD控制或者PI控制的输出波形。上述代码的运行结果如下图所示:
在这里插入图片描述
具有多组PID参数的matlab代码如下,

% 设定从小到大和从大到小的PID系数
Kp_increase = 1;  % 从小到大的比例增益
Ki_increase = 0.5;  % 从小到大的积分增益
Kd_increase = 0.1;  % 从小到大的微分增益

Kp_decrease = 0.5;  % 从大到小的比例增益
Ki_decrease = 0.2;  % 从大到小的积分增益
Kd_decrease = 0.05;  % 从大到小的微分增益

% 设定目标值和时间段
setpoints = [1000, 800, 1500];
durations = [100, 200, 500];

% 初始化变量
target = setpoints(1);
output = 0;
integral = 0;
prev_error = 0;

% 控制时间步长和总时间
dt = 0.1;
total_time = sum(durations);

% 记录时间、输出值和误差
time = 0;
time_history = [];
output_history = [];
error_history = [];

% PID控制循环
for i = 1:numel(setpoints)
    duration = durations(i);
    if i > 1 && setpoints(i) < setpoints(i-1)
        % 从大到小的过程,使用不同的PID系数
        Kp = Kp_decrease;
        Ki = Ki_decrease;
        Kd = Kd_decrease;
    else
        % 从小到大的过程,使用不同的PID系数
        Kp = Kp_increase;
        Ki = Ki_increase;
        Kd = Kd_increase;
    end
    
    for t = 1:(duration/dt)
        % 计算误差和PID控制量
        error = target - output;
        integral = integral + error * dt;
        derivative = (error - prev_error) / dt;
        control = Kp * error + Ki * integral + Kd * derivative;
        
        % 更新输出值
        output = output + control * dt;
        
        % 记录时间、输出值和误差
        time = time + dt;
        time_history = [time_history, time];
        output_history = [output_history, output];
        error_history = [error_history, error];
        
        % 稳定后更新目标值
        if abs(output - target) < 1e-2 && t*dt >= 1
            target = setpoints(min(i+1, numel(setpoints)));
            integral = 0;  % 重置积分项
        end
        
        % 更新上一个时间步的误差
        prev_error = error;
    end
end

% 绘制曲线图
figure;
hold on;
plot(time_history, output_history, 'LineWidth', 2);
plot(time_history, error_history, 'LineWidth', 2);
hold off;
xlabel('时间 (秒)');
ylabel('数值');
title('PID控制器输出和误差曲线');
legend('输出', '误差');
grid on;

上述代码的运行结果如下图所示:在这里插入图片描述
2.FPGA中PID参数处理
FPGA不擅长处理浮点运算,所以我的理解是:PID的参数最好不是小数,那如何让PID参数不是小数呢?我是这样处理的,将计算出来的偏差(目标值与当前值的差值)都缩小,可以采用右移的方式缩小。偏差的正负需要判断一下,如果是正值,不做处理;如果是负值,将右移后的数据乘以-1(width’b1111…111)。然后再进行PID的运算,得到比例项、积分项、微分项的结果。(PS:如果前辈们还有更加好的处理的方法,希望您不吝赐教)
3.结束
在应用PID的算法过程中,可以预留出PID参数接口,利用串口接受数据,改变PID的参数,可以提高系统调试的效率。祝各位可以快速找到系统的最适参数!

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值