版主
主题
回帖0
积分10609
阅读权限200
注册时间2008-11-22
最后登录1970-1-1
在线时间 小时
|
PID算法(c 语言)
; R8 Z A) ]1 P! T+ `: ^1 `# K" }#include <stdio.h> 9 C: O) u) t( A0 t& |
#include<math.h> 0 X( }- L7 X. l
//定义PID 的结构体
0 ]9 W% O8 L1 ystruct _pid
5 `. _' Z/ B6 V( ]{
+ ^ F6 d+ y3 G8 `, iint pv; //integer that contains the process value 过/ j* N5 x+ c2 q- H: u, A% b1 l1 h
程量 ) P/ P# [/ L1 Q# `: J ]
int sp; //*integer that contains the set point 设7 l$ F. W2 _* Z5 {: V2 p# h
定值
% K7 h8 S0 o9 v' L( R7 s. @float integral; // 积分值 -- 偏差累计值 ) j0 R! E9 f5 ?8 o
float pgain; ' J1 J* e' I$ ~
float igain; ; {0 P1 b' w) g2 y" J5 `6 x/ x/ V) \
float dgain; ! q% Y, u1 J; [; o; j9 y: j
int deadband; //死区
' m* w% ~6 V. E9 _- y7 F% v: X0 o& Hint last_error;
& F0 ^( O: I0 s% X}; ; b$ n( d' `7 T) \5 ]
" J* t3 A( r5 x% T
struct _pid warm,*pid; 8 `% `0 T( ]5 z- E0 j
int process_point, set_point,dead_band; float p_gain, i_gain, d_gain,
8 ~1 d1 S1 d% i5 {integral_val,new_integ;;
+ B% }( Q. [( U' U6 I) k
. h8 L4 Q" U/ n; Y//------------------------! c. s c/ m: P9 ]6 S9 o3 v: L
---------------------- ) o) O) G) E3 d" ]* ~+ q
pid_init DESCRIPTION This function initializes the * H7 y% _9 m$ ?" D5 h$ H
pointers in the _pid structure to the process variable 2 y3 r! M L' C! N$ J' U# |
and the setpoint. *pv and *sp are integer pointers. 8 r+ Z& s" f- M7 g' @
//------------------------8 @+ k( C/ }" ~; ~# ]/ H3 {
----------------------
$ }6 E2 e: g! w' m4 G4 |# z$ M$ H3 J5 Y8 s, U' j
void pid_init(struct _pid *warm, int process_point, 2 }; H1 o) W# e3 i) o G
int set_point) ; ?+ R% n7 q, o( m! z8 M
{ ; X6 [5 J# v+ @9 A$ u
struct _pid *pid; + a2 r a4 r* T0 R
pid = warm; ' ?: w, c. H4 Q
pid->pv = process_point;
?* f! a2 L+ g2 c2 a2 Zpid->sp = set_point; ; t7 N' o( E( x- M
}
7 m! P: K6 Z3 v9 ~9 e8 H" X
6 L& F% w% A' s//------------------------
B8 c. c$ f& Z N$ }' t----------------------pid_tune DESCRIPTION Sets the proportional gain
7 n# I# H9 N/ H3 Q" d J(p_gain), integral gain (i_gain),
. ]# B1 x. X, K0 y5 Z4 I3 O/ Oderivitive gain (d_gain), and the dead band (dead_band) 7 f" {1 R, u; a! ^% |5 A4 g
of a pid control structure _pid.
6 T7 A) s6 \. g# t# G" \
) S* \: S( m: P) k0 D& ^6 b设定PID参数 ---- P,I,D,死区
1 I$ [ }2 H% L! ]7 C: C//------------------------
: c& g* R& q! l; p! [+ U---------------------- 8 M: R4 \. X8 z2 q% j
; B2 ^* L& h; }+ O
void pid_tune(struct _pid *pid, float p_gain, float
" A& @& j& |) G5 Ci_gain, float d_gain, int dead_band) ' |% r/ [# Z$ A( l3 @
{ ! ~" u/ ~( b" Q# N
pid->pgain = p_gain;
7 r, W( d7 U, s8 h% wpid->igain = i_gain; ( g# v5 h% w) M3 ~% {
pid->dgain = d_gain;
* }5 J* n5 |: g0 n( v& g/ xpid->deadband = dead_band;
9 ]9 R$ H+ ~, J8 hpid->integral= integral_val; * a* _0 W0 O. G$ u- m
pid->last_error=0;
4 L- X7 H0 l" i7 B4 G$ _2 o" M}
+ F: g" ~' b( F
3 z4 W4 b: {2 G5 E. M, \( \//------------------------
3 U2 n }6 r3 H3 f8 l---------------------- pid_setinteg DESCRIPTION Set a new value for the 3 C1 }2 K( f u0 d2 M0 p0 I) ?' s2 B
integral term of the pid equation.
9 ]) P$ S3 h' z3 |; A- NThis is useful for setting the initial output of the
; }/ ]# |) w" W8 n6 epid controller at start up.
' E) {, Z* `3 c
' P. v6 ~! }1 V. N" i, K; `, q+ t! r设定输出初始值 ; Y1 r5 c0 Y! k
//------------------------
8 A! f2 g. W3 k7 i$ P9 m/ x----------------------
6 B' J6 m1 y/ u0 U O/ Z& a& Z$ {1 A4 a5 @
void pid_setinteg(struct _pid *pid,float new_integ)
" C2 s$ i6 L# ^$ A) h! `" q{
% ?' J& ~- Z( A' {. i' p. n9 Tpid->integral = new_integ; 3 R( [( p4 v% r2 t" ]
pid->last_error = 0; 6 k9 H( |) ]" N& q& A1 g
}
( N" y, i! _: w: |3 L$ O1 p# ]! q6 I2 C( o/ V% \. \
//------------------------" Q. `! s/ O2 Z, x6 g: B
---------------------- " ]/ q2 I* H# t+ }' `1 t+ \$ ]
pid_bumpless DESCRIPTION Bumpless transfer 9 d' Q4 `2 l; F0 j2 ~. K9 Q
algorithim.
1 _6 J4 f* n' p7 I9 O' ]% H+ JWhen suddenly changing setpoints, or when restarting * t9 ~6 h- q# f' i/ G# r" h
the PID equation after an extended pause,
. T: z+ m/ W; d/ \ @" x* _; Xthe derivative of the equation can cause a bump in the controller output. This function will help smooth out ! x+ y M. w) \, s) G: c
that bump.
! b% H! y( w9 a9 \, ]5 C- w. sThe process value in *pv should be the updated just r$ m- H y: @. a6 s
before this function is used. 4 \9 y h( D F
4 e6 r& A; p! p
pid_bumpless 实现无扰切换
# Y4 w+ D2 b3 j0 j: g$ V) D当突然改变设定值时,或重新启动后,将引起扰动输出。这
/ O# a$ `; E6 l+ @& h# f: n5 _2 B个函数将能实现平顺扰动, 在调用该函数之前需要先更新 PV值
! t& i+ K( N. s2 i//------------------------" N6 Q8 r" n* J$ m& g
---------------------- - r. i T; |3 G
# M: q6 x9 c! Q3 c& f( qvoid pid_bumpless(struct _pid *pid) " T! M7 |/ j A3 I! [
{
/ N% k* j, @- n0 o [* a9 _pid->last_error = (pid->sp)-(pid->pv); //设定值与反馈值偏差 9 e+ d3 w; H x9 r* K
} 8 B1 t# Q2 R* f
: {& Q" V5 {9 E3 n6 Z' V/ c3 G//------------------------( x! B$ D. z4 H" M# E9 ^* ^
---------------------- % g. U1 o6 m) s1 y
pid_calc DESCRIPTION Performs PID calculations for the 6 b% E! `- z+ C* x
_pid structure *a. This function uses the positional form of the pid 1 h9 z7 B) |! C. u6 x' M. V0 L
equation, and incorporates an integral windup * J% {/ M( |; p8 N
prevention algorithim.
2 L7 _1 O5 _$ lRectangular integration is used, so this function must / H+ Y" P3 w! F
be repeated on a consistent time basis for accurate ! }6 b" O: Z3 K& y% V# t" q5 \4 h% w
control.
8 f( K, j3 F6 W9 _7 ?: }2 L0 pRETURN VALUE The new output value for the pid loop. # _$ n; |) X9 \& W, ]5 T
USAGE #include "control.h"
' c, X( @6 V1 K5 M' M, W( z4 ^本函数使用位置式PID计算方式,并且采取了积分饱和限制运算
5 N& G* J ~8 z) {) |, A5 U3 Q4 aPID计算 6 m1 r9 ^/ T$ _3 h: A" N: T6 r0 S
//------------------------
# E6 {+ `/ K' f7 Y: Y---------------------- 3 F9 o+ o" I* J! d6 C' T, g
- z* J; E$ [( o% @6 O. K6 D
float pid_calc(struct _pid *pid) : G9 m' }& C* K) M; Y5 W2 M
{·
, E+ v8 w! L8 Yint err;
/ v5 e% o0 O) y. {# b% J1 Ufloat pterm, dterm, result, ferror; y% B+ k. v6 f# T# M
" d+ A4 w# r3 b& v# {& T6 U& j// 计算偏差 " u/ C1 A5 ~, Q7 _& R
err = (pid->sp) - (pid->pv);
9 y4 E5 c. J& R9 r! ?4 B // 判断是否大于死区 ( R5 g: W; `9 M4 N6 U8 D
if (abs(err) > pid->deadband) ) c2 z' A3 v9 C5 F) ^
{ 2 G1 X6 Z. v5 `. x% b; A
ferror = (float) err; //do integer to float 4 J' N% u2 W: M# X% |! B: y% X5 m
conversion only once 数据类型转换
7 _' d- Y$ b0 R& _" \$ ^$ Y; o: n& N7 l
// 比例项
3 _# y+ x" ~+ g! v$ F0 Kpterm = pid->pgain * ferror;
- r7 e Y# d: \1 |6 X, O9 f8 a% g+ s
9 d& u) v! z( z8 ]# H+ ^% vif (pterm > 100 || pterm < -100)
! ?) H' o! T6 @- k- z{
8 J6 Z" s0 N; h. D; kpid->integral = 0.0;
9 m8 ?! @* a4 X1 U}
5 X( I8 X$ ?3 }- C. W6 delse
U7 E+ a3 X: m; [6 T) _. _5 L{ 9 i1 g: Z; C1 Q
// 积分项 : U+ _+ V( l0 S% K
pid->integral += pid->igain * ferror;
; Q) i+ \& X3 s" e/ b& }! t% [8 [3 D: A1 S o0 e9 t9 `
// 输出为0--100% 9 ^' Z7 k/ `: ?
// 如果计算结果大于100,则等于100 4 [$ X L2 a/ e; \4 A" g8 B
if (pid->integral > 100.0) & Y8 [! T4 Z e. u5 O. K' z" D
{ pid->integral = 100.0;
! K! R' }& H7 ^8 A+ K' y. S}
% t5 p* U5 B# T! G// 如果计算结果小于0.0,则等于0
) O+ o3 Z" J6 A, k; p9 V' @else if (pid->integral < 0.0)
, v8 e+ {. K! f( M: [9 rpid->integral = 0.0; & `, D; }' j- D r# Q& e
$ K( u/ u% T [4 l: l' t
} ) @% X. w' k) w2 Q
9 a( {& `% k/ h2 G5 b- U/ [1 c// 微分项
. q) H( R0 c' a. g4 Kdterm = ((float)(err - pid->last_error)) * pid->dgain; - t6 c/ ?% x& f0 \+ u6 o
$ C. u1 R0 w1 P I
result = pterm + pid->integral + dterm;
; e/ K7 t2 \. b9 j' P}
$ o: U2 a8 A: ielse " G/ ^5 T8 z: l% s- r) ~
result = pid->integral; // 在死区范围内,保持现有输出
6 g2 t3 W! S; j) G" {. K, @) ^' e6 u: C! A$ a& L& L
// 保存上次偏差 ; Q8 [1 |6 A- m) ?8 }& o
pid->last_error = err;
- r0 O% p2 \$ ?* w
- U: ~. O0 p6 f6 {& o H% V// 输出PID值(0-100) : |" H) }1 D; |( l5 s% g% s" n
return (result); }
5 M2 {- \/ F+ p7 l+ w+ q% O: a) q$ J1 p: ?# F
//------------------------
1 c' J8 o! F8 F7 r----------------------
0 E9 g' Q( ~5 Z; Y( Mvoid main(void)
2 E% F4 M+ n" k- w( t. D. ^# o{
) I1 c) M; [5 x5 l( p. Lfloat display_value;
( v+ |- s+ x x4 V! rint count=0;
- w8 D, A* i' qpid = &warm; ( C; W; g7 J. j% W2 [) a
( O4 H( I2 ^) K' c9 c
// printf("Enter the values of Process point, Set
' W1 ]$ n/ N& T; jpoint, P gain, I gain, D gain \n"); 6 ^1 ~& M# o- [. Z: u3 `! Y
// scanf("%d%d%f%f%f", &process_point, &set_point,
0 z0 B" B5 L# L* S4 }&p_gain, &i_gain, &d_gain); O+ a: C; \5 B4 `0 T4 O. [; |
2 T( k# [2 ^5 M* T. Q
// 初始化参数 ' z/ a/ @# U3 I
process_point = 30;
- x5 @5 w! q0 R& ^/ x' hset_point = 40; ) U1 u7 l7 [! |
p_gain = (float)(5.2);
5 B) h+ r, k* \i_gain = (float)(0.77);
) S _* ]0 K2 ~% ad_gain = (float)(0.18); ; b8 L. M' K- m9 i6 |* _( ]2 p
dead_band = 2; i I' ]: ?0 \! I& j
integral_val =(float)(0.01);
8 m" o5 T' j4 Q* q# @$ G7 _; B
2 h) P, Y+ C' f3 e* kprintf("The values of Process point, Set point, P gain,
" ^4 C( }) S" U7 a1 A0 UI gain, D gain \n");
k" C8 \- I- [+ [+ J; p S }) Tprintf(" %6d %6d %4f %4f %4f\n", process_point, 4 H' ]" o- I) y3 O: U
set_point, p_gain, i_gain, d_gain); 7 Y5 T* Z! j0 w& I" d
printf("Enter the values of Process point\n"); & G) Q; U N, R: ]
while(count<=20)
& B) n" Z5 u6 P: _3 G3 @{ ; F9 H U* @8 y P' X
scanf("%d",&process_point); 5 D* y% \" @5 ^! F3 G3 }
7 k. E9 S& R% H! h% ]4 y0 ]
// 设定PV,SP 值 + h! @) y% v5 E c3 x. }' _" |
pid_init(&warm, process_point, set_point); ( x2 k! w& e- I5 g! t, `
; u4 X- f& Y' K) a8 `5 _+ ~5 k: I// 初始化PID 参数值
8 ^& S2 | l6 L; q+ }$ qpid_tune(&warm, p_gain,i_gain,d_gain,dead_band); 8 W' P* W1 h8 Q' A% R B) H, K
+ \0 O' W' k" S
// 初始化PID 输出值 ! | ~2 g* [" R: y; \) c. A
pid_setinteg(&warm,0.0); 9 x, N/ e- H# }* o
//pid_setinteg(&warm,30.0);
9 H! ~, w( j) R% Y9 ]& E# O. Q //Get input value for process point % _0 p1 M, t2 J% N# _5 V$ \
pid_bumpless(&warm); 5 ^* m" g4 s* F E
: t$ P4 O5 V( N5 c# [* O
// how to display output . R9 q. t) V% {, E8 I8 o
display_value = pid_calc(&warm); * n2 l% d' J# H0 m j
( ^# D a+ j7 x) D( ^3 D R
printf("%f\n", display_value);
5 i" n4 Z6 F; s! R& X1 _//printf("\n%f%f%f%f",warm.pv,warm.sp,warm.igain,wa
( D& t( l% l* d% A: _8 jrm.dgain); 3 V) g \6 V7 S+ s5 n2 ~
% A8 O% M- v0 R5 }
count++; ) i9 W3 J% K6 E; J( y
} ; p3 a. v# u8 F. `4 l) p
}2 B$ L9 w, Z( j& }9 b& m
) B+ {1 m0 L$ j2 v0 U# { |
|