FPGA实现PI控制

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

目录

1 pid的基本原理

2 FPGA实现 

3 联合仿真 


1 pid的基本原理

PID控制器(比例-积分-微分控制器),由比例单元(Proportional)、积分单元(Integral)和微分单元(Derivative组成。可以透过调整这三个单元的增益K_{p}K_{i}K_{d}来调定其特性。PID控制器主要适用于基本上线性,且动态特性不随时间变化的系统。

fpga 控制 帕尔贴,fpga开发

有些应用只需要PID控制器的部分单元,可以将不需要单元的参数设为零即可。因此PID控制器可以变成PI控制器PD控制器P控制器I控制器。其中又以PI控制器比较常用,因为D控制器对回授噪声十分敏感,而若没有I控制器的话,系统不会回到参考值,会存在一个误差量。

定义u(t)为控制输出,PID算法可以用下式表示

fpga 控制 帕尔贴,fpga开发

Kp——比例系数

Ti——积分时间常数

Td——微分时间常数

e(t)——偏差

u(t)——控制量

在采样周期足够小时,可以作如下近似:

fpga 控制 帕尔贴,fpga开发

T———— 为采样周期
k———— 为采样序号, k=0,1,2….

用这种近似方法,可以得到两种形式数字PID控制算法 :

位置式PID算法

fpga 控制 帕尔贴,fpga开发

可以看出数字调节的输出u(k)跟过去的所有偏差信号有关,计算机需要对e(i)进行累加,运算量太大,一般不用

增量式PID算法

Δu(k)=u(k)−u(k−1)=kp​[e(k)−e(k−1)]+ki​e(k)

增量式PID的输出为

u(k)=u(k−1)+Δu(k)

u(k)=u(k−1)+Δu(k)=u(k−1)+Kp​∗(e(k)−e(k−1))+Kie(k)

2 FPGA实现 

fpga 控制 帕尔贴,fpga开发

fpga 控制 帕尔贴,fpga开发

状态机代码:


//
//
// u(k)=u(k−1)+Δu(k)=u(k−1)+KP​∗(e(k)−e(k−1))+Ki​​e(k)
//
module pi #(
    parameter [23:0] k_p = 24'd30,  //比例参数,避免小数
    parameter [23:0] k_i = 24'd2    //积分参数
) (
    input  wire signed [15:0] i_real,  //输出
    input  wire signed [15:0] i_aim,   //目标
    input  wire               clk,     //系统时钟
    input  wire               rstn,    //复位
    input  wire               pi_en,   //pi控制器开关
    output wire signed [15:0] u_out,   //pi控制器输出
    output reg                o_en     //pi控制器输出有效标志
);
  reg signed [31:0] error_1, error_2, delta_error;  //ek ek-1 e(k)-e(k-1)
  reg signed [31:0] mult_kp, mult_i, mult_i1, mult_i2;  //kp*(e(k)-e(k-1)) ki*ek  寄存积分误差
  reg signed [31:0] u_out_temp, delta_u;  //u(k-1)+deltau

  assign u_out = u_out_temp[15:0];
  //误差限幅 加法 乘法 减法	
  function reg signed [31:0] protect_add(input signed [31:0] a, input signed [31:0] b);
    begin
      protect_add = $signed({a[31], a}) + $signed({b[31], b});
      if (protect_add > $signed(33'h7fffffff))  //
        protect_add = $signed(32'h7fffffff);
      else if (protect_add < -$signed(32'h7fffffff))
	   protect_add = -$signed(32'h7fffffff);
      else protect_add = protect_add;
    end
  endfunction

  function reg signed [31:0] protect_mul(input signed [31:0] a, input signed [24:0] b);
    begin
      protect_mul = a * b;
      if (protect_mul > $signed(57'h7fffffff))  //
        protect_mul = $signed(32'h7fffffff);
      else if (protect_mul < -$signed(57'h7fffffff))
	   protect_mul = -$signed(32'h7fffffff);
      else protect_mul = protect_mul;
    end
  endfunction

  function reg signed [31:0] protect_subtract(input signed [31:0] a, input signed [31:0] b);
    begin
      protect_subtract = $signed({a[31], a}) - $signed({b[31], b});
      if (protect_subtract > $signed(33'h7fffffff))
	   protect_subtract = $signed(32'h7fffffff);
      else if (protect_subtract < -$signed(32'h7fffffff)) 
	  protect_subtract = -$signed(32'h7fffffff);
      else protect_subtract = protect_subtract;
    end
  endfunction

reg [2:0] state ;
parameter IDLE = 3'd0;
parameter Ki_ek = 3'd1;
parameter Delta_ek = 3'd2;
parameter Kp_delta_ek = 3'd3;
parameter Delta_u = 3'd4;
parameter U_out = 3'd5;
  //e(k)
  always @(posedge clk or negedge rstn)
    if (~rstn) begin
      state <= IDLE;
      error_1 <= 0;
	  	error_2 <= 0;
		delta_error <= 0;
		mult_kp <= 0;
		mult_i <=0;
		mult_i1 <=0;
		mult_i2 <=0;
		delta_u<=0;
		u_out_temp<=0;
	end
	else begin 
		case (state)
	IDLE:  if (pi_en) begin    //ek
				error_1<= protect_subtract(i_aim,i_real);
				o_en<=0;
				state <=Ki_ek;
			end
			else begin
				error_1<=0;
				state<=IDLE;
				end
	Ki_ek: begin  
				error_2<=error_1;//ek-1
				mult_i<=protect_mul(error_1,k_i);//ki*ek
				state<=Delta_ek;
			end
	Delta_ek: 	begin 
				mult_i1<=mult_i;//delay_ki*ek
				delta_error<=protect_subtract(error_1,error_2);//ek-ek-1
				state<=Kp_delta_ek;
			end
	Kp_delta_ek:	begin 
				mult_i2<=mult_i1;//delay_ki*ek again
				mult_kp<=protect_mul(delta_error,k_p);//kp*(ek-ek-1)
				state<=Delta_u;
					end
	Delta_u:	begin
		 		delta_u <= protect_add(mult_i2, mult_kp);//kp*(ek-ek-1)+ki*ek
				state<=U_out;
				end
	U_out:	begin 
				 u_out_temp = protect_add(u_out_temp, delta_u);//u(k)=u(k−1)+Δu(k)
				 state<=IDLE;
				 o_en<=1'b1;
			end
	default :
			state<=IDLE;
		endcase
	end

endmodule

状态机:

fpga 控制 帕尔贴,fpga开发

流水线代码:

//
//
// u(k)=u(k−1)+Δu(k)=u(k−1)+KP​∗(e(k)−e(k−1))+Ki​​e(k)
//
module pi #(
    parameter [23:0] k_p = 24'd30,  //比例参数,避免小数
    parameter [23:0] k_i = 24'd2    //积分参数
) (
    input  wire signed [15:0] i_real,  //输出
    input  wire signed [15:0] i_aim,   //目标
    input  wire               clk,     //系统时钟
    input  wire               rstn,    //复位
    input  wire               pi_en,   //pi控制器开关
    output wire signed [15:0] u_out,   //pi控制器输出
    output reg                o_en     //pi控制器输出有效标志
);
  reg signed [31:0] error_1, error_2, delta_error;  //ek ek-1 e(k)-e(k-1)
  reg signed [31:0] mult_kp, mult_i, mult_i1, mult_i2;  //kp*(e(k)-e(k-1)) ki*ek  寄存积分误差
  reg signed [31:0] u_out_temp, delta_u;  //u(k-1)+deltau
  reg en_s1, en_s2, en_s3, en_s4, en_s5;  //流水线标志

  assign u_out = u_out_temp[15:0];
  //误差限幅 加法 乘法 减法	
  function reg signed [31:0] protect_add(input signed [31:0] a, input signed [31:0] b);
    begin
      protect_add = $signed({a[31], a}) + $signed({b[31], b});
      if (protect_add > $signed(33'h7fffffff))  //
        protect_add = $signed(32'h7fffffff);
      else if (protect_add < -$signed(32'h7fffffff))
	   protect_add = -$signed(32'h7fffffff);
      else protect_add = protect_add;
    end
  endfunction

  function reg signed [31:0] protect_mul(input signed [31:0] a, input signed [24:0] b);
    begin
      protect_mul = a * b;
      if (protect_mul > $signed(57'h7fffffff))  //
        protect_mul = $signed(32'h7fffffff);
      else if (protect_mul < -$signed(57'h7fffffff))
	   protect_mul = -$signed(32'h7fffffff);
      else protect_mul = protect_mul;
    end
  endfunction

  function reg signed [31:0] protect_subtract(input signed [31:0] a, input signed [31:0] b);
    begin
      protect_subtract = $signed({a[31], a}) - $signed({b[31], b});
      if (protect_subtract > $signed(33'h7fffffff))
	   protect_subtract = $signed(32'h7fffffff);
      else if (protect_subtract < -$signed(32'h7fffffff)) 
	  protect_subtract = -$signed(32'h7fffffff);
      else protect_subtract = protect_subtract;
    end
  endfunction

 //e(k)
  always @(posedge clk or negedge rstn)
    if (~rstn) begin
      en_s1   <= 1'b0;
      error_1 <= 0;
    end else begin
      en_s1 <= pi_en;
      if (pi_en) begin
        error_1 <=  protect_subtract(i_aim,i_real);
      end
    end
  //e(k-1) 
  always @(posedge clk or negedge rstn)
    if (~rstn) begin
      en_s2   <= 1'b0;
      error_2 <= 0;
    end else begin
      en_s2 <= en_s1;
      if (en_s1) begin
        error_2   <= error_1;  //e(k-1)
        mult_i <= protect_mul(error_1, k_i);  //ki*ek
      end
    end
  //比例误差的计算 减法一个周期 乘法一个周期 
  //所以需要将积分误差延时两个周期
  //e(k)-e(k-1)
  always @(posedge clk or negedge rstn)
    if (~rstn) begin
      en_s3       <= 1'b0;
      mult_i1  <= 0;
      delta_error <= 0;
    end else begin
      en_s3 <= en_s2;
      if (en_s2) begin
        mult_i1  <= mult_i;
        delta_error <= protect_subtract(error_1, error_2);
      end
    end
  //	kp*(e(k)-e(k-1))
  always @(posedge clk or negedge rstn)
    if (~rstn) begin
      en_s4      <= 1'b0;
      mult_i2 <= 0;
      mult_kp  <= 0;
    end else begin
      en_s4 <= en_s3;
      if (en_s3) begin
        mult_i2 <= mult_i1;
        mult_kp  <= protect_mul(delta_error, k_p);
      end
    end
  //delta_u
  always @(posedge clk or negedge rstn)
    if (~rstn) begin
      en_s5   <= 1'b0;
      delta_u <= 0;
    end else begin
      en_s5 <= en_s4;
      if (en_s4) begin
        delta_u <= protect_add(mult_i2, mult_kp);
      end
    end
  //		u_out
  always @(posedge clk or negedge rstn)
    if (~rstn) begin
      o_en       <= 1'b0;
      u_out_temp <= 0;
    end else begin
      o_en <= en_s5;
      if (en_s5) begin
        u_out_temp = protect_add(u_out_temp, delta_u);
      end
    end
endmodule

流水线的速度比状态机快很多,但是资源也比状态机消耗得多。

3 联合仿真 

testbench

`timescale 1ns / 1ps


module tb_pi();
//输入
reg      [15:0] i_real;
reg      [15:0] i_aim;
reg       sys_clk;
reg       rstn;
reg       pi_en;
//输出
wire      [15:0] u_out;
wire       o_en  ;




//初始值
initial
    begin
        sys_clk = 1'b1;
        rstn   <=  1'b0;
		  i_real<=16'd0;
        i_aim<=16'd350;
        pi_en<=1'b1;
        #20
        rstn   <=  1'b1;

    end

always #10 sys_clk = ~sys_clk;
//将pi控制器的输出减少2^6倍
always #30  i_real =i_real+u_out>> 6;
//例化
pi  u_pi
(
. i_real      (i_real) ,
. i_aim       (i_aim),
. clk         (sys_clk ),
. rstn        (rstn ),
. pi_en       (1'b1),     
. u_out       (u_out),
. o_en        (o_en)
);



endmodule

3、仿真结果

fpga 控制 帕尔贴,fpga开发

这里上升的比较缓慢,可以将u_out与i_real,之间的线性关系即本文中的2^6 适当调整。 

参考:

PI闭环的FPGA实现_爱折腾的张Sir的博客-CSDN博客深入浅出PID控制算法(二)————PID算法离散化和增量式PID算法原理及Matlab实现_万般滋味皆生活的博客-CSDN博客_离散pid公式文章来源地址https://www.toymoban.com/news/detail-779024.html

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

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

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

相关文章

  • 电子定时器洗衣机控制Verilog代码Quartus 睿智FPGA开发板

    名称:电子定时器洗衣机控制Verilog代码Quartus   睿智FPGA开发板(文末获取) 软件:Quartus 语言:Verilog 代码功能: 1.设计一个电子定时器,控制洗衣机作如下运转:定时启动,正转20秒,暂停10秒,反 转20秒,暂停10秒,定时未到回到“正转20秒暂停10秒..... 2.若定时到,则停机发

    2024年01月20日
    浏览(53)
  • 自动售货机控制系统的FPGA设计与实现

            采用VHDL语言设计一个自动售货机控制系统,要求能在MaxPlus Ⅱ软件平台进行仿真模拟,技术指标如下: 1)有2元、3元、8元商品;有1元、5元、10元钱币; 2)当投入的总币值大于顾客购买的商品单价时,机器提供商品并将余币退出,回到初始状态;若投入的总币值小

    2024年02月06日
    浏览(45)
  • QuartusLCD1602液晶驱动显示控制verilog代码青创QC-FPGA开发板

    名称:QuartusLCD1602液晶驱动显示控制verilog代码青创QC-FPGA开发板(文末获取) 软件:Quartus 语言:Verilog 代码功能: LCD1602液晶驱动显示控制 第一行显示\\\"HUAWEI NOVA7\\\"  第二行显示\\\"5Gshouji\\\"      显示内容可以直接修改以下代码实现 parameter   Data_First =  \\\"  HUAWEI NOVA7 \\\",         

    2024年02月03日
    浏览(41)
  • FPGA 学习笔记:Verilog 实现LED流水灯控制

    在初步了解 Xilinx Vivado 的使用后,开启了FPGA Hello World 程序:LED 流水灯控制 在嵌入式MCU中,流水灯需要延时来实现,FPGA的延时,使用外部晶振来实现 实现 3个 LED 流水灯控制,也就是循环依次点亮, LED 低电平亮, 高电平灭,FPGA 有一个40MHz的外部晶振,作为系统时钟输入开

    2023年04月08日
    浏览(42)
  • 基于fpga的ddr3读写控制,纯verilog实现,能实现多通道图像数据读写控制

    基于fpga的ddr3读写控制,纯verilog实现,能实现多通道图像数据读写控制,模块接口清晰,可移植性高. 基于FPGA的DDR3读写控制是一项重要的技术,它为多通道图像数据的读写提供了高效的解决方案。本文将介绍一种纯Verilog实现的DDR3读写控制模块,旨在实现模块接口清晰、可移

    2024年04月12日
    浏览(57)
  • 【FPGA开发】HDMI通信协议解析及FPGA实现

      笔者在这里使用的开发板是正点原子的达芬奇开发板,FPGA型号为XC7A35TFGG484-2。参考的课程是正点原子的课程手把手教你学达芬奇达芬奇Pro之FPGA开发篇。   HDMI,全称为High Definition Multimedia Interface,即高清多媒体接口。它不仅可以传输视频信号,还可以传输音频信号。上

    2024年02月21日
    浏览(48)
  • 基于 VPX 总线的工件台运动控制系统研究与开发-DSP+FPGA硬件架构(一)

    作为光刻机核心单元之一,超精密工件台主要负责实现快速扫描、上下片、精密定位、调平调焦等功能。目前,较为成熟的方案大多采用 VME 并行总线架构来建立超精密工件台控制系统,由于随着系统性能要求的提升,VME 总线以及相应的处理器已无法满足需求,所以必须设计

    2024年02月03日
    浏览(46)
  • 基于DSP+FPGA的机载雷达伺服控制系统的硬件设计与开发(一)总体设计

    2.1 功能要求及性能指标 2.1.1 功能要求 ( 1 )具备方位和俯仰两轴运动的能力; (2)方位轴可实现预置、周扫和扇扫功能; (3)俯仰轴可实现预置功能。 2.1.2 性能指标 ( 1 )运动范围:方位转动范围为 ,俯仰转动范围为 ; (2)角速度:方位最大角速度为 100º/s ,俯仰最

    2024年02月16日
    浏览(44)
  • 紫光同创 FPGA 开发跳坑指南(四)—— DDR3 控制器 IP 的使用

    DDR3 是一种大容量的存储器件,采用了预取技术和双边沿采样技术,以实现高速数据存储与读取,在视频处理中可以用来缓存 1 帧或多帧图像。 目录 一、紫光 DDR3 IP 的安装 二、紫光 DDR3 IP 的配置 三、DDR3 IP 的使用 3.1 DDR3 写操作 3.2 DDR3 读操作         在 Pango Design Suit 中,选

    2024年01月25日
    浏览(52)
  • 基于FPGA的永磁同步伺服控制系统的设计,在FPGA实现了伺服电机的矢量控制, 坐标变换,电流环,速度环,位置环,电机反馈接口,SVPWM

    一个基于FPGA的永磁同步伺服控制系统,利用Verilog语言在FPGA上实现了伺服电机的矢量控制、坐标变换、电流环、速度环、位置环以及电机反馈接口。这个系统具有很高的研究价值。 涉及到的知识点和领域范围主要包括:FPGA(现场可编程门阵列)、永磁同步伺服控制系统、矢

    2024年02月04日
    浏览(44)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包