基于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.仿真波形


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