版主
主题
回帖0
积分10609
阅读权限200
注册时间2008-11-22
最后登录1970-1-1
在线时间 小时
|
PID算法(c 语言)( `5 v7 {, D" [: L; c* c
#include <stdio.h> " D$ C' L/ r: n$ m
#include<math.h>
o+ X/ {2 B# }! D5 k' |//定义PID 的结构体 # W0 ~2 p0 K2 y) ^+ J# x
struct _pid
5 a }* B8 j5 J! d# z{ 3 ?5 |; D" m# V% h
int pv; //integer that contains the process value 过0 R0 h: P2 A* v
程量 ; ?3 S9 [7 b4 h" [% A, ~, c
int sp; //*integer that contains the set point 设
4 w0 k+ d# l; W& ]8 |定值
$ x) C( C$ N$ M3 n* w8 bfloat integral; // 积分值 -- 偏差累计值
3 y L8 V4 Z( j% ?6 y/ D! Ufloat pgain;
7 \5 C9 K6 S1 Q* R8 v4 R. jfloat igain;
' {4 [, t9 U# o* L3 D! S/ @float dgain; * C7 s8 K E2 s4 l% v* Z% {! M
int deadband; //死区 ) C3 k5 \9 \/ J7 d- E2 ~# g9 ?9 ~
int last_error; 5 {% q3 q s* w# h" d5 H
};
# ?9 H/ v6 `8 _. k6 K0 r0 B! Z! Q1 r3 _' g
struct _pid warm,*pid; 4 g2 w w5 ?0 W. Q e3 o: A$ q
int process_point, set_point,dead_band; float p_gain, i_gain, d_gain, 1 B$ {' [) B( \* c! T
integral_val,new_integ;;
: e: M4 w7 m3 D$ k9 n/ U0 v" [& ` L8 Q, I" @0 p8 C9 B
//------------------------/ x0 y0 p2 y1 p( G; ~: V
----------------------
" V; E4 J3 V2 D* Q0 @4 Ipid_init DESCRIPTION This function initializes the $ i6 Y1 |9 E) B% [( f5 J! L9 |9 ~ f
pointers in the _pid structure to the process variable 5 k* j1 P, E. w O) x& f
and the setpoint. *pv and *sp are integer pointers.
2 j% w# f8 \% L. |- M! n//------------------------6 l! y5 K. P5 q2 o- i. `8 K8 W+ E
---------------------- 3 q5 ~* h L7 v+ P, F+ p, ^/ |% z( i
- L& @: E3 U6 H! m7 x3 s: [9 L0 evoid pid_init(struct _pid *warm, int process_point,
1 v3 X7 l* t5 Z* z9 kint set_point) % y1 Y8 Z) {+ c# ?( P3 z! f4 @
{
r& O0 t2 X: @+ S3 R E+ nstruct _pid *pid; 2 q, g' a8 H+ e4 u6 f/ O
pid = warm;
: K/ Y Q( A) V7 ~. N2 d; zpid->pv = process_point;
1 f) t. [0 u. y: p1 @/ d1 ]6 vpid->sp = set_point;
9 T9 x( N+ e# ~2 V3 T}
+ k5 ?* |& o+ g6 c" h8 k( K$ N: m" P' ]9 Z
//------------------------! k. g* j) j+ Y9 k* x
----------------------pid_tune DESCRIPTION Sets the proportional gain 1 o4 g5 b' u9 E8 F& _7 n" x
(p_gain), integral gain (i_gain), % d5 E* y4 P" V4 m' s2 f
derivitive gain (d_gain), and the dead band (dead_band) 8 [5 [; y; ]/ K( d9 G) J2 \6 ?! {0 t
of a pid control structure _pid. 0 V" `/ h! a# Y5 {7 z- T: u' c; R
' C" M3 v l2 }8 F, _+ W设定PID参数 ---- P,I,D,死区 6 x1 h0 K# {" A/ \
//------------------------
+ t! @ N& V% I) _5 M----------------------
1 R, \" c& w+ N* v2 L+ t2 f$ p/ V$ J3 R) h. `
void pid_tune(struct _pid *pid, float p_gain, float
% V2 Q* @5 o4 b( Oi_gain, float d_gain, int dead_band)
4 W% K0 m/ H- }2 S3 d{
( }$ d8 I6 y% E6 a) {pid->pgain = p_gain; & p/ Q; h0 T% _. n
pid->igain = i_gain; / |7 \) n% `0 B7 }, Z7 `
pid->dgain = d_gain; $ u! q% B1 a. d4 w+ S8 V6 z
pid->deadband = dead_band;
; D, f' \( L8 ^6 P6 I7 `pid->integral= integral_val; 0 v- I- h7 @2 K' E$ p
pid->last_error=0; 8 ]/ |2 k. v0 @9 Q) V( c
}
+ ^; |- k {) B9 m6 ^9 c3 O( o4 h' q# H; W6 V3 K6 }
//------------------------
/ ]% w! }' ?. p& y4 \---------------------- pid_setinteg DESCRIPTION Set a new value for the
, b0 r! M/ F( Dintegral term of the pid equation. 8 c) d9 j3 v- Q9 g% t2 L; I3 u* ]4 n
This is useful for setting the initial output of the 7 ]+ s; ^; w5 B% N6 ~
pid controller at start up.
- E. ~ w- d0 X: J r' ?7 z* {8 J
5 J4 \& [7 P, m$ C: K& W设定输出初始值
, e# W% \: R q//------------------------' [: \3 z R! ~6 H( l
----------------------
$ E1 h; T/ Q% g) Z- w' l& w+ |! V6 i9 J
void pid_setinteg(struct _pid *pid,float new_integ) ! z& ]! T& z; Q! j& C* G% U
{ 7 v- i1 h& H0 G
pid->integral = new_integ;
. M" h) X2 \; mpid->last_error = 0; 8 |8 K4 X9 w/ A8 u# S4 M
} 6 Z" Y) L& I8 r" s, v) I3 Q
5 z0 |! e) A# s) R
//------------------------5 ]) R1 i6 F4 E: n1 J( k; b
----------------------
; }+ B# e: R+ K3 z( A& n; v& z" n2 \+ V0 \pid_bumpless DESCRIPTION Bumpless transfer F, q3 K5 Z, u' Y
algorithim.
2 L" G9 q, w& h+ P* W1 EWhen suddenly changing setpoints, or when restarting 8 L7 T4 d. ?$ r4 I* i
the PID equation after an extended pause,
+ q( ^) m5 X+ u- M/ dthe derivative of the equation can cause a bump in the controller output. This function will help smooth out
" T3 T! r. v8 t: s; ^that bump. 3 s4 A- R F, h. b3 y% }; D* |1 t
The process value in *pv should be the updated just % u* ?6 {( c5 O8 c1 F2 e
before this function is used. 7 \% w% I ~ z; t$ A8 W
8 c9 `4 ]/ n0 {: Q+ a$ k* U& Zpid_bumpless 实现无扰切换 $ f" f w' g9 N9 y7 K
当突然改变设定值时,或重新启动后,将引起扰动输出。这- q" R. l9 u5 g+ J
个函数将能实现平顺扰动, 在调用该函数之前需要先更新 PV值
' G0 p5 c/ q9 W1 A0 N//------------------------ B9 r7 R2 ]) Q& o x3 ]
----------------------
4 Y% h7 I+ ^. M0 a7 r& ^# Y) M1 B/ h7 Z# |, [/ J5 W. i
void pid_bumpless(struct _pid *pid)
% U+ L8 R+ C& I8 A{ # V& U! [7 n0 w0 M
pid->last_error = (pid->sp)-(pid->pv); //设定值与反馈值偏差
( g/ y2 J0 `7 Q) y$ L} ! u" X$ I1 ? b1 s, s: R/ i
7 l" v: O$ n8 J/ C. w* U//------------------------
+ M& B2 X" N3 y1 U$ P: a----------------------
5 B0 U& ^+ B' j: k; bpid_calc DESCRIPTION Performs PID calculations for the
6 H/ y) K/ ?, }_pid structure *a. This function uses the positional form of the pid + {. D$ N1 f& u) h5 T7 ?" R6 U$ ~
equation, and incorporates an integral windup
( k# d! V' d# F) J. Mprevention algorithim.
! Y X' w) ]$ `: }$ GRectangular integration is used, so this function must 9 U! b% @' N$ s: _) p D9 j
be repeated on a consistent time basis for accurate
. O# H( t; f; i7 ]4 O" vcontrol.
8 B! g( ~$ K) }6 KRETURN VALUE The new output value for the pid loop.
6 x& v$ x- a- z, X. XUSAGE #include "control.h" 1 b# p7 Q$ l' @* e# b P" M) t
本函数使用位置式PID计算方式,并且采取了积分饱和限制运算 % |% @7 M4 p& L, E3 {2 d, G" O7 C
PID计算 # ]+ |6 d7 X; i3 j
//------------------------
3 \( T. ?6 p* I& v0 r& }----------------------
0 Y, T/ I2 ~8 v6 n
: q/ T( {& L2 w. `1 |2 T1 \. Y5 S/ Cfloat pid_calc(struct _pid *pid) / {& o+ b" b6 S- n$ N+ D m
{·
. `! L& O! a5 ]int err;
' [ M# e' Z# s' i+ G3 Bfloat pterm, dterm, result, ferror;
. u1 q7 m1 T# a
0 B; Z& q( K/ c// 计算偏差
6 ~& C2 t0 v$ y5 I" x: l2 T8 Herr = (pid->sp) - (pid->pv); ) U6 L% ?) c" O$ ^- g7 D0 s
// 判断是否大于死区
' u4 L/ M& H8 U# E$ f# Y0 Vif (abs(err) > pid->deadband) + ^+ n H, }! M, \ O0 P$ o
{ 6 _3 G5 I4 \1 [$ s& V
ferror = (float) err; //do integer to float 1 k, u- a2 J# g- V( [: v
conversion only once 数据类型转换 4 A+ u) g+ h) X
, t0 N/ o) Z: \4 W1 S
// 比例项 , b% J$ X% r& u6 t) B# }
pterm = pid->pgain * ferror;
& o' _) _' D* v' P) `% y" {" @* s8 }! @9 y9 N: m
if (pterm > 100 || pterm < -100) ; V/ z- J: P' f" D$ K0 P5 U7 L
{
$ t* K: {( B1 ?7 T" \6 Ppid->integral = 0.0;
# E' k j9 _' l3 U- _} 3 ?( M# {# D8 q8 _$ E# O. _/ x
else
/ n' Y f! a& _. \; A{
[/ x; L8 H' V1 m, G/ `6 Q// 积分项
- e% ]# G/ `5 X! L3 c; Gpid->integral += pid->igain * ferror;
; d5 j9 l% y8 c3 S: @
; J3 [- g% G: T/ R- I// 输出为0--100%
. _* v# B u$ L% v m$ K5 s7 P// 如果计算结果大于100,则等于100
$ j0 b8 q4 M* _& `% |5 zif (pid->integral > 100.0)
2 P( p. B% v5 p3 {{ pid->integral = 100.0; - i; L! s' g& D! G, v$ b8 ]. Z9 G( f
}
# F0 r; ~ K" j0 _* G* o// 如果计算结果小于0.0,则等于0 7 X9 R& z; t# G$ O
else if (pid->integral < 0.0)
; A5 D. }. ?4 Wpid->integral = 0.0;
, C+ J: ^, Y3 b9 n/ I1 v/ w/ I$ c8 q7 d! ~$ |8 p/ M
} 6 ?; t* j$ }6 X' N) W- t, L
0 [% \9 e- e. @) ~+ ^$ n
// 微分项
! M7 g2 c) s/ pdterm = ((float)(err - pid->last_error)) * pid->dgain;
N# u4 a0 |) E5 F: b# a3 L7 i1 e7 T2 G
U: J7 O$ p+ B) Vresult = pterm + pid->integral + dterm; 9 f" E" s8 }! N, a2 a- D7 o& J) x
} ; h$ |- h! [+ b8 r* }
else
6 o% o! |6 H. Kresult = pid->integral; // 在死区范围内,保持现有输出 ! b$ w) E9 N4 v2 ^& A3 q
) x# h) a# u! ~ Q: D, G// 保存上次偏差 $ a, S7 K( _$ C( y6 m( P8 K: m) c y
pid->last_error = err; ! ?$ K6 { P/ x, J7 e
# U# `" j* i( \! _9 U// 输出PID值(0-100)
9 ]% J( S* C1 u8 |. G) N3 rreturn (result); }
0 M0 |% _+ Y X
) _1 u2 A2 B5 G4 w% X- Q2 n//------------------------
# n; j4 [- }7 w/ l5 O& u---------------------- / J. w a/ }0 H
void main(void) w3 I' J/ ~' }2 b6 M
{
* N/ l, ^# ~1 t! R3 M r; ~float display_value;
/ c3 X% H; I% C: y; w, A# f" Z6 kint count=0; ) Q, \. m: z# o: ?- I$ d( ?
pid = &warm;
0 G# k9 D& X% V7 ?' _! x9 Y7 d* c0 b8 z2 v' [' D7 v
// printf("Enter the values of Process point, Set 5 ?2 s' O1 O9 W
point, P gain, I gain, D gain \n");
2 o4 d3 v/ s# o& `; K, b7 S( V# Z// scanf("%d%d%f%f%f", &process_point, &set_point,
& R; J% @; N7 t) f, v) R&p_gain, &i_gain, &d_gain);
! K1 l/ s5 C2 D, ?9 j
/ C( n" B3 A% O6 N* j$ D* f- ^// 初始化参数
, U/ {% b; p! ?0 uprocess_point = 30; : U! i- L' g5 @$ j: Q
set_point = 40;
& ]3 p/ b' c' e/ M6 U! tp_gain = (float)(5.2); : \. y$ R0 b! M" l& \
i_gain = (float)(0.77); ( o8 N: o/ z% i) U8 V3 Z6 L/ v
d_gain = (float)(0.18);
8 ?, v5 `. B, \& Idead_band = 2; . k5 @9 n! _ v6 ^8 I
integral_val =(float)(0.01); 0 ?. |/ e. s' u& L; @
$ U7 }5 k- C" o* p
printf("The values of Process point, Set point, P gain, # ~! [ A) ~* @0 G- J* x3 _! ~
I gain, D gain \n"); % Z4 c5 j1 a% S! s% z9 C
printf(" %6d %6d %4f %4f %4f\n", process_point,
# I" p6 V- m6 Y% d* U" hset_point, p_gain, i_gain, d_gain);
: l. Z9 Q/ z' N9 _ ^printf("Enter the values of Process point\n");
3 Q2 H3 K& o3 u1 ?: b# D9 Zwhile(count<=20) ) q4 v% S4 \: v' H6 g1 e
{ % G! z- V4 e! K1 j
scanf("%d",&process_point);
$ p" R# U; X" T( i5 p( d' D
/ b6 _7 g* o6 `// 设定PV,SP 值
! |& _) w9 j( q* o X/ Zpid_init(&warm, process_point, set_point); " B2 g1 m$ } G5 S
: x, O: |$ v3 v/ O1 r
// 初始化PID 参数值 . b' e3 b) I/ y/ E
pid_tune(&warm, p_gain,i_gain,d_gain,dead_band);
3 @9 s. F8 e3 |! ^5 _2 t% X
6 H- G+ }+ A% E// 初始化PID 输出值 # [' d5 W7 r* h3 w8 P8 V! V
pid_setinteg(&warm,0.0);
8 S4 }% l- Z7 X, r2 ^+ F//pid_setinteg(&warm,30.0); 3 F5 } X9 p/ r& B0 |& V5 v
//Get input value for process point
. x2 G3 A' G+ F @* {" c# M% \( S- mpid_bumpless(&warm);
* c1 g: Z# _- C* c
& A" E$ A& O! Z% Y" _( B0 y// how to display output
8 }, H9 z# _# |# Kdisplay_value = pid_calc(&warm); $ Z t6 O- o/ B7 o! X, e2 K* K) z
; ~; q% L. n) T+ O$ oprintf("%f\n", display_value);
) P1 [5 a$ d: s) ?0 ~//printf("\n%f%f%f%f",warm.pv,warm.sp,warm.igain,wa% M2 G3 u8 d+ }
rm.dgain);
# s) V5 Y& _% z5 o U4 u" _( I9 u: }9 c: [2 q+ p$ c' U
count++;
7 T1 U& u `$ }) y7 Z# t}
9 w* t2 W/ w7 U; y0 r2 o, d7 M}" T) A. g: W$ R
: T8 v0 `: b- K2 O3 ~3 Y |
|