FPGA实现PID控制器——基于Quartus prime 18.0

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

目录

 1. PID控制器和离散化PID控制器

1.1 PID控制器

1.1.1 P控制器

1.1.2 稳态误差和I控制器

1.1.3 超调和D控制器

1.2 离散式PID控制器——位置式PID控制器

2.PID控制系统Simulink仿真

3.Verilog代码编写和Modelsim仿真

3.1 误差计算模块和PID算法模块编写

3.1.1 误差计算模块

3.1.2 PID算法模块

3.2 主模块及Testbench模块编写

3.2.1 主模块编写

3.2.2 Testbench模块编写

3.3 仿真结果


 1. PID控制器和离散化PID控制器

1.1 PID控制器

PID控制器中的P, I, D分别代表比例、积分、微分,它是一种用于控制工业应用中压力、流量、温度和速度等不同过程变量的设备。在该控制器中,控制回路反馈装置用于调节所有过程变量。

PID控制器这样的闭环系统包括反馈控制系统。该系统使用固定点评估反馈变量以生成误差信号。在此基础上,它会改变系统输出。这个过程将一直持续到误差达到零,否则反馈变量的值就等于一个固定点。

quartus pid,fpga开发,fpga

1.1.1 P控制器

P控制器通过比例运算来调节系统输出和目标值之间的误差。例如系统输出为5,目标值为10,当设定P控制器的比例系数为Kp=0.8时,则有如下计算过程:

quartus pid,fpga开发,fpga

通过误差和比例系数之间的直接乘法运算,P控制器实现了对误差的纠正。

由以上的例子可以看出,当Kp的值越大时,系统达到稳态(即输出值等于目标值)的速度也就越快,但是当Kp的值过大时,系统的输出误差绝对值并不一定减小,例如将上例的Kp改为2,则误差e(t)由P控制前的5变为了控制后的-5,实际上,当Kp的值过大时,误差的绝对值有可能越来越大,导致系统输出进入发散状态。

1.1.2 稳态误差和I控制器

在实际的系统控制中,系统往往存在阻尼或其他形式的消耗。例如一个力学系统中可能会有摩擦,热学系统可能存在热能耗散等等。这将会导致我们输出的比例控制并不能完全地转化为系统输出。例如一个热力学系统每秒向外耗散0.5℃的热量,当误差为1℃且Kp=0.5时,输出值与目标值之间将永远存在1℃的误差。这部分误差即为稳态误差。

在这种情况下便需要积分控制来消除这一部分误差。通过引入对误差的积分值,我们便可以在一次积分控制中对前一段时刻产生的误差累积量进行控制,即

通过这样的方式,当系统存在稳态误差时,积分项的误差累积值将会越来越大,从而实现了稳态误差的消除。

1.1.3 超调和D控制器

在控制系统中,我们往往很难一次就将输出值控制到与目标值相等,为使系统更快地达到稳态,往往选用较大的比例系数Kp,从而会导致系统的输出会先高于目标值,然后又低于目标值,这样在反复震荡的过程中振幅逐渐减小,最终达到稳态值。在这个过程中系统的输出信号超过目标值的现象就称为超调现象,超出的值就称为超调量。在此过程中超调量的最大值称为最大超调量。一般来说,在系统输出不发散的前提下,比例系数越大,超调量也就越大,系统达到稳态的速度也越快。但是超调量过大时,系统的稳定性也会变差,在许多实际场景中,这是我们不愿看到的。因此我们引入微分控制,来对系统的超调和震荡进行控制。

我们知道,微分表示了一个函数图像的斜率,即当前时刻的变化率。因此,对当前时刻的误差e(t)进行微分运算,便可得到当前时刻误差的变化率,也就可以预测出下一时刻误差的变化趋势。因此通过这一手段,我们便可以在当前时刻提前对控制信号做出调整,从而在误差减小或是增大时加快或减小控制信号的输出。我们在向杯子里倒水时,随着水越来越满(误差越来越小),逐渐减慢倒水的速度,就可以理解为是一个微分控制的过程。微分控制的公式如下:

将比例P,积分I,微分D三部分的公式合在一起,便得到了PID控制算法的计算公式:

quartus pid,fpga开发,fpga

在工程中,PID控制器的系数KP、KI、和KD需要结合实际给出,即PID参数整定。这里不再给出整定的具体方法,大家可以自行搜索查阅。

1.2 离散式PID控制器——位置式PID控制器

无论计算机还是FPGA芯片,采取的控制方式都是采样控制,只能根据采样时刻的偏差来计算控制量,因此计算机控制系统中,必须对公式进行离散化,具体就是用求和代替积分,用向后差分来代替微分,使模拟PID离散化为数字形式的差分方程。

离散式的PID控制算法主要有位置式PID和增量式PID两种,本文使用的是位置式PID控制。由上文给出的PID控制算法:

quartus pid,fpga开发,fpga

对于离散信号而言,取某一采样点k,此时的误差e(t)为e(k)。则比例项的误差值就是e(k),而积分项可以用之前时段误差值的累加得到,即

quartus pid,fpga开发,fpga

同理,微分项的误差变化率也可以用当前时刻误差减去上一时刻误差得到,即

其中,T为采样周期。

在PID控制公式中,可将KI,KD写作另一种形式,如下:

quartus pid,fpga开发,fpga

式中引入了积分时间常数TI和微分时间常数TD,从而使得KI和KD得以用KP表示出来。由此可以得出离散PID控制的公式:

quartus pid,fpga开发,fpga

quartus pid,fpga开发,fpga

由此得出的即为离散PID控制的位置式算法。

2.PID控制系统Simulink仿真

利用Simulink对控制系统进行仿真,主要目的是选取合适的PID参数,并获取输入输出数据,便于使用Modelsim进行Verilog代码的仿真,并将Simulink的仿真结果与Modelsim仿真结果对比,验证仿真的正确性。搭建的控制系统框图如下:

quartus pid,fpga开发,fpga

图中目标信号输入为阶跃信号,初值为0,终值为1,阶跃时间为1s。PID参数KP=50,KI=100,KD=3。将target和sig_in的值输出到工作区,作为Modelsim仿真时的输入量。将仿真运行5s,结果如图所示:

quartus pid,fpga开发,fpga

上图中,上方曲线为误差信号,中间曲线为系统输出,也是下一时刻反馈信号输入,即Modelsim仿真中控制器的输入sig_in,下方曲线为控制器输出,即Modelsim仿真中的输出ctrl_out。

输出到Matlab工作区的值target和sig_in需要经过处理才能输入到Modelsim,Matlab处理代码如下:

% 将数据左移7位并取整,保留前七位并换算为整数方便计算
sig_in = round(sig_in * 1000000);
target = round(target * 1000000);

% 将十进制数转化为十六进制数
sig_in = dec2hex(sig_in);
target = dec2hex(target);

% 将数据保存为txt格式
% sig_in
in = fopen('sig_in.txt','wt');
fprintf(in,'%g\n',sig_in);
fclose(in);
% target
tgt = fopen('target.txt','wt');
fprintf(tgt,'%g\n',target);
fclose(tgt);

处理后即得到十六进制的输入数据。注意Matlab的十六进制数会保存为字符串格式,在输入到Modelsim仿真中时需要再次处理(实际上把引号删除即可)。

3.Verilog代码编写和Modelsim仿真

PID控制器的Verilog代码分为三个部分:误差计算模块、PID算法模块和主模块。

3.1 误差计算模块和PID算法模块编写

3.1.1 误差计算模块

误差计算模块的主要功能为计算比例项、积分项和微分项的误差值,并对积分项的误差累加值进行限幅,代码如下:

module error (
        input  wire                         clk     ,   // 时钟信号
        input  wire                         rstn    ,   // 复位信号
        input  wire     signed     [31:0]   sig_in  ,   // 反馈信号输入
        input  wire     signed     [31:0]   target  ,   // 目标信号

        output reg      signed     [31:0]   error   ,   // 当前状态误差信号
        output reg      signed     [31:0]   error1  ,   // 上一状态误差信号
        output reg      signed     [31:0]   sum_e       // 误差信号累加值 用于积分环节
    );

    parameter [31:0] itg_max = 32'd100000000     ;       // 积分限幅,最大累加值为100
    parameter [31:0] itg_min = -32'd100000000    ;       // 积分限幅,最小累加值为-100
    always @(posedge clk or negedge rstn) begin
        if(!rstn) begin             // 复位
            error  <= 32'd0 ;
            error1 <= 32'd0 ;
            sum_e  <= 32'd0 ;
        end
        else begin
            error  <= target - sig_in   ;       // 误差信号e = 目标信号t - 反馈信号s
            error1 <= error             ;       // 将误差信号打一拍 得到上一时刻的误差值
            // 由于二进制数使用补码表示正负,因此限幅的条件与简单的十进制数表示方法存在差异
            if ((sum_e > itg_max) && (sum_e < 32'h7FFF_FFFF)) begin
                sum_e <= itg_max;
            end
            else if ((sum_e < itg_min) && (sum_e > 32'h8000_0000)) begin
                sum_e <= itg_min;
            end
            else
                sum_e  <= sum_e + error     ;       // 积分误差累加                     
        end
    end

endmodule

由于Verilog程序中需要给定输入输出的位宽,因此限幅功能也可以不加

3.1.2 PID算法模块

PID算法模块对误差模块输出的误差进行处理,输出PID控制器输出,代码如下:

module pid_ctrl (
        input  wire                clk     ,    // 时钟
        input  wire                rstn    ,    // 复位
        input  wire signed [31:0]  error   ,    // 误差
        input  wire signed [31:0]  error1  ,    // 上一时刻误差
        input  wire signed [31:0]  sum_e   ,    // 误差累加值

        input  wire signed [7:0]   kp      ,    // 比例系数
        input  wire signed [7:0]   ki      ,    // 积分系数
        input  wire signed [7:0]   kd      ,    // 微分系数

        output reg  signed [63:0]  ctrl_out     // 控制器输出
    );

    always @(posedge clk or negedge rstn) begin
        if(! rstn) begin
            ctrl_out <= 64'd0;
        end
        else begin
            ctrl_out <= (kp*error) + (ki*sum_e) + (kd*(error - error1));    // PID计算
        end
    end

endmodule

3.2 主模块及Testbench模块编写

3.2.1 主模块编写

主模块只需将两个模块依次例化即可,代码如下:

module pid_controller (
        input  wire                  clk      ,      // 时钟50MHz
        input  wire                  rstn     ,      // 复位信号
        input  wire signed [31:0]    sig_in   ,      // 反馈信号输入
        input  wire signed [31:0]    target   ,      // 目标信号

        input  wire signed [7:0]     kp       ,      // 比例环节系数
        input  wire signed [7:0]     ki       ,      // 积分环节系数
        input  wire signed [7:0]     kd       ,      // 微分环节系数

        output wire signed [63:0]    ctrl_out        // 控制信号输出
    );

    wire     [31:0]  error   ;
    wire     [31:0]  error1  ;
    wire     [31:0]  sum_e   ;
    error error_inst (
              .clk            (clk)       ,
              .rstn           (rstn)      ,
              .sig_in         (sig_in)    ,
              .target         (target)    ,
              .error          (error)     ,
              .error1         (error1)    ,
              .sum_e          (sum_e)
          );

    pid_ctrl pid_ctrl_inst (
                 .clk            (clk)     ,
                 .rstn           (rstn)    ,
                 .error          (error)   ,
                 .error1         (error1)  ,
                 .sum_e          (sum_e)   ,
                 .kp             (kp)      ,
                 .ki             (ki)      ,
                 .kd             (kd)      ,
                 .ctrl_out       (ctrl_out)
             );

endmodule

3.2.2 Testbench模块编写

代码如下:

`timescale 1ps/1ps
module pid_controller_tb;

    //Ports
    reg                         clk     ;
    reg                         rstn    ;
    reg   signed  [31:0]        sig_in  ;
    reg   signed  [31:0]        target  ;
    reg   signed  [7:0]         kp      ;
    reg   signed  [7:0]         ki      ;
    reg   signed  [7:0]         kd      ;
    wire  signed  [63:0]        ctrl_out;

    integer i;
    reg [31:0]  txt_in       [0:500-1]  ;
    reg [31:0]  txt_target   [0:500-1]  ;
    reg [7:0]   count                   ;
    reg [15:0]  file                    ;
    initial begin
        $readmemh("sig_in.txt", txt_in);      // 读取输入信号sig_in
        $readmemh("target.txt", txt_target);  // 读取输入信号target
        file = $fopen("ctrl_out.txt","w");    // 建立新文件用于保存输出ctrl_out
    end
    initial begin   
        // 给定PID系数,数值与上面不同,原因见下 3.3
        kp      =   8'd50  ;
        ki      =   8'd1   ;
        kd      =   8'd300 ;
        //开启时钟及复位
        clk     =   1'b0    ;
        rstn    =   1'b1    ;
        # 5;
        rstn    =   1'b0    ;
        # 5;
        rstn    =   1'b1    ;
        // 依次读取输入数据
        for (i = 0;i <= 500; i = i + 1) begin
            sig_in = txt_in[i]      ;
            target = txt_target[i]  ;
            #10;
        end
    end

    pid_controller pid_controller_inst (
                       .clk         (clk)       ,
                       .rstn        (rstn)      ,
                       .sig_in      (sig_in)    ,
                       .target      (target)    ,
                       .kp          (kp)        ,
                       .ki          (ki)        ,
                       .kd          (kd)        ,
                       .ctrl_out    (ctrl_out)
                   );

    always #5  clk = ~clk ;
    // 将ctrl_out保存到txt文件
    always @(posedge clk) begin
        if (count < 8'd500) begin
            $fwrite(file,"%d\n", ctrl_out);
            count <= count + 1;
        end
        else begin
            count <= 8'd0;
            $fclose(file);   // 关闭文件读写
        end
    end

endmodule

3.3 仿真结果

利用Modelsim进行仿真,结果如下图:

quartus pid,fpga开发,fpga

由上图可看出,Modelsim输出的波形与图2中Matlab中的仿真波形基本一致,将输出的ctrl_out.txt进行处理后放入Matlab工作区(保存为矩阵D),导入到Simulink中代替PID控制器的输出,框图如下:

quartus pid,fpga开发,fpga

仿真5s,在scope“输出比较”模块中观察输出信号,如下图:

quartus pid,fpga开发,fpga

由上图不难看出,两个输出的信号波形基本相同。

在Testbench文件中,使用的PID控制系数与仿真时的系数不同。如果仍使用KP=50,KI=100,KD=3的系数结果如下图:

quartus pid,fpga开发,fpga

由离散PID算法的公式:

quartus pid,fpga开发,fpga

可以看出相比于连续的PID控制算法,式中多了采样周期T,因此离散PID的参数与连续PID的参数相比应该多一个采样周期T,即:

经处理后KI=1,KD=300,修正后的PID参数即可得出正确的仿真值。文章来源地址https://www.toymoban.com/news/detail-775837.html

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

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

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

相关文章

  • 【OpenAI】Python:基于 Gym-CarRacing 的自动驾驶项目(4) | 车辆控制功能的实现 | 开环控制 | 闭环控制 | 启停式控制 | PID 控制 | Stanley 控制器

    【OpenAI】Python:基于 Gym-CarRacing 的自动驾驶项目(4) | 车辆控制功能的实现 | 开环控制 | 闭环控制 | 启停式控制 | PID 控制 | Stanley 控制器

       猛戳!跟哥们一起玩蛇啊  👉 《一起玩蛇》🐍  ​ 💭 写在前面: 本篇是关于多伦多大学自动驾驶专业项目的博客。GYM-Box2D CarRacing 是一种在 OpenAI Gym 平台上开发和比较强化学习算法的模拟环境。它是流行的 Box2D 物理引擎的一个版本,经过修改以支持模拟汽车在赛道上

    2024年02月08日
    浏览(12)
  • 【OpenAI】Python:(4) 基于 Gym-CarRacing 的自动驾驶项目 | 车辆控制功能的实现 | 开环控制 | 闭环控制 | 启停式控制 | PID 控制 | Stanley 控制器

    【OpenAI】Python:(4) 基于 Gym-CarRacing 的自动驾驶项目 | 车辆控制功能的实现 | 开环控制 | 闭环控制 | 启停式控制 | PID 控制 | Stanley 控制器

       猛戳!跟哥们一起玩蛇啊  👉 《一起玩蛇》🐍  ​ 💭 写在前面: 本篇是关于多伦多大学自动驾驶专业项目的博客。GYM-Box2D CarRacing 是一种在 OpenAI Gym 平台上开发和比较强化学习算法的模拟环境。它是流行的 Box2D 物理引擎的一个版本,经过修改以支持模拟汽车在赛道上

    2024年02月03日
    浏览(14)
  • 基于simulink的PID控制器设计

    基于simulink的PID控制器设计

    目录 1、PID算法的基本理论 1.1 PID 控制的基本概念 1.2 基本公式 1.3 PID控制系统原理图 2、在simulink中搭建PID控制器模型及调参  3、调参 PID 控制器是一种比例、积分、微分并联控制器。它是最广泛应用的一种控制器。在 PID 控制器中,它的数学模型由比例、积分、微分三部分

    2024年02月03日
    浏览(8)
  • 【抗扰PID控制】干扰抑制PID控制器研究(Matlab代码实现)

    【抗扰PID控制】干扰抑制PID控制器研究(Matlab代码实现)

    💥💥💞💞 欢迎来到本博客 ❤️❤️💥💥 🏆博主优势: 🌞🌞🌞 博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️ 座右铭: 行百里者,半于九十。 📋📋📋 本文目录如下: 🎁🎁🎁 目录 💥1 概述 📚2 运行结果 🎉3 参考文献 🌈4 Matlab代码、Simulink、文

    2024年02月11日
    浏览(11)
  • 模糊PID控制器的实现

    模糊PID控制器的实现

    本文讨论有关模糊PID相关的问题。模糊PID是一种将PID控制和模糊算法结合起来的控制算法,其实质上是将模糊算法用在了PID的参数整定上,以此来满足需要动态调整PID参数的系统的要求。 (1)传统的控制方法有时无法满足控制精度的要求,而且抗干扰的能力较弱,模糊控制可以

    2023年04月16日
    浏览(7)
  • 基于FPGA和Verilog实现的9层电梯控制器仿真设计

    基于FPGA和Verilog实现的9层电梯控制器仿真设计

    资源下载地址:https://download.csdn.net/download/sheziqiong/85628810 资源下载地址:https://download.csdn.net/download/sheziqiong/85628810 电梯最少可以往返于0—9层楼。 乘客要去的楼层数A可手动输入并显示,按取消键可清除本次输入。 可自动显示电梯运行的楼层数B 当AB时,电梯上升; 当AB时,

    2024年02月02日
    浏览(9)
  • 基于Matlab自抗扰控制器及其PID控制(附上完整源码+数据)

    自抗扰控制器(Active Disturbance Rejection Control, ADRC)是一种新型的控制策略,它具有强大的抗干扰能力和良好的控制性能。与传统的PID控制器相比,ADRC能够更好地抑制系统的干扰,提高控制系统的稳定性和鲁棒性。 在ADRC中,核心思想是引入一个扰动观测器(Disturbance Observer,

    2024年02月16日
    浏览(6)
  • 基于FPGA的4x4矩阵键盘控制器verilog开发实现

    基于FPGA的4x4矩阵键盘控制器verilog开发实现

    欢迎订阅《FPGA学习入门100例教程》、《MATLAB学习入门100例教程》 目录 一、理论基础 二、核心程序 三、测试结果        基于FPGA的4x4矩阵键盘控制器是一种使用FPGA(现场可编程门阵列)来实现对4x4矩阵键盘进行控制的设备。该控制器能够有效地降低硬件资源的使用,提高系

    2024年02月11日
    浏览(6)
  • 一级倒立摆控制 —— PID 控制器设计及 MATLAB 实现

    一级倒立摆控制 —— PID 控制器设计及 MATLAB 实现

    最优控制介绍 一级倒立摆控制 —— 系统建模(传递函数模型与状态空间方程表示) 一级倒立摆控制 —— 最优控制 线性二次型控制(LQR)及 MATLAB 实现 一级倒立摆控制 —— MPC 控制器设计及 MATLAB 实现 一级倒立摆控制 —— ROS2 仿真 一级倒立摆控制 —— LQR 控制器 GAZEBO 仿

    2024年02月03日
    浏览(11)
  • 【毕业设计】42基于FPGA的LCD1602控制器设计仿真与实现(原理图+仿真+源代码+论文)

    【毕业设计】42基于FPGA的LCD1602控制器设计仿真与实现(原理图+仿真+源代码+论文)

    包含此题目毕业设计全套资料: 原理图工程文件 仿真工程文件 源代码 仿真截图 低重复率论文,字数:19964 基于altera 公司cyclone4代芯片的fpga以及quartusII软件设计一款屏幕显示系统,显示装置可以选择点阵或字符型液晶,最终实现滚动显示、可控制滚动方向、暂停、清屏等功能

    2024年02月04日
    浏览(18)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包