一乐电子

 找回密码
 请使用微信账号登录和注册会员

QQ登录

只需一步,快速开始

微信扫码登录

搜索
查看: 2683|回复: 6

PID C语言

[复制链接]
发表于 2014-3-19 21:59 | 显示全部楼层 |阅读模式
PID算法(c 语言)
% V5 i" M0 b. n. n5 ~1 {#include <stdio.h>
) D0 g+ f/ t1 V0 W+ I; ~! L0 f3 ]#include<math.h>
; u& A7 `8 X$ L3 [* M//定义PID 的结构体
. j& q3 s! }/ G& i" N3 {struct _pid ! X- q+ d0 _! l( r& T9 c
{ . R  [) k( K' p" Z6 w) u
int pv; //integer that contains the process value 过, L* z5 p9 {/ }7 D8 C. p
程量 9 e. _- l' h1 K0 ]- _
int sp; //*integer that contains the set point   设8 }$ q5 u3 r8 Q! K$ J, K
定值
! f4 D* b2 m+ Sfloat integral; // 积分值 -- 偏差累计值
5 H1 T, ], @) a$ u6 H9 s/ _* gfloat pgain; 1 i& n! G) q: f  t0 G4 {! S0 D' N# b
float igain; + O7 j9 v5 f2 C9 `8 m
float dgain; ; O5 B$ E  k( c$ g
int deadband;    //死区
/ y- w# \7 e* @- ]/ e$ Y5 Qint last_error; . Z1 V6 G, C, U) y/ T1 S, `
}; : Z" M2 J5 S8 N9 h, G

- X" E+ p; D4 d) j; [struct _pid wARM,*pid; 2 U9 K: a' F" d" S/ X
int process_point, set_point,dead_band; float p_gain, i_gain, d_gain,
7 m1 u, ^6 v6 C. C0 `8 ?9 |integral_val,new_integ;; ) a# P$ n; a+ v2 W: ^0 i5 v- a9 Z. y

( @* a; V$ p0 M1 v+ H- _//------------------------
8 t# E! S) n0 B/ q6 }---------------------- 7 C7 H  I) S2 J2 k* f* B$ p
pid_init DESCRIPTION This function initializes the
1 Y( s! l" g& l. Q7 ipointers  in  the  _pid  structure  to  the  process  variable 4 L, s5 v9 @( j% K1 L
and the setpoint. *pv and *sp are integer pointers.
! }) x' l( ?: u3 I//------------------------
$ ?, x1 ]% M3 v* R4 Q: ^7 ]---------------------- 8 @8 k# D& R$ f! G  n7 \  Y! @

4 C& v; V; a5 [% avoid pid_init(struct _pid *warm, int process_point,
* J- t1 t0 g3 o; O6 H8 zint set_point) & ]2 s: {  O; f9 y2 ~. E2 O
{ % j/ j% m" P# z: V  G. U
struct _pid *pid; 9 e  I& Q6 M& j
pid = warm; 6 H, u, ?7 C5 Q2 q
pid->pv = process_point; ; M$ [  u2 A9 z, ~2 j9 F$ d% m$ E/ y
pid->sp = set_point;
+ C2 Z1 J* R' L4 {; h4 _} 9 f0 [$ Y; T0 R# W1 z' Q

$ D$ `0 {; M& u# n* L2 g4 R3 L//------------------------& x1 `7 X$ M! K' J# ^2 l
----------------------pid_tune DESCRIPTION Sets the proportional gain ' j$ A" w- J, `7 m! Y
(p_gain), integral gain (i_gain),
/ B4 s% J) ]3 ^' S! Hderivitive  gain  (d_gain),  and  the  dead  band  (dead_band) ( m% ~0 V' ]6 L' r+ G$ X, K/ E
of a pid control structure _pid.  
5 P" R" B0 @: m$ ]1 {/ p( M9 m  a- o4 n, H, S2 a
设定PID参数 ---- P,I,D,死区 % U! `! n+ X( a2 I
//------------------------" q7 i  ]  Q, Y$ o' w5 Q
----------------------
" @6 d, K- I- @$ F# q5 ^
: e( b" e/ c' [7 V  i( ovoid pid_tune(struct _pid *pid, float p_gain, float / N4 H; Y. U, g" B' ^
i_gain, float d_gain, int dead_band) 3 w# p; x! e! T  g% _
{ 9 t4 P- r7 K: g, j4 F( V% u4 h
pid->pgain = p_gain; ) u3 f9 N- x/ U6 C, ]6 d
pid->igain = i_gain; , ^% j! Y9 s* X
pid->dgain = d_gain; . k3 L9 ?' L- ?, B( r/ [) ]
pid->deadband = dead_band; ) R5 V: X: k- L; l
pid->integral= integral_val; 9 e( u7 Y4 \  ]6 X" ^( r
pid->last_error=0; / O5 Y: r- ^. l. e' h7 I
} ! U, T+ b5 C9 }8 p% C! x4 Q

& i# I' D( r$ A% p8 |//------------------------
. p8 l) D3 L; m4 @9 n---------------------- pid_setinteg DESCRIPTION Set a new value for the : p8 l* U' C3 c3 l. ~5 V
integral term of the pid equation. 5 r& [% N3 |+ U, P
This is useful for setting the initial output of the
# O6 A( ^8 `  I5 ipid controller at start up.
" Y3 O7 c# B* w/ n2 o. d4 O* \! A% w7 M& {2 o8 X
设定输出初始值 % J$ y5 G) U2 U  b: U$ O
//------------------------" L5 V0 V* g2 y6 b5 o; b- j' i
---------------------- & O. J; h: h  S. h- G

( e' J- J: v6 x/ a; Q' e2 N9 p- ~void pid_setinteg(struct _pid *pid,float new_integ)
6 ~' l- Y& y* b4 z( h9 Y  {{
# W- Z0 n& s2 n, a+ }& ?pid->integral = new_integ;
) q! F6 l' l, c- v6 Vpid->last_error = 0; : n* k9 q+ ~2 k" {: Z
} & |, }- C" d  R. _9 Q) H% o
" U2 W. H; w6 r
//------------------------
! ]: ?! q$ M8 S/ ]4 f----------------------
1 t. c& q1 z; w4 L' ]9 jpid_bumpless DESCRIPTION Bumpless transfer ; ?+ q8 v3 {0 O# G9 ]
algorithim. % k% k' T2 |  l. v! c: w& W7 X' j
When suddenly changing setpoints, or when restarting
! o2 r! `( S8 N$ W0 Dthe PID equation after an extended pause, - f. _+ }9 ]( |% P; W
the derivative of the equation can cause a bump in the controller output. This function will help smooth out   e: N. V6 O8 \" ?
that bump.
1 C2 u& B! y7 \9 [1 ~The process value in *pv should be the updated just , s- |, D+ B; g- T+ C
before this function is used. * G9 n# _6 V2 D! J; N

0 u' s, k3 f9 l% H1 k  npid_bumpless 实现无扰切换
6 S. n/ f% A. j" t' A9 m# _当突然改变设定值时,或重新启动后,将引起扰动输出。这' J$ {8 T1 R! F2 Z+ T: D& t
个函数将能实现平顺扰动, 在调用该函数之前需要先更新 PV值 # \1 B) u" N# N; H
//------------------------! k# D. Y6 F  ?( F) ]
---------------------- 9 x% }: ^2 R  h8 @

2 i5 A) S2 X+ Qvoid pid_bumpless(struct _pid *pid) ; q0 t/ X/ |3 d' I7 B& J5 X
{ / G) _/ q: O8 h$ V3 o1 `
pid->last_error = (pid->sp)-(pid->pv);  //设定值与反馈值偏差 % D  R# r. w: A2 r- W( @3 e
} 3 S. \0 B7 b1 R- L

) J( k# y- w) j" F4 w//------------------------
: S3 i5 e, h1 I& b( g4 A+ q2 u---------------------- ) m6 r1 n) H/ i
pid_calc  DESCRIPTION  Performs  PID  calculations  for  the ! P. S  d, I' L/ X: @/ c
_pid structure *a. This function uses the positional form of the pid
; a- x, u* U# @9 c7 ~equation, and incorporates an integral windup 9 ]4 c7 U" \7 C) R
prevention algorithim. 7 n+ S" d/ m+ `) y8 l, D
Rectangular  integration  is  used,  so  this  function  must
+ ~' e6 F: D- J5 xbe repeated on a consistent time basis for accurate % {9 @: i" `9 P2 x3 {
control. ; ~9 E; H- @6 F/ C) b
RETURN VALUE The new output value for the pid loop. 1 m3 X0 D) }/ `
USAGE #include "control.h"
0 s2 S1 k9 z! s+ H2 V" `5 o7 k本函数使用位置式PID计算方式,并且采取了积分饱和限制运算 ) y. P5 O: X+ H
PID计算 8 d4 Q: f7 x/ q4 W: b
//------------------------5 u! E* [  A* K& h3 @
---------------------- 3 i& a! W$ r" R; p; S: G

1 k$ l) E! a' ~9 [) Y, |! l9 Ofloat pid_calc(struct _pid *pid)
. e! }; ^: y5 D  S" [+ M0 E( p; @5 O
int err; % N$ ^4 F# l  |# u6 p
float pterm, dterm, result, ferror;
! _1 E' L  U- f+ U3 c0 i- ]7 X
. C" C) a3 h- r! E// 计算偏差 4 U) G5 R% }) D
err = (pid->sp) - (pid->pv);
! e% L9 s  _6 o. n, ?  ` // 判断是否大于死区
/ a- ^7 Y+ q" d6 |! Y. Z4 `if (abs(err) > pid->deadband)
# O. s$ a5 Q( t% ~2 s{
" `8 N& {9 y% h6 @( x/ gferror = (float) err;   //do integer to float
$ C5 S4 c+ I4 v# Uconversion only once 数据类型转换
4 U  X/ }- l6 m% P/ M8 N' ~& n8 g: B1 J- @0 K% v
// 比例项 + L+ Y3 z2 l; H1 m4 f/ U
pterm = pid->pgain * ferror; + I1 y4 {& G4 q" y/ y" w
! s! u6 ~! W( O: i) N
if (pterm > 100 || pterm < -100) 7 u! p' b5 J" T4 K
{ : G0 a' P% @' n/ _- o% y* z( c
pid->integral = 0.0;
+ @7 ], \% Z' ?2 ]' ?4 W} ' y" ]6 m# L" w$ P, G
else
+ F3 Z+ H* m  P0 N9 o; S{
2 @" `5 Y) h4 [$ `0 |% u// 积分项 7 b( W) U, p- W$ O* ]" b
pid->integral += pid->igain * ferror; 8 I$ w' d/ b/ I' L* k  f0 E0 W3 p+ I
# o- t( H6 y: ^! b
// 输出为0--100%
) Y; G4 H5 B) I& T6 p1 ], w// 如果计算结果大于100,则等于100
4 U, ]" \: l( v9 v1 q9 ?5 k5 jif (pid->integral > 100.0) 0 R- Y. T4 o& X* l$ j
{ pid->integral = 100.0;
/ R! \/ R' A& v: I- Y} " [# R' \; s2 ~; s5 _8 F5 E
// 如果计算结果小于0.0,则等于0 4 m9 \" Y- \; h
else if (pid->integral < 0.0)
2 s6 H6 \- b  N% T) `+ o5 E1 Rpid->integral = 0.0; ) K; Z8 F) _: u' A1 g
' u$ r% t! o5 [
}
4 U0 ?- [; X: j9 A6 S4 _# M" Z& m8 z; E& a! P
// 微分项 & g$ z: t4 Y: s& e
dterm  =  ((float)(err  -  pid->last_error))  *  pid->dgain; * c1 V6 H) I& i) x+ J. @

2 D- W0 k7 X9 N9 S. ?result = pterm + pid->integral + dterm;
8 o' E5 P6 n! {: K1 ]# K} 9 f/ F! q2 a0 L' w8 K
else 8 d8 S+ d% H- X
result = pid->integral; // 在死区范围内,保持现有输出
4 _  C, u" C7 ]  s. W1 R, w* ~1 l! f
9 Q% G1 L: v5 Q/ t% g' r  a// 保存上次偏差 % ^& L* b" Z+ X6 T" N: N
pid->last_error = err;
) x7 H- B2 N- }* r6 m
# p; T' ^( M: }. G/ U! T// 输出PID值(0-100)
4 w. L, w# ~, w3 |3 rreturn (result); }
, I" d0 X  t' M& ?* k2 V. q
, l+ p$ V. o, V7 ?" X//------------------------( Q- O9 @* Q5 g' I; w
---------------------- 9 b5 D; F' s) U' @! `
void main(void)
3 D8 a0 K% u' m! C5 [5 c! y{
3 Z1 ]' W% _- Q* I/ Gfloat display_value; % s" h0 b( q0 E! H  a7 p
int count=0; 6 g6 X: W* g' [  x
pid = &warm; 1 |( O7 s4 [9 Q! R, @- d- M# K
; v) z) Y( V( A7 W2 w( x0 `; J
// printf("Enter the values of Process point, Set
* s; R. L. K2 \; K" [point, P gain, I gain, D gain \n"); ' ?& j- A- @( H& x, o4 L" z" x. d
// scanf("%d%d%f%f%f", &process_point, &set_point,
( v; [; T6 q- q- M1 N&p_gain, &i_gain, &d_gain);
" |+ B$ a( `% ]$ A/ c7 Y& o; S* a) p* X4 X9 a2 G. q
// 初始化参数 7 h8 q" x' Z9 D; g! K' y( K5 s$ j+ d
process_point = 30; 1 t- F4 n3 x& E9 U/ u
set_point = 40;
1 t1 c3 {  L& S( Tp_gain = (float)(5.2); ' l  T# p" j0 }8 t% y. v8 @
i_gain = (float)(0.77); 0 |! p9 d' a2 W% r& q0 @! M" {
d_gain = (float)(0.18); 9 Y8 m/ S- ~& r4 d( v/ ?, U
dead_band = 2;  
2 Y3 t1 J2 w4 ^, j8 Q2 X, xintegral_val =(float)(0.01); 6 b7 D7 `3 `' w1 a, g( z

6 Z8 }( x! d) z6 r4 J9 d+ b% K/ z2 eprintf("The  values  of  Process  point,  Set  point,  P  gain, - I/ P. K0 I6 A% t4 Y9 X
I gain, D gain \n"); ! F2 B2 [# u1 b" K9 G' }: T
printf(" %6d %6d %4f %4f %4f\n", process_point, % P- s4 o, |0 w  y" G* L
set_point, p_gain, i_gain, d_gain);
1 m  A' k( f8 m7 b6 ?% Vprintf("Enter the values of Process point\n");
! `- q. [- D: k  Pwhile(count<=20)
5 w+ I3 H, W2 D. L{ & y* g) o! E  o/ ?0 r
scanf("%d",&process_point); " A* ^& a. X7 a2 e- V

( j5 f8 v- J0 P* V( P( J// 设定PV,SP 值
7 x- p- ]4 i/ s: b$ Apid_init(&warm, process_point, set_point); 3 u$ }4 w  ^( X
. h3 l9 E/ r. m% p
// 初始化PID 参数值 / \' C( H3 d7 q6 |
pid_tune(&warm, p_gain,i_gain,d_gain,dead_band);
/ i! o/ i! R- k) l3 V$ R; _0 A" A# e* M1 O- J
// 初始化PID 输出值
$ ?" t( w- G* K) S# ppid_setinteg(&warm,0.0); * d* S) O. k- ~" P4 D4 V, P/ ]
//pid_setinteg(&warm,30.0);
* V6 C6 r# E& h4 l- R7 A2 H) m6 V //Get input value for process point 4 j8 Y# R. T6 L' g2 r
pid_bumpless(&warm); ) i- F9 J( h" l$ O0 @

8 N8 K) t6 @% c& B3 Y// how to display output / r) W1 v  w) x6 w
display_value = pid_calc(&warm);
6 ?, j. C+ F; h( R( k7 ~. U3 Z/ A, [5 c
printf("%f\n", display_value);   p; A* u9 \, |' Z; O! v
//printf("\n%f%f%f%f",warm.pv,warm.sp,warm.igain,wa3 P5 u5 _8 Y8 L
rm.dgain);
* T9 a* u" F2 m5 {7 s! `+ Z( i) j, \2 h4 Q" D! }0 s% D
count++;
; M% U4 U' z8 F' b! |$ @}
" B  w; N0 Y9 w( L* f. x}8 _" E/ M2 _8 r
7 x" F# n& j4 A9 o2 _# V
发表于 2014-3-19 22:11 | 显示全部楼层
版主,这个更是针对什么设备的?是不是要根据不同的设备来制定不同的PID算法?比如驱动两个电炉,一个功率1000w,另一个2000w,在相同的控制温度下,同一个PID处理程序,温度的变化曲线就相差很大。
回复

使用道具 举报

 楼主| 发表于 2014-3-19 22:13 | 显示全部楼层
在电子数字计算机直接数字控制系统中,PID控制器是通过计算机PID控制算法程序实现的。计算机直接数字控制系统大多数是采样-数据控制系统。进入计算机的连续-时间信号,必须经过采样和整量化后,变成数字量,方能进入计算机的存贮器和寄存器,而在数字计算机中的计算和处理,不论是积分还是微分,只能用数值计算去逼近。 在数字计算机中,PID控制规律的实现,也必须用数值逼近的方法。当采样周期相当短时,用求和代替积分,用差商代替微商,使PID算法离散化,将描述连续-时间PID算法的微分方程,变为描述离散-时间PID算法的差分方程。算法中,为了求和,必须将系统偏差的全部过去值e(j)(j=1,2,3,... ,k)都存储起来。这种算法得出控制量的全量输出u(k),是控制量的绝对数值。在控制系统中,这种控制量确定了执行机构的位置,例如在阀门控制中,这种算法的输出对应了阀门的位置(开度)。所以,将这种算法称为“位置算法”。当执行机构需要的不是控制量的绝对值,而是控制量的增量(例如去驱动步进电动机)时,需要用PID的“增量算法”。已看不出是PID的表达式了,也看不出P、I、D作用的直接关系,只表示了各次误差量对控制作用的影响。数字增量式PID算法,只要贮存最近的三个误差采样值e(k)、e(k-1)、e(k-2)就足够了。
5 V1 G( b! S6 t: v/ q- k
回复

使用道具 举报

 楼主| 发表于 2014-3-19 22:15 | 显示全部楼层
好多是在网上找的,我也在学习当中。
回复

使用道具 举报

发表于 2014-3-19 22:18 | 显示全部楼层
保留,这个应该好好理解
回复

使用道具 举报

发表于 2014-3-20 09:29 | 显示全部楼层
8055 发表于 2014-3-19 22:11
7 H4 h0 E' @% M2 `) \9 u版主,这个更是针对什么设备的?是不是要根据不同的设备来制定不同的PID算法?比如驱动两个电炉,一个功率1 ...

" g; {, a6 z5 x5 g" M" w用同一个PID算法没问题,但要处理好PID参数,比如热容量差不多的情况下,两个设备的P参数要差一倍左右。
0 l) L- q+ t8 Z! l
回复

使用道具 举报

发表于 2014-3-20 10:26 | 显示全部楼层
收藏学习中、、、
回复

使用道具 举报

本版积分规则

QQ|一淘宝店|手机版|商店|一乐电子 ( 粤ICP备09076165号 ) 公安备案粤公网安备 44522102000183号

GMT+8, 2025-8-20 12:10 , Processed in 0.034565 second(s), 24 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表