PID闭环的FPGA实现

1 原理分析

最近小张同学在做项目的时候发现PI闭环的FPGA学习资料很少,秉持着“既然没有轮子,那么自己就造一个的原则”,于是乎自己写了个PI的Verilog程序。
FPGA中实现PI闭环与DSP、STM32、arm中都不一样,由于FPGA中没有数学库,需要从底层开始解决运算中产生的小数、除法等问题。因此FPGA中实现PI闭环相比来说有一点点难度。

​ 首先,位置式PI和增量式PI的选择问题,由于位置式PI的实现原理包含历史误差的累计,并且启动瞬间或状态突然切换瞬间会有突变现象,突变现象会影响电机的动态性能,同时启动电流会很大,而这会对电机工作状态产生影响,因此采用增量式PI控制更优。当然,我觉得用位置式pi也能适用于电机的pi闭环。因为本质上来说,这两种pi实现机理并无差异,最终的控制效果也应该差异不大。

而增量式PI控制通常包括并联式PI控制和串联式PI控制,并联式PI控制可以实现KpK_pKp​和KiK_iKi​ 的解耦,方便参数调试,所以采用并联式增量PI控制器。

上图是增量并联并联式PI框图,含义为参考值与实际值比较得到的差值分为两部分,一部分通过P的直接增益,另一部分通过积分的积分增益,合并输出。

下图是传递函数,只调节Kp相,可以调节幅值,对应的Ki值需要与之对应,可以调节控制系统的零点,Kp幅值增加对应的零点频率会下降,零点频率实际上是Kp和Ki的函数

典型pid系统的输出信号表达式如(1)所示
uk=Kp((et)+1Ti∫0te(t)d(t)+Tdde(k)e(k))u_k = K_p((e_t)+\frac{1}{T_i}\int ^t_0 e(t){\rm d}(t)+T_d\frac{de(k)}{e(k)}) uk​=Kp​((et​)+Ti​1​∫0t​e(t)d(t)+Td​e(k)de(k)​)

采用PI控制,即无微分项,则
uk=Kp((et)+1Ti∫0te(t)d(t))u_k = K_p((e_t)+\frac{1}{T_i}\int ^t_0 e(t){\rm d}(t)) uk​=Kp​((et​)+Ti​1​∫0t​e(t)d(t))

2 PI的硬件实现

在数字电路中,并无法实现连续时间的积分和微分,因此数字pid中,只能以固定采样周期来进行离散化,从而实现近似的连续时间的积分和微分,利用这个思想,将式(2)进行离散化,

  1. 用一系列采样时间kT来代替时间t
  2. 以和式来代替积分: ∫0te(t)d(t))=∑e(jT)T=T∑e(k)\int ^t_0 e(t){\rm d}(t)) = \sum e(jT)T = T\sum e(k) ∫0t​e(t)d(t))=∑e(jT)T=T∑e(k)
  3. 向后差分 来代替 微分 de(t)dt=e(k)−e(k−1)Δt=e(k)−e(k−1)Ts\frac{de(t)}{dt}=\frac{e(k)-e(k-1)}{\Delta t}=\frac{e(k)-e(k-1)}{T_s}dtde(t)​=Δte(k)−e(k−1)​=Ts​e(k)−e(k−1)​

可得位置式PID的离散化如下式
uk=Kp(ek)+Ki∑(ek)+Kd(e(k)−e(k−1))u_k = K_p(e_k)+K_i\sum(e_k)+K_d(e(k)-e(k-1)) uk​=Kp​(ek​)+Ki​∑(ek​)+Kd​(e(k)−e(k−1))
PI中令位置式KdK_dKd​ = 0 即可得 位置式PI表达式
uk=Kp(ek)+Ki∑(ek)u_k = K_p(e_k)+K_i\sum(e_k) uk​=Kp​(ek​)+Ki​∑(ek​)
硬件中可以对误差的累计Sum(k)=Sum(k−1)+(k)。Sum(k)=Sum(k-1)+(k)。Sum(k)=Sum(k−1)+(k)。

增量式PID

增量为:
Δu(k)=u(k)−u(k−1)=kp[e(k)−e(k−1)]+kie(k)+kd[e(k)−2e(k−1)+e(k−2)]\Delta u(k) = u(k)-u(k-1) =k_p[e(k)-e(k-1)]+k_i\,\,e(k)+k_d\,[e(k)-2e(k-1)+e(k-2)] Δu(k)=u(k)−u(k−1)=kp​[e(k)−e(k−1)]+ki​e(k)+kd​[e(k)−2e(k−1)+e(k−2)]
令位置式KdK_dKd​ = 0 即可得
Δu(k)=u(k)−u(k−1)=kp[e(k)−e(k−1)]+kie(k)\Delta u(k) = u(k)-u(k-1) =k_p[e(k)-e(k-1)]+k_i\,\,e(k) Δ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)+\Delta u(k) u(k)=u(k−1)+Δu(k)

然而很多场合下需要的往往不只增量,还有上一拍的输出值,于是可知增量式PI调节器算法为
u(k)=u(k−1)+Δu(k)=u(k−2)+Δu(k−1)+Δu(k)=u(0)+u(1)+.....+u(k−1)u(k)=u(k-1)+\Delta u(k)=u(k-2)+\Delta u(k-1)+\Delta u(k)=u(0)+u(1)+.....+u(k-1) u(k)=u(k−1)+Δu(k)=u(k−2)+Δu(k−1)+Δu(k)=u(0)+u(1)+.....+u(k−1)
由于u(0)=0u(0)=0u(0)=0在具体编程操作中,对每一拍的Δu(k)\Delta u(k)Δu(k)进行累积,即为PI调节器的输出;同样地,为了避免超过允许值,仅需对输出限幅即可

事实上,由增量式PI
u(k)=u(k−1)+Δu(k)=u(k−1)+KP∗(e(k)−e(k−1))+KiTse(k)u(k)=u(k-1)+\Delta u(k)=u(k-1)+K_P*(e(k)-e(k-1))+K_iT_se(k) u(k)=u(k−1)+Δu(k)=u(k−1)+KP​∗(e(k)−e(k−1))+Ki​Ts​e(k)
可得
u(k−1)=u(k−2)+Δu(k−1)=u(k−2)+KP∗(e(k−1)−e(k−2))+KiTse(k−1)u(k-1)=u(k-2)+\Delta u(k-1)=u(k-2)+K_P*(e(k-1)-e(k-2))+K_iT_se(k-1) u(k−1)=u(k−2)+Δu(k−1)=u(k−2)+KP​∗(e(k−1)−e(k−2))+Ki​Ts​e(k−1)
代入上式即可约去e(k−1)e(k-1)e(k−1)项,不断迭代,由于e(0)=0e(0)=0e(0)=0,可发现其最终结果与位置式PI的表达式一致,也即两种PI算法完全相同(未超出限幅值的前提下)
因此,可以理解为无论用增量叠加的方式来计算位置式PI,还是直接计算,结果都是相同的。两者唯一的区别就是位置式PI需要同时设置积分限幅和输出限幅,而增量式PI只需输出限幅。 增量式的好处就是启动时和状态突然发生变化时不会产生突变,其控制效果与位置式PI基本相同。

3 如何在硬件中实现积分器

如何实现一个积分器(I)?

​ 创建一个加法器是最简单的形式,PI环节如上述框图描述所示。Z-1代表延迟块,T代表采样周期。
Out(x)=Out(x−1)+In(x)∗TOut(x) = Out(x-1) + In(x)*T Out(x)=Out(x−1)+In(x)∗T
​ 新输出值 = 旧输出值 + 输入*采样周期

//C语言实现
Out += In*T;

4、FPGA的硬件实现

话不多说,直接贴代码

代码简单易懂 相信各位聪明的小伙伴一看就能看懂

`timescale 1 ns/1 ns//增量式 PI
//仿真验证通过版本
// 至于k_p k_i
module pid_controller_delta #(parameter   logic  [23:0] k_p=24'd30,   //kPparameter   logic  [23:0] k_i=24'd2        //Ki
)(input  wire signed [15:0] i_real,//实际电流值input  wire signed [15:0] i_aim, //输入给定电流值input  wire                   clk,input  wire                     rstn,input  wire                    pi_en,  //park变换是否完成的信号,高定平即完成park变换output wire  signed [15:0] u_out, //输出电压值 u_alpha U_betaoutput reg                   o_en    //PI 结束信号);reg signed [31:0] error_1,error_2,delta_error;//误差值 error_1为上一时刻的误差值,error_2为当前的误差值reg signed [31:0] multipy_p,multipy_i,multipy_i1,multipy_i2;          //分别代表delta_u两部分的乘积reg signed [31:0] u_out_temp,delta_u;            //寄存上一时刻的输出值,delta_u代表输出的增量reg                     en_s1,en_s2,en_s3,en_s4,en_s5; assign   u_out = u_out_temp[15:0];  function automatic logic signed [31:0] protect_add(input logic signed [31:0] a, input logic signed [31:0] b);automatic logic signed [32:0] y;y = $signed({a[31],a})+$signed({b[31],b});  //积分限幅//积分限幅if(       y  >  $signed(33'h7fffffff)  )//return          $signed(32'h7fffffff);else if(  y  < -$signed(32'h7fffffff)   )return         -$signed(32'h7fffffff);elsereturn       $signed(y[31:0]);endfunction function automatic logic signed [31:0] protect_mul(input logic signed [31:0] a, input logic signed [24:0] b);automatic logic signed [57:0] y;y = a * b;  //积分限幅//积分限幅if(       y  >  $signed(57'h7fffffff)  )//return         $signed(32'h7fffffff);else if(  y  < -$signed(57'h7fffffff)   )return         -$signed(32'h7fffffff);elsereturn       $signed(y[31:0]);endfunction function automatic logic signed [31:0] protect_subtract(input logic signed [31:0] a, input logic signed [31:0] b);automatic logic signed [32:0] y;y = $signed({a[31],a}) - $signed({b[31],b});//if(              y  >  $signed(33'h7fffffff)  )return        $signed(32'h7fffffff);else if (   y  < -$signed(32'h7fffffff)  )return               -$signed(32'h7fffffff);else return               $signed(y[31:0]);endfunction// plpeline 1  计算e(k)always@(posedge clk or negedge rstn)if(~rstn) beginen_s1   <= 1'b0;error_1 <= 0;end else beginen_s1 <= pi_en;if(pi_en) beginerror_1 <=  $signed({{16{i_aim[15]}},i_aim}) - $signed({{16{i_real[15]}},i_real}) ;endend//pipeline 2 计算e(k-1)always@(posedge clk or negedge rstn)if(~rstn) beginen_s2   <= 1'b0;error_2 <= 0;endelse beginen_s2 <= en_s1;if(en_s1) beginerror_2 <= error_1;  //e(k-1)multipy_i <= protect_mul(error_1,k_i);end endalways@(posedge clk or negedge rstn)if(~rstn) beginen_s3 <= 1'b0;multipy_i1 <= 0;delta_error <= 0;endelse beginen_s3 <= en_s2;if(en_s2) beginmultipy_i1 <= multipy_i;delta_error <= protect_subtract(error_1,error_2);end         end     always@(posedge clk or negedge rstn)if(~rstn) beginen_s4 <= 1'b0;multipy_i2 <= 0;multipy_p <=0;endelse beginen_s4 <= en_s3;if(en_s3) beginmultipy_i2 <= multipy_i1;multipy_p  <= protect_mul(delta_error,k_p);endendalways@(posedge clk or negedge rstn)if(~rstn) beginen_s5 <= 1'b0;delta_u <= 0;endelse beginen_s5 <= en_s4;if(en_s4) begindelta_u <= protect_add(multipy_i2,multipy_p);endendalways@(posedge clk or negedge rstn)if(~rstn) begino_en <= 1'b0;u_out_temp <= 0;end else begino_en <= en_s5;if(en_s5) beginu_out_temp = protect_add(u_out_temp,delta_u);endend
endmodule

5、仿真波形

i_aim 给定值是350 实际值是调节后的曲线,从图中可以看出,PI调节可以快速达到闭环,并进入稳态。

如果感觉博主的博客写的还可以的话,欢迎一键三连,点个关注不迷路哦~

PI闭环的FPGA实现相关推荐

  1. FPGA实现PI控制

    目录 1 pid的基本原理 2 FPGA实现 3 联合仿真 1 pid的基本原理 PID控制器(比例-积分-微分控制器),由比例单元(Proportional).积分单元(Integral)和微分单元 ...

  2. linux fpga 开发板,香蕉派BPI-F2S ,四核Linux工业级应用的开源硬件开发板,FPGA教学套装...

    香蕉派BPI-F2S 是 香蕉派团队 and 凌阳科技首次合作开发的一款工业级应用的开发板, 使用SP7021芯片设计.具有高性能,低功耗的特点; 内嵌 Linux Embed 系统,适合于语音图像处 ...

  3. 番茄的随笔7:从PI和PR的传递函数波特图分析参数的影响

    1. 概述 本文从PI和PR算法的传递函数波特图出发,分析两种控制方法的特性和参数设置. 2. PI算法 PID算法即比例积分微分控制算法,其传递函数为: 实际应用时,PID算法可以只采用一个或两个环 ...

  4. 永磁同步电机FOC控制之坐标变换:Clarke,Park,IPark,IClarke及算法实现流程

    FOC坐标变换 01.坐标变换与坐标系 abc三相静止坐标系(3s坐标系): αβ两相静止坐标系(2s坐标系): dq两相旋转坐标系(2r坐标系): 02.Clarke变换及其逆变换: 03.Park ...

  5. 智能车竞赛技术报告 | 节能信标组 - 兰州交通大学 - 先锋队

    简 介: 本文以第十六届全国大学生智能车大赛为背景,介绍了兰州交通大学节能信标组在比赛中的实现方案.本次比赛采用了3D打印的自制车模,主控芯片采用了英飞凌的TC264芯片,软件平台采用的IAR.本文中 ...

  6. 永磁同步电机位置检测学习笔记

    传感器位置检测法 编码器.旋转变压器和霍尔是常用的检测旋转电机转子位置的传感器.虽然目前无位置传感器运行研究的人很多,但是不影响研究位置传感器,因为在高精度控制的场合下,是需要位置传感器来保证控制精度 ...

  7. 交流异步电机调速系统仿真 三相异步电机调压调速系统 matlab

    交流异步电机调速系统仿真 三相异步电机调压调速系统 matlab.simulink仿真 PI闭环 晶闸管触发 matlab simulink 仿真 有详细的文档说明,模型运行无问题

  8. 无刷电机驱动复习--智能车竞赛极速越野组复盘(1)

    本篇博文的主要目的一方面是为我之后的答辩提供参考,另一方面是为现在正在参加智能车竞赛的同学们提供一个参考.首先先对无刷电机进行介绍,然后会讲一讲具体的驱动原理,最后讲一讲其他的驱动方式.语言方面可能不 ...

  9. pi/4dqpsk的matlab及FPGA仿真

    基于八相偏移调制的原理,本着资料稀少的原则,分享一下自己的经验. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % PIQPSKMODEM使用清单 % 卷积编码/编 ...

  10. PMSM永磁同步电机PI双闭环SVPWM矢量控制 本模型包括DC直流电源、逆变桥、PMSM、park变换、clark变换、SVPWM、PI控制器、信号测量等单元模块

    PMSM永磁同步电机PI双闭环SVPWM矢量控制 Matlab/Simulink仿真模型(成品) 1.本模型包括DC直流电源.逆变桥.PMSM.park变换.clark变换.SVPWM.PI控制器.信 ...

最新文章

  1. Python基础(1) - 初识Python
  2. MySQL数据库如何杀死会话_如何彻底杀掉不良用户会话
  3. 清理disuz垃圾用户信息SQL语句
  4. CentOS7中关闭selinux
  5. 深入理解 Linux的 I/O 系统
  6. port wifi to ICS(4.0.3)
  7. 学校计算机二级模拟上机能看分数吗,全国计算机二级考试机试考完怎么储存的...
  8. 伤钱伤感情 10件不能和亲戚一起干的事儿
  9. ffmpeg实现摄像头拉流_干货 | 速看!乐橙K32Famp;K36F摄像头全彩夜视功能的不同点全在这了!...
  10. 腾讯广告算法大赛 | 初赛第一名心得分享
  11. WebRTC 将一统实时音视频天下?
  12. CDOJ 1157 数列(seq) 分块+线段树
  13. 推荐:年度巨献:《Ubuntu桌面生存指南》(作者:ghosert)
  14. Mongo 创建数据库
  15. excel如何去重统计户数_Excel如何去重,然后统计数据?_excel提取数据并去重
  16. python3 模拟登录网站
  17. IE无法打开网页的问题
  18. 7代cpu能装虚拟xp系统吗_小米手机最新系统MIUI 11 推荐,附带小米刷机资源
  19. JNDI注入学习(看不懂直接喷,别忍着!)
  20. windows系统下自定义图标

热门文章

  1. 华为HCIP认证考试简介
  2. python用turtle画一个苹果
  3. 数据包络分析法(DEA)_2
  4. CS224n(2019):Assignment2 参考答案
  5. 实用网站合集(持续更新ing)
  6. 【自然语言处理】论述自然语言处理的技术范畴
  7. AXure交互设计指南
  8. java对象转map_java中实现map与对象相互转换的几种实现
  9. 无人机设计过程中的计算和假设
  10. 【代码审计】YUNUCMS_v1.0.6 后台代码执行漏洞分析