FPGA学习之实现PID算法

这篇具有很好参考价值的文章主要介绍了FPGA学习之实现PID算法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1 废话篇

1.1 理论学习

PID控制算法的学习,本次介绍位置式和增量式PID控制算法的原理和Matlab的仿真分析

1.1.1 模拟PID控制算法

在工程中,比较用的多的就是比例、积分、微分控制,简称PID控制。G(s) 为被控对象的系统传递函数。
fpga pid,FPGA学习,fpga开发,学习,算法
fpga pid,FPGA学习,fpga开发,学习,算法
fpga pid,FPGA学习,fpga开发,学习,算法

PID控制算法分为三种,分别是P调节,PI调节和PID调节算法。

P调节算法:比例控制是一种最简单的控制方式。其控制器的输出和输入误差信号成比例光系。偏差一旦产生。控制器立即就发生作用即调节控制输出,使被控量朝着减小误差的方向变化,偏差减小的速度取决于比例系数Kp,Kp越大偏差减小的越快,但是容易引起振荡,尤其是在迟滞环节比较大的情况下,Kp减小,发生振荡的可能性减小。但是调节的速度变慢。但单纯的比例控制存在稳态误差不能消除的缺点,这里就需要积分控制。P调节算法的控制规律和阶跃响应如下图所示
fpga pid,FPGA学习,fpga开发,学习,算法

PI调节算法
在积分控制中,控制器的输出与输入误差信号的积分成正比关系。对一个自动控制系统,如果在进入问太后存在稳态误差,则称这个控制系统是有稳态误差的或者简称有差系统。为了消除稳态误差,在控制器中必须引入“积分项”。积分项对误差取决于时间的积分,随着时间的增加,积分项会增大。这样,即便误差很小,积分项也会随着时间的增大而加大,它推动控制器的输出增大使稳态误差进一步减少,直至等于零。因此,比例+积分控制器,可以使系统进入稳态后无稳态误差,实质上就是对偏差累积进行控制,直至偏差为零。积分控制作用始终施加指向给定值的作用力,有利于消除静差,其效果不仅与偏差大小有关,而且还与偏差持续的时间有关。PI调节算法的控制规律和阶跃响应如下图所示:
fpga pid,FPGA学习,fpga开发,学习,算法
PID调节算法:
在微分控制中,控制器的输出和输入误差信号的微分(即误差变化率)成正比关系。自动控制系统在克服误差的调节过程中可能会出现振荡甚至失稳。其原因使由于存在有较大惯性组件(环节)或有滞后组件,具有抑制误差的作用,其变化总是落后于误差的变化。解决的方法是使抑制误差的作用的变化“超前”,即在误差接近0时,抑制误差的作用就应该是零。这就是说,在控制器中仅引入“比例”项往往是不够的,比例项的作用仅是放大误差的幅值,而目前需要增加的是 微分项,它能预测误差变化的趋势,这样,具有比例+微分的控制器,就能够提前使抑制误差的控制作用等于零,甚至为负值,从而避免了被控量的严重超调。所以对有较大惯性或者滞后的被控对象,微分比较有效果
fpga pid,FPGA学习,fpga开发,学习,算法

1.1.2 离散化

fpga pid,FPGA学习,fpga开发,学习,算法
fpga pid,FPGA学习,fpga开发,学习,算法
fpga pid,FPGA学习,fpga开发,学习,算法

1.1.3 伪算法

这里看到网上一个位置式PID实现的伪算法:

previous_error := 0 // 上一次偏差
integral := 0;   // 积分和

// 循环
// 采样周期为dt
loop:
	// setpoint 设定值
	// measured value 反馈值
	 error := setpoint - measured_value;    		 // 计算得到偏差
	 integral := integral + error * dt;     		 // 计算得到积分累加和
	 derivative := (error - previous_error ) / dt;   // 计算得到的微分
	 output := kp*error + ki*integral + kd*derivate;  // 计算得到PID的输出
	 previous_error := error;                         // 保存当前偏差为下一次采样时所需要的历史偏差
	 wait(dt);
	 goto loop;
	 

1.1.4 matlab算法位置式

对应的matlab仿真:

% 位置式PID算法仿真
clear;
clc;
%% 参数定义
Ts = 1e-3;% 采样时间     
e_sum = 0;% 多次误差和
% PID参数(可根据实际情况调节)
kp = 0.32;% 比例 
ki = 0.15;% 积分
kd = 0.12;% 微分
%% 建立被控系统
% 假设被控对象的系统传递函数为0.88/(0.05s + 1.5)
s_sys = tf(0.88,[0.05 1.5]); % 根据传递函数建立被控系统的模型
z_sys = c2d(s_sys,Ts,'z');    % 拉氏变换-->z变换
[m,n] = tfdata(z_sys,'v');
%% 开始PID控制
T = 2000;% 设置仿真运行时间
r = 800;% 期望输出值
% 预先分配内存
u = zeros(1,T);% PID输出初始值
y = zeros(1,T);% 被控系统响应输出
e = zeros(1,T);% 误差信号
for k=2:1:T
    y(k) = -n(2)*y(k-1) + m(1)*u(k) + m(2)*u(k-1);% 计算被控系统输出
    e(k) = r - y(k);   % 计算误差
    u(k) = kp*e(k) + ki*e_sum + kd*(e(k)-e(k-1)); %根据误差调整PID控制量输出
    e_sum = e_sum+e(k);% 计算多次误差和
end
% 绘制过渡过程的曲线
t = 1:1:T;
figure('Color','White');
plot(t,y,'r-','LineWidth',1.2);
title('pid-pos')
xlabel('t');
ylabel('y');
grid on;
set(gca,'FontSize',12,'LineWidth',1.2,'Fontname', 'Times New Roman','FontWeight','Bold')

fpga pid,FPGA学习,fpga开发,学习,算法

1.1.5 matlab 算法增量式

fpga pid,FPGA学习,fpga开发,学习,算法

% 位置式PID算法仿真
clear;
clc;
%% 参数定义
Ts = 1e-3;% 采样时间     
% PID参数(可根据实际情况调节)
kp = 0.32;% 比例 
ki = 0.15;% 积分
kd = 0.12;% 微分
%% 建立被控系统
% 假设被控对象的系统传递函数为0.88/(0.05s + 1.5)
s_sys = tf(0.88,[0.05 1.5]); % 根据传递函数建立被控系统的模型
z_sys = c2d(s_sys,Ts,'z');    % 拉氏变换-->z变换
[m,n] = tfdata(z_sys,'v');
%% 开始PID控制
T = 2000;% 设置仿真运行时间
r = 800;% 期望输出值
% 预先分配内存
u = zeros(1,T);% PID输出初始值
y = zeros(1,T);% 被控系统响应输出
e = zeros(1,T);% 误差信号
d_u = zeros(1,T);% PID输出增量
for k=3:1:T
    y(k) = -n(2)*y(k-1) + m(1)*u(k) + m(2)*u(k-1);% 计算被控系统输出
    e(k) = r - y(k);   % 计算误差
    d_u(k) = kp*(e(k)-e(k-1))+ki*e(k)+kd*((e(k)-e(k-1))-(e(k-1)-e(k-2)));% 根据误差获取PID增量
    u(k) = u(k-1) + d_u(k);% 根据PID增量计算PID控制输出
end
% 绘制过渡过程的曲线
t = 1:1:T;
figure('Color','White');
plot(t,y,'r-','LineWidth',1.2);
title('pid-incre')
xlabel('t');
ylabel('y');
grid on;
set(gca,'FontSize',12,'LineWidth',1.2,'Fontname', 'Times New Roman','FontWeight','Bold')

fpga pid,FPGA学习,fpga开发,学习,算法

1.1.5 verilog 实现PID

error.v

module error(

    input clk,
    input rst_n,
    input signed [9:0] target,
    input signed [9:0] y,
    
    output signed [9:0] ek0,
    output reg signed[9:0] ek1;
    output reg signed [9:0] ek2;
);

assign ek0 = target - y;   // 计算e(k)

always @(posedge clk or negedge rst_n) begin
    
    if(!rst_n) begin
        ek1 <= 10'd0;
        ek2 <= 10'd0;
    end
    else begin
        ek1 <= ek0;                 // 延时一个时钟周期 得到e(k-1)
        ek2 <= ek1;                 // 再延时一个时钟周期 得到e(k-2)
    end 
end


endmodule

pid_value.v

///
// Company: <Name>
//
// File: pid_value.v
// File history:
//      <Revision number>: <Date>: <Comments>
//      <Revision number>: <Date>: <Comments>
//      <Revision number>: <Date>: <Comments>
//
// Description: 
//
// <Description here>
//
// Targeted device: <Family::SmartFusion> <Die::A2F060M3E> <Package::288 CS>
// Author: <Name>
//
/// 

//`timescale <time_units> / <precision>

module pid_value( 

    input clk,                          // 时钟信号
    input rst_n,                        // 复位信号,低电平有效
    input signed [14:0] d_uk,           // pid 增量

    output reg signed [14:0] uk0        // pid 输出值

);

reg signed [14:0] uk1 = 15'd0;          // 上一时刻u(k-1) 的值

always @(d_uk) begin
    uk0 = uk1 + d_uk;                   // 计算pid 输出值
    uk1 = uk0;                          // 寄存上一时刻 u(k-1) 的值
end

//<statements>

endmodule

incre_value.v

///
// Company: <Name>
//
// File: incre_value.v
// File history:
//      <Revision number>: <Date>: <Comments>
//      <Revision number>: <Date>: <Comments>
//      <Revision number>: <Date>: <Comments>
//
// Description: 
//
// <Description here>
//
// Targeted device: <Family::SmartFusion> <Die::A2F060M3E> <Package::288 CS>
// Author: <Name>
//
/// 

//`timescale <time_units> / <precision>

module incre_value( 

    input signed [9:0] ek0,
    input signed [9:0] ek1,
    input signed [9:0] ek2,

    input [3:0] kp,
    input [3:0] ki,
    input [3:0] kd,

    output signed [14:0] d_uk

);


assign  d_uk = kp*(ek0 -ek1) + ki*ek0 + kd*((ek0 - ek1)-(ek1 - ek2)); // 计算pid增量

//<statements>

endmodule


demo_top.v

///
// Company: <Name>
//
// File: demo_top.v
// File history:
//      <Revision number>: <Date>: <Comments>
//      <Revision number>: <Date>: <Comments>
//      <Revision number>: <Date>: <Comments>
//
// Description: 
//
// <Description here>
//
// Targeted device: <Family::SmartFusion> <Die::A2F060M3E> <Package::288 CS>
// Author: <Name>
//
/// 

//`timescale <time_units> / <precision>

module demo_top (

    input clk,                          // 时钟信号
    input rst_n,                        // 复位信号
    input signed [9:0] target,          // 目标值
    input signed [9:0] y,               // 实际输出值

    input [3:0] kp,
    input [3:0] ki,
    input [3:0] kd,
    
    output signed [14:0] uk0            // pid 输出值
);


wire signed [9:0] ek0;
wire signed [9:0] ek1;
wire signed [9:0] ek2;

error error_inst(
    .clk(clk),
    .rst_n(rst_n),
    .y(y),
    .ek0(ek0),
    .ek1(ek1),
    .ek2(ek2)
);

wire signed [14:0] d_uk; // pid 增量
incre_value incre_value_inst(

    .ek0(ek0),
    .ek1(ek1),
    .ek2(ek2),
    .kp(kp),
    .ki(ki),
    .kd(kd),
    .d_uk(d_uk)

);

pid_value pid_value_inst(

    .clk(clk),
    .rst_n(rst_n),
    .d_uk(d_uk),
    .uk0(uk0)
);

endmodule


tb_demo_top.v文章来源地址https://www.toymoban.com/news/detail-806803.html

///
// Company: <Name>
//
// File: tb_demo_top.v
// File history:
//      <Revision number>: <Date>: <Comments>
//      <Revision number>: <Date>: <Comments>
//      <Revision number>: <Date>: <Comments>
//
// Description: 
//
// <Description here>
//
// Targeted device: <Family::SmartFusion> <Die::A2F060M3E> <Package::288 CS>
// Author: <Name>
//
/// 

//`timescale <time_units> / <precision>

module tb_demo_top();

reg clk;
reg rst_n;
reg signed [9:0] target ;  // 目标值
reg signed [9:0] y; // 实际值

reg [3:0] kp;    // 比例系数
reg [3:0] ki;    // 积分系数
reg [3:0] kd;    // 微分系数

wire signed [14:0] uk0;

reg [10:0] i;
reg [8:0] mytxt[0:1997];

initial begin
    $readmemh(,mytxt);
    clk = 1'b0;
    rst_n = 1'b1;
    #5 rst_n = 1'b0;
    #5 rst_n = 1'b1;
    target = 10'd350;
    kp = 4'd10;
    ki = 4'd9;
    kd = 4'd8;

    for(i = 0; i<11'd1997; i=i+1)
        begin
            y = mytxt[i];
            #10;
        end
end

 
always #5 clk = ~clk;

demo_top demo_top_tb(.clk(clk),
.rst_n(rst_n),
.target(target),
.y(y),
.kp(kp),
.ki(ki),
.kd(kd),
.uk0(uk0)
); 

//<statements>

endmodule


到了这里,关于FPGA学习之实现PID算法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于FPGA的PID控制器设计

    PID控制应该算是应用非常广泛的控制算法了。常见的比如控制环境温度,控制无人机飞行高度速度等。PID我们将其分成三个参数,如下: P-比例控制,基本作用就是控制对象以线性的方式增加,在一个常量比例下,动态输出,缺点是会产生一个稳态误差。 I-积分控制,基本作

    2024年02月03日
    浏览(48)
  • m基于FPGA的FOC控制器verilog实现,包括CLARK,PARK,PID及SVPWM,含testbench

    目录 1.算法仿真效果 2.算法涉及理论知识概要 3.MATLAB核心程序 4.完整算法代码文件 Quartus II 12.1(64-Bit) ModelSim-Altera 6.6d Starter Edition 仿真结果如下: 整个系统的结构如下所示: 1、采集到两相电流 2、经过clarke变换后得到两轴正交电流量, 3、经过旋转变换后得到正交的电流量

    2024年02月15日
    浏览(40)
  • 自适应PID算法学习(01)——单神经元PID控制

      单神经元含有n个输入,仅1个输出,每个输入端可记作 x i ( i = 1 , 2 , . . . n ) x_i (i=1,2,...n) x i ​ ( i = 1 , 2 , ... n ) ,若该神经元为多元组成网络中某一层(输入层/输出层/隐含层)其中的一个单元,记该神经元输出为 o j ( j = 1 , 2 , . . . ) o_j(j=1,2,...) o j ​ ( j = 1 , 2 , ... ) ;不

    2024年02月16日
    浏览(33)
  • 【两周学会FPGA】从0到1学习紫光同创FPGA开发|盘古PGL22G开发板学习之数码管静态显示(四)

      本原创教程由深圳市小眼睛科技有限公司创作,版权归本公司所有,如需转载,需授权并注明出处 适用于板卡型号: 紫光同创PGL22G开发平台(盘古22K) 一:盘古22K开发板(紫光同创PGL22G开发平台)简介 盘古22K开发板是基于紫光同创Logos系列PGL22G芯片设计的一款FPGA开发板

    2024年02月10日
    浏览(33)
  • 【PID】基于Matlab实现增量式PID算法

    ✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信。 🍎个人主页:Matlab科研工作室 🍊个人信条:格物致知。 增量式PID控制较常规PID更具优势,但有关其参数整定的方法很少,针对这种问题,介绍了增量式PID算法的原理及特点,基于MATLAB平台

    2024年02月14日
    浏览(30)
  • 【两周学会FPGA】从0到1学习紫光同创FPGA开发|盘古PGL22G开发板学习之DDR3 IP简单读写测试(六)

    本原创教程由深圳市小眼睛科技有限公司创作,版权归本公司所有,如需转载,需授权并注明出处 适用于板卡型号: 紫光同创PGL22G开发平台(盘古22K) 一:盘古22K开发板(紫光同创PGL22G开发平台)简介 盘古22K开发板是基于紫光同创Logos系列PGL22G芯片设计的一款FPGA开发板,全

    2024年01月23日
    浏览(55)
  • 电赛控制类PID算法实现

    一、什么是PID 学过自动控制原理的对PID并不陌生,PID控制是对偏差信号e(t)进行比例、积分和微分运算变换后形成的一种控制规律。PID 算法的一般形式: PID控制系统原理框图 二、PID离散化 对PID连续系统离散化,从而方便在处理器上实现,PID 离散表示形式: 离散化后最终得

    2024年02月06日
    浏览(27)
  • 智能算法实现PID智能车控制系统

    PID控制是自动控制领域中产生最早,应用最广的一种控制方法。本文以论述PID参数先进整定方法开始,介绍了近几年得到的最新研究成果。接下来,从PID控制的结构形式实际控制工程需求和实现条件分析了PD控制的独特优点和理论依据。在众多的PID调整方法中,本文选择了内

    2024年02月08日
    浏览(31)
  • PID控制算法,带C语言源码实现

    PID即:Proportional(比例)、Integral(积分)、Differential(微分)的缩写。PID控制算法是结合比例、积分和微分三种环节于一体的控制算法。PID算法是连续系统中技术最为成熟、应用最为广泛的一种控制算法。 PID控制算法出现于20世纪30至40年代,适用于对被控对象模型了解不清

    2024年04月29日
    浏览(28)
  • 【物联网】C语言实现PID算法:原理、例子和代码详解

    PID(Proportional-Integral-Derivative)是一种常用的控制算法,广泛应用于工业控制系统中。本文将详细介绍PID算法的原理,并给出一个具体的例子和相应的C语言代码实现。 PID算法通过不断调整输出值,使得系统的实际值逐渐接近期望值。它由三个部分组成: 比例(P)、积分(

    2024年02月12日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包