基于FPGA的PID算法学习———实现PID比例控制算法

基于FPGA的PID算法学习


前言

学习内容:参考网站:
PID算法控制

PID即:Proportional(比例)、Integral(积分)、Differential(微分)的缩写。也就是说,PID算法是结合这三种环节在一起的。

闭环控制:输出会影响到输入,进而逐渐逼近目标。

一、PID算法分析

PID比例控制算法:

核心部分,大部分作用来自于P,I和D主要控制减小误差。

目标值:Target

实际值:Pid_out

误差值:e_t

上一时刻误差值:e_t_1

上两个时刻误差值:e_t_2

弥补值:u_t

相关公式:

误差值:e_t=Target - Pid_out

误差值:e_t_1=e_t

误差值:e_t_2=e_t_1

弥补值:u(t)= (Kp * (e(t)-e(t-1)) + Ki * e(t) + Kd * ( e(t)- 2*e(t-1)-e(t-2) ) )

输出值:Pid_out = Pid_out + u(t)

增量式PID:

二、PID仿真分析

1. PID代码

c 复制代码
`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2025/06/10 17:09:23
// Design Name: 
// Module Name: PID
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//
module PID(
     input                     sys_clk  ,  
     input                     rst_n,   
     //signal  
	  input		 signed	[7:0]  target,
	  output reg signed	[7:0]  Pid_out
    );
	 
	 reg	signed	[15:0]		e_t;//目标值和现在值的差距
	 reg	signed	[15:0]		e_t_1;//上一时刻差距
	 reg	signed	[15:0]		e_t_2;//上一时刻差距
	 reg	signed	[32:0]		u_t;//补偿值
     
	 parameter signed K_p = 32'd100;
	 parameter signed div_p = 8'd3;
	 
	 parameter signed K_i = 32'd250;
	 parameter signed div_i = 8'd3;
	 
	 parameter signed K_d = 32'd50;
	 parameter signed div_d = 8'd3;
//	 assign e_t = target - Pid_out;
	 always @(posedge sys_clk or negedge rst_n)begin
		  if(!rst_n)begin
				e_t <= 16'd0;
		  end
		  else begin
				e_t <= target - Pid_out;
		  end
	 end
	 
	 always @(posedge sys_clk or negedge rst_n)begin
		  if(!rst_n)begin
				e_t_1 <= 16'd0;
		  end
		  else begin
				e_t_1 <= e_t;
		  end
	 end
	 
	 always @(posedge sys_clk or negedge rst_n)begin
		  if(!rst_n)begin
				e_t_2 <= 16'd0;
		  end
		  else begin
				e_t_2 <= e_t_1;
		  end
	 end
	 
	 always @(posedge sys_clk or negedge rst_n)begin
		  if(!rst_n)begin
				u_t <= 32'd0;
		  end
		  else begin
				u_t <= ((e_t - e_t_1) * K_p )/1000 + ( e_t * K_i)/1000 +  ( (e_t -(2* e_t_1) + e_t_2 ) * K_d)/1000 ;
		  end
	 end
	 
	 always @(posedge sys_clk or negedge rst_n)begin
		  if(!rst_n)begin
				Pid_out <= 8'd0;
		  end
		  else begin
		        Pid_out <= Pid_out + u_t;
		  end
	 end
	 
	 
	 
endmodule

2.PI代码

c 复制代码
module PID_control(
     input                     sys_clk  ,  
     input                     rst_n,   
     //signal  
	  input		 signed	[7:0]  target,
	  output reg signed	[7:0]  Pid_out
    );
	 
	 reg	signed	[15:0]		e_t;//目标值和现在值的差距
	 reg	signed	[15:0]		e_t_1;//上一时刻差距
	 reg	signed	[32:0]		u_t;//补偿值
     
	 parameter signed K_p = 32'd200;
	 parameter signed div_p = 8'd3;
	 
	 parameter signed K_i = 32'd310;
	 parameter signed div_i = 8'd3;
//	 assign e_t = target - Pid_out;
	 always @(posedge sys_clk or negedge rst_n)begin
		  if(!rst_n)begin
				e_t <= 16'd0;
		  end
		  else begin
				e_t <= target - Pid_out;
		  end
	 end
	 
	 always @(posedge sys_clk or negedge rst_n)begin
		  if(!rst_n)begin
				e_t_1 <= 16'd0;
		  end
		  else begin
				e_t_1 <= e_t;
		  end
	 end
	 
	 always @(posedge sys_clk or negedge rst_n)begin
		  if(!rst_n)begin
				u_t <= 32'd0;
		  end
		  else begin
				u_t <= ((e_t - e_t_1) * K_p )/1000 + ( e_t * K_i)/1000 ;
		  end
	 end
	 
	 always @(posedge sys_clk or negedge rst_n)begin
		  if(!rst_n)begin
				Pid_out <= 8'd0;
		  end
		  else begin
		        Pid_out <= Pid_out + u_t;
		  end
	 end
	 
	 
	 
endmodule

3.P代码

c 复制代码
module PID_trol(
     input                     sys_clk  ,  
     input                     rst_n,   
     //signal  
	  input		 signed	[7:0]  target,
	  output reg signed	[7:0]  Pid_out
    );
	 
	 reg	signed	[15:0]		e_t;//目标值和现在值的差距
	 reg	signed	[32:0]		u_t;//补偿值
     
	 parameter signed K_p = 32'd300;
	 parameter signed div = 8'd3;
//	 assign e_t = target - Pid_out;
	 always @(posedge sys_clk or negedge rst_n)begin
		  if(!rst_n)begin
				e_t <= 16'd0;
		  end
		  else begin
				e_t <= target - Pid_out;
		  end
	 end
	 
	 always @(posedge sys_clk or negedge rst_n)begin
		  if(!rst_n)begin
				u_t <= 32'd0;
		  end
		  else begin
				u_t <= (e_t * K_p )/1000;
		  end
	 end
	 
	 always @(posedge sys_clk or negedge rst_n)begin
		  if(!rst_n)begin
				Pid_out <= 8'd0;
		  end
		  else begin
		        Pid_out <= Pid_out + u_t;
		  end
	 end
	 
	 
	 
endmodule

4.顶层

c 复制代码
`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2025/06/10 13:45:03
// Design Name: 
// Module Name: top
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module top(
     input                     sys_clk  ,  
     input                     rst_n,   
     //signal  
	  input		  signed	[7:0]  target,
	  output wire signed	[7:0]  P_out,
	  output wire signed	[7:0]  Pi_out,
	  output wire signed	[7:0]  Pid_out
    );
    
    PID u_PID (
        .sys_clk   (sys_clk),
        .rst_n     (rst_n),
        .target    (target),
        .Pid_out   (Pid_out) 
    );
    
   PID_control u_PI (
        .sys_clk   (sys_clk),
        .rst_n     (rst_n),
        .target    (target),
        .Pid_out   (Pi_out) 
    );
    
    PID_trol u_P(
    .sys_clk   (sys_clk),
    .rst_n     (rst_n),
    .target    (target),
    .Pid_out   (P_out)
);
endmodule

5.测试文件

c 复制代码
`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2025/06/10 13:48:03
// Design Name: 
// Module Name: tb_top
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//

`timescale 1ns / 1ps

module tb_top();
    // 输入信号
    reg         sys_clk;
    reg         rst_n;
    reg signed [7:0] target;
    
    // 输出信号
    wire signed [7:0] P_out;
    wire signed [7:0] Pi_out;
    wire signed [7:0] Pid_out;
    // 实例化顶层模块
    top u_top (
        .sys_clk (sys_clk),
        .rst_n   (rst_n),
        .target  (target),
        .P_out   (P_out),
        .Pi_out  (Pi_out),
        .Pid_out (Pid_out)
    );
    
    // 时钟生成(100MHz)
    initial begin
        sys_clk = 0;
        forever #10 sys_clk = ~sys_clk;  // 10ns周期 = 100MHz
    end
    
    // 测试激励
    initial begin
        // 初始化并复位
        rst_n = 0;
        target = 0;
        #20;  // 等待两个时钟周期
        
        // 释放复位
        rst_n = 1;
        #10;
        
        // 测试场景 1:正目标值
        target = 8'd100;   // +50


    end
    

endmodule

6.仿真波形

总结

简单测试,有问题欢迎交流

相关推荐
CappuccinoRose8 分钟前
专项事件体系
前端·学习·网络状态·表单事件·剪贴板事件·拖放事件·页面可见性
(Charon)12 分钟前
【Kafka】消息队列学习(一):为什么需要Kafka?从消息队列到整体架构
学习·架构·kafka
金金计较.18 分钟前
Go语言-2
开发语言·算法·golang
计算机编程-吉哥29 分钟前
基于机器学习的城市交通拥堵分析与预测平台【计算机毕业设计选题·机器学习·随机森林算法】
hadoop·算法·随机森林·机器学习·课程设计·计算机毕业设计选题·大数据毕业设计选题推荐
传奇开心果编程44 分钟前
【Rust入门知识点学与练】第26课:Unsafe Rust
开发语言·学习·rust
zyeyeye1 小时前
C++入门:从HelloWorld到命名空间揭秘
c语言·开发语言·c++·算法
牧羊人.3331 小时前
动手学深度学习 04 | Dataset 和 DataLoader、数据增强
人工智能·pytorch·深度学习·算法
励志不掉头发的内向程序员1 小时前
【LibreCAD 2D架构】从 addHistory 到 RS_UndoCycle:LibreCAD 里的两套 History 与撤销机制
开发语言·c++·qt·学习·系统架构
`流年づ1 小时前
人工智能学习笔记 - 自动微分
人工智能·笔记·学习
elseif1231 小时前
【双指针/二分】P1102 A-B 数对
c++·算法·二分·双指针