版主
主题
回帖0
积分10609
阅读权限200
注册时间2008-11-22
最后登录1970-1-1
在线时间 小时
|
PID算法(c 语言)# J$ |- n: W# d8 Z- V$ @
#include <stdio.h>
" e# N8 y5 L* [5 l; w( [0 E#include<math.h> $ s/ L. N" ~: ^0 f4 @; T" `) I9 X
//定义PID 的结构体 % ]$ m4 j* K1 e$ d* k: B2 d
struct _pid
/ j/ X; k& k) N. j: g0 m8 r6 j{ ! u: _3 \4 @ ^! q: q: Q2 G: W- f
int pv; //integer that contains the process value 过! d4 p1 F t. t4 }" I
程量 . _. B' H: t3 J f, j
int sp; //*integer that contains the set point 设& K3 L+ ~# B% F, \0 D, l: d9 k4 Y+ P, f
定值 3 K6 C# D: m" a& F, J$ L6 z+ U
float integral; // 积分值 -- 偏差累计值
3 n& `* ?3 A& O4 z' F# y7 Yfloat pgain; # R* u/ F7 v. d# X; e
float igain; - L8 g# j) v; P
float dgain;
$ K- ~3 p5 P4 _& w9 `0 \int deadband; //死区 + E4 ^( V$ |- n( f' b+ ~
int last_error;
% Q- O, K7 s7 L4 A1 ?- ?* f}; ( A# F' ^) {# Y& p! l3 n
. ^2 | N1 g$ y- Ystruct _pid warm,*pid;
8 x! h* |5 d: S8 f; k3 ^int process_point, set_point,dead_band; float p_gain, i_gain, d_gain, ! V! Q, r% X% B" k' g
integral_val,new_integ;;
8 W. j N9 D# W) ]2 [# ?) T( f1 y# M/ g$ `8 T u, a9 }! E3 ^1 b
//------------------------
) Y T, u! p1 q' }' @1 F- U/ J" [---------------------- % B. {7 T9 h1 l% t+ f
pid_init DESCRIPTION This function initializes the
; d) i* @: v6 A+ o$ gpointers in the _pid structure to the process variable $ L$ l( B# T- m, e8 W9 N
and the setpoint. *pv and *sp are integer pointers. ( g3 ^6 U# u) C; F2 S0 ~$ e
//------------------------
/ C& S, |( d( A2 B% E; [---------------------- v9 ?. [; j: q1 Z, `% E% [
, c% y' }' }# }& Q* j' svoid pid_init(struct _pid *warm, int process_point, : k4 d+ H9 W6 c% ?5 M3 k
int set_point) % ^6 i6 [) v6 N
{ ( G, {3 K; e/ K% V% t2 k" V
struct _pid *pid; " U- h& L2 \$ g) A. ~$ W
pid = warm;
6 ?( L6 @& U; v" ]8 o7 D/ W( R) Dpid->pv = process_point;
3 M& P( e+ _* I1 s' o& v2 Mpid->sp = set_point; 0 c1 a6 F/ G# @" ^
} - S. a5 W' ^+ F$ R1 ~/ M: q
2 f8 q# P' T1 ^( U* j! w; H _/ Y
//------------------------9 w% z$ Q( S: \9 [
----------------------pid_tune DESCRIPTION Sets the proportional gain
1 y# Z( v- I- F2 p- z0 E( X(p_gain), integral gain (i_gain), 9 I: G$ c: I) H5 i! Q
derivitive gain (d_gain), and the dead band (dead_band)
% b' s2 [1 t a& cof a pid control structure _pid.
9 w8 x+ A% w# y& E3 l1 q8 K' a3 B4 P) K2 Y& ]* C- ?+ S5 W+ R
设定PID参数 ---- P,I,D,死区
/ R5 f) i, Y I% F( `. F0 l//------------------------7 p5 n/ D! q6 D$ r5 K3 C
---------------------- ' l) J( a: d7 z0 p6 G
L* _, n2 `2 U$ W& p2 K' mvoid pid_tune(struct _pid *pid, float p_gain, float 5 f3 u+ M) D& \, t
i_gain, float d_gain, int dead_band) / f, I9 k* U* I& a: t: b* k
{ & @3 ?9 I8 c9 \* M% H: e
pid->pgain = p_gain;
7 A K6 o3 ?7 z4 S7 J2 \) ipid->igain = i_gain; & Z& F' R' C- u' S% A+ R# S; S( e9 B9 n
pid->dgain = d_gain; 1 \! r2 \% F* N q H* f
pid->deadband = dead_band;
2 d* Y- _* h+ ?2 Cpid->integral= integral_val;
5 O7 h) g- S0 w9 g/ R9 _5 H! zpid->last_error=0;
0 Q: r& Z8 _4 y}
0 X! K; s: j7 e6 @8 C4 l5 }1 }5 k* E2 G: @: x+ n% o
//------------------------# i: C* I( _5 b* b% v
---------------------- pid_setinteg DESCRIPTION Set a new value for the
8 \9 _0 L2 l) c6 m( yintegral term of the pid equation.
v0 C% ]1 N' B# A* } U) [1 D* }1 H! cThis is useful for setting the initial output of the
% ?# `7 J! z2 m, T# N3 Hpid controller at start up.
+ k( k6 C, | Y* _
4 d! L$ R/ r1 E% V+ N' C设定输出初始值
d5 e: ]5 Y$ X- K7 k( K//------------------------
* l! w0 H \5 ^4 c9 {% J6 F% F----------------------
8 E+ e, m$ e2 t% P4 }& c- T% I3 \3 o U3 P6 i
void pid_setinteg(struct _pid *pid,float new_integ)
$ }3 [+ Z- p4 \- e7 W. k% V# q7 L4 W{ & k: {- x. l4 M
pid->integral = new_integ; ! A4 v4 o! J- G6 A. C) j, x
pid->last_error = 0; . W$ c) w" |' n0 M4 v
} 8 X, C, W! r8 \. B( `
) l1 c, k/ \- r# i- G6 M+ p5 C//------------------------ O& w3 o' o+ C0 c
---------------------- ' i/ k! d3 w- \! z1 ^ q) u% h
pid_bumpless DESCRIPTION Bumpless transfer
3 P4 r" Z6 _6 k7 x% Balgorithim. {+ \1 U4 @- h; a$ p
When suddenly changing setpoints, or when restarting
$ |; ^- K' |2 V* ]the PID equation after an extended pause, $ H6 H6 G/ a' _# D
the derivative of the equation can cause a bump in the controller output. This function will help smooth out & Q9 Y3 c# j- Y# {6 O
that bump.
7 X0 x" h% q7 `The process value in *pv should be the updated just
) |; m# E- j$ v+ f6 J; pbefore this function is used.
. t% }" P) Y2 |3 W
8 c* n' W2 I8 \2 Cpid_bumpless 实现无扰切换
9 R0 y- c: w; s6 H5 M* d4 C! {$ r. h当突然改变设定值时,或重新启动后,将引起扰动输出。这
" U1 o+ T& m8 c' U" g2 {/ j* L个函数将能实现平顺扰动, 在调用该函数之前需要先更新 PV值
. C* e h; X* u7 c9 L8 d, h" y//------------------------
4 `0 A; N9 J4 m# ]3 h) F" m----------------------
# q& [) j/ l- Z' O* v- m5 O$ Q
0 ]1 }" {+ o! U4 m! M) d Rvoid pid_bumpless(struct _pid *pid)
) b) D/ k6 Q( K8 L5 E/ T% \; v% B{ 2 ^# g8 g1 q, | P! F( Q' W$ q9 [6 j
pid->last_error = (pid->sp)-(pid->pv); //设定值与反馈值偏差 ; |, Q" |7 M5 K: q# F( D
} ( D2 f& O7 a. k- x* {% t1 {! R. G
+ Y; d5 B' G3 `, [& o" X//------------------------
$ A6 Y8 }( e0 c- G& L3 `7 ^---------------------- ; @& X u$ G; s) l! }8 s
pid_calc DESCRIPTION Performs PID calculations for the 2 |( E4 v- j6 D) w# {
_pid structure *a. This function uses the positional form of the pid
$ H! X& x8 m5 E( X( A7 v* y, I! pequation, and incorporates an integral windup
) \6 k6 P) s v* v6 G2 zprevention algorithim. 6 A0 v8 ^& t8 k4 j. _" ^- V/ ]
Rectangular integration is used, so this function must
4 T. o# `9 N* V, D- hbe repeated on a consistent time basis for accurate
$ M1 x+ _6 k; I1 Mcontrol.
- Y8 h/ y# b$ R/ d2 lRETURN VALUE The new output value for the pid loop.
; }9 Q! O3 V, W6 ?$ Z( OUSAGE #include "control.h" % { G% ]$ l! t7 _8 h! e
本函数使用位置式PID计算方式,并且采取了积分饱和限制运算
, z8 ^! I2 f- u& D1 \PID计算 ' i) \# |& c( o4 M
//------------------------
* x; n% a. l! m$ j: T- y7 X! x---------------------- 6 l/ I- n4 @6 ]; Y
: ^' z0 O( p' G3 u5 ^: h
float pid_calc(struct _pid *pid)
: h* }5 w# g5 l- p{·
V- x% a/ z9 bint err;
; f `- H" F) g% f: P8 D% D" {+ sfloat pterm, dterm, result, ferror; 3 Y! V# q5 U$ G1 Z
/ i) G1 M' {0 `$ G: B
// 计算偏差 * C( F1 X# g: z# w5 \
err = (pid->sp) - (pid->pv);
" m. {9 o8 \2 ` @% v) G Y/ T$ N9 M // 判断是否大于死区
+ i( o9 ~/ C9 s8 e+ v$ qif (abs(err) > pid->deadband) 2 y2 o6 z7 W3 Z! Y& u# z/ I7 t' K3 S
{ " a* K$ X5 x. \
ferror = (float) err; //do integer to float
! k: E1 |+ L% p( L& N0 econversion only once 数据类型转换
" j+ F3 h C0 r) {
9 n. ? `" O; P ^0 F/ [2 h// 比例项 $ i q+ w! n( [: {
pterm = pid->pgain * ferror; k) f0 S8 h+ g2 Q. V
. Z5 E, t: q( t3 @8 L
if (pterm > 100 || pterm < -100) $ c- E" s- c0 `, l7 a8 R
{ 5 T1 T/ H" L) N: ]1 d: [
pid->integral = 0.0;
7 h2 U# U1 s" y$ x3 ?; X" Z. Z* a# _}
( m+ m( ?& T) d7 Q& Celse 1 R% i* B, Q2 q" s+ o- w
{ 5 V9 R, K& Y4 z# ~1 l% G' r& f
// 积分项
# n9 T1 U% f( c6 u. W$ upid->integral += pid->igain * ferror;
0 j/ M7 q3 S1 q1 S r% O4 ^+ c' i% D) {& K- h) N4 q
// 输出为0--100%
" b2 [6 J% Y7 [+ ]% L5 T6 z// 如果计算结果大于100,则等于100
) S+ U% q, j& v7 vif (pid->integral > 100.0) 8 n& ]- P, H4 V, M: r
{ pid->integral = 100.0;
2 }; o* a. T8 }4 ~} # J! R6 H. o% z0 X
// 如果计算结果小于0.0,则等于0 3 Y3 b' j/ v& z0 q, u: t; S% C
else if (pid->integral < 0.0)
, C! n1 u/ h$ t( o: y8 zpid->integral = 0.0; 1 I2 n0 K- X* X+ O$ f2 J
/ |, P* [" c& D1 j
} # |4 i# u* W0 Y. Q6 [3 a& Z
: G3 [" u5 Q: o3 X \3 m: l// 微分项 / W' ?& S9 r' v$ h
dterm = ((float)(err - pid->last_error)) * pid->dgain;
5 e+ h1 D7 |* C, G% }" @8 I7 E& n8 F x0 ~, e5 i! f
result = pterm + pid->integral + dterm;
2 I6 W. v% g, j} % x6 z( O# D8 a
else 1 s2 B& o5 v5 c9 O( Q
result = pid->integral; // 在死区范围内,保持现有输出
9 O. N5 A6 [5 e
! N% s& k/ R. N- I, A, t( e// 保存上次偏差 9 k ?; G* q1 n6 }6 N
pid->last_error = err;
6 i7 ^2 W# ]. P' a n# P, V* L) y; s, b6 p
// 输出PID值(0-100) + ^% V, C) X+ W1 j% s
return (result); }
: N' h0 j. M# w* n: ]5 j& U2 e0 U0 x1 p' q3 ~! p% ^1 ?3 D
//------------------------
1 T1 f8 H/ G$ o% b* X/ T( S---------------------- 1 t) Y" \; g3 j, p( S
void main(void)
3 t+ Z. |3 r7 O* H{
* A/ l p* G; b( Nfloat display_value;
/ z& e& z' D: @& C9 Cint count=0; " {" i) o: k, h. y4 }: y
pid = &warm;
- }6 r" B7 u$ ~# e' Q
/ s; O5 [2 [/ A) ]( G( w// printf("Enter the values of Process point, Set % ]* h' e, ?4 b1 |; _7 E% \
point, P gain, I gain, D gain \n");
2 x; o7 Q+ x: U3 Y( Z// scanf("%d%d%f%f%f", &process_point, &set_point, 7 {! |$ |: C1 W: B( P* k+ h
&p_gain, &i_gain, &d_gain); ) n6 e' e4 I0 d$ \6 a$ w
7 h! T5 k- _; c: t5 J6 D
// 初始化参数 4 E/ ?# \8 R# R" z) b$ `9 p
process_point = 30;
% m1 Q- x, ^) iset_point = 40; & J, X- _: I- z; Q
p_gain = (float)(5.2); + V4 |* Y2 Q$ {4 q4 E8 f
i_gain = (float)(0.77);
1 N5 p" d9 g; q1 C* `d_gain = (float)(0.18);
% Y* n1 y0 \. {3 Y1 P0 }" |: Odead_band = 2; 6 c% \' k4 p9 i( W+ E5 q
integral_val =(float)(0.01);
$ q p5 v8 J. ]) J$ J3 A @2 t% o) j7 X: r4 q% L! R- e
printf("The values of Process point, Set point, P gain,
4 j7 \" |6 v: t8 c: A2 {$ D+ DI gain, D gain \n");
6 k8 q1 ]6 E: S k: Y) F8 a: O5 B- Yprintf(" %6d %6d %4f %4f %4f\n", process_point,
I/ Y, r2 R' G7 Tset_point, p_gain, i_gain, d_gain); ) l* @2 h/ K! g) W$ H
printf("Enter the values of Process point\n"); , i' k7 }8 Z+ _% j
while(count<=20)
' n T. ?5 B x( c( q9 c b* X p4 O{
4 M f/ `5 F0 sscanf("%d",&process_point);
% s- w+ O; _4 u! e+ F: z$ |* L# U
2 N! B% u: x! |3 v" N' U// 设定PV,SP 值 0 }, m; N: v$ X! \
pid_init(&warm, process_point, set_point);
( j g4 l% W+ Q$ c" y, _' r; l5 |- N) c* s& ^/ x
// 初始化PID 参数值
+ W: ]' r7 ]5 ^" n5 Ppid_tune(&warm, p_gain,i_gain,d_gain,dead_band);
7 } U' Y" w1 H) \& ^. i, E' X6 `' Y9 c; u- e% ^
// 初始化PID 输出值
9 [/ R$ U: v8 N7 ^pid_setinteg(&warm,0.0); ( E* i. b) o# }2 g" g
//pid_setinteg(&warm,30.0);
2 j+ b5 C; O# ~/ n. j2 u //Get input value for process point
9 o3 z" M' l. g$ F- tpid_bumpless(&warm);
$ K* ^3 x$ h# s, |( t. J- d: E
, N4 k( P3 C3 v0 q3 R' `" f// how to display output # j& `! P, `9 y# x% i+ ?
display_value = pid_calc(&warm); & ^, f: j! G/ i) H% O+ ^/ O
) v. r3 R/ n2 P* D/ fprintf("%f\n", display_value);
9 g5 S; b( l0 O% ~+ D# d& I//printf("\n%f%f%f%f",warm.pv,warm.sp,warm.igain,wa. w) U! G$ N2 e, |" r' e
rm.dgain); 7 N: ?" a3 m) t- ~2 y6 h" J" Y8 f* g
3 E) f3 a- y4 L# j$ Lcount++; % w* p: `) \5 v
}
6 B: j K9 _$ a- K( c}
: p; ~4 @, }) a+ P7 R8 N: g1 h; K1 ^( b6 k9 t. U
|
|