版主
主题
回帖0
积分10609
阅读权限200
注册时间2008-11-22
最后登录1970-1-1
在线时间 小时
|
PID算法(c 语言); g/ ~8 G0 q9 h0 A4 L; E; Y6 v9 U# o
#include <stdio.h> " w# d3 U* G! h
#include<math.h>
9 G6 ~) A T% y& K2 o- `+ z* W//定义PID 的结构体 & L9 Y$ |- S* p' `8 @) s
struct _pid 7 U, w0 m S/ n- Y" W
{ , N1 Y2 }' x! H+ N! ^4 P
int pv; //integer that contains the process value 过
6 T' \( F6 P7 N5 [# ` f程量
" B0 u, Y1 W. t! Nint sp; //*integer that contains the set point 设3 J6 Y+ N4 p5 u# l7 t7 ~; i
定值 5 E4 _4 ~$ K: V/ K
float integral; // 积分值 -- 偏差累计值 - G/ v5 Q; F4 X' W
float pgain; , }2 k: g% I! G W+ w" z
float igain;
1 q0 [ P: ~. a. I) n' L- {float dgain; " _) X; p1 l. F8 z
int deadband; //死区
6 `# u2 v0 E1 a. P# k+ @& Xint last_error;
6 ?/ `3 I; s) I3 C};
* [! |6 D" i# x. i) G5 L" b8 q+ x, ~4 F" J, U! G. O
struct _pid wARM,*pid; , w7 Q. D9 u7 h2 [
int process_point, set_point,dead_band; float p_gain, i_gain, d_gain, ( q, x" B6 G; \ I7 g% O
integral_val,new_integ;;
% Z7 j4 H) n$ k6 ~/ Y; j Z8 p6 Z7 r% h: B4 | o* u4 s
//------------------------
" e& c0 R2 O9 r1 s---------------------- v! O+ i& @8 P: }8 ^
pid_init DESCRIPTION This function initializes the : g! |8 L5 c: A4 X
pointers in the _pid structure to the process variable ( ], v) e6 ^! C
and the setpoint. *pv and *sp are integer pointers. : U) c$ V" f1 x4 ]- X9 J
//------------------------5 p C; u/ @9 B8 x2 }5 U( c+ D" Q" `
---------------------- ; \+ ?* B3 ?" x2 H" y
- _/ c% m# g: h6 f
void pid_init(struct _pid *warm, int process_point, . L' s2 @. `. }! {( A, T/ K- Y
int set_point) 8 U' T# Q& v3 T- P
{
1 b8 n7 l3 m: }. i6 {, istruct _pid *pid; - y" \; P/ P; x
pid = warm; & P' ?; l5 s3 y& `* J
pid->pv = process_point; . X# m5 p D2 E: K) `# Y
pid->sp = set_point;
4 R# h S2 U4 q: N0 S a8 f}
/ K% J" d, E) m+ A/ o& _3 c$ E8 K& Q: s
//------------------------! p4 H5 l1 j1 P+ K! u, S8 Q
----------------------pid_tune DESCRIPTION Sets the proportional gain & L/ g3 N' a6 N2 ~! r1 [
(p_gain), integral gain (i_gain), 9 m" K& x' G6 m& c! _( @8 V
derivitive gain (d_gain), and the dead band (dead_band)
* ^! J* M* J9 h: e: ]of a pid control structure _pid. . m; y1 b: L/ k7 I& M9 ?% U
! f1 _6 {+ @8 z/ D( w) g& Q, f, |设定PID参数 ---- P,I,D,死区 ( C5 E! U9 w' I o# p5 h
//------------------------0 T* f/ n5 D6 \$ e( P: S
---------------------- + j/ Q, X" ^5 y# H5 V/ X2 l
! a7 M1 S! C% W" b
void pid_tune(struct _pid *pid, float p_gain, float
4 @( C6 t6 e& qi_gain, float d_gain, int dead_band) 4 @- F. K% x6 J. H, g1 U# [
{
6 j/ s& E* V/ v, P0 h' |( x0 M6 Qpid->pgain = p_gain; ' |8 F3 f% w" U( P
pid->igain = i_gain; 2 U2 s( b: P# z* n8 q6 z& J
pid->dgain = d_gain;
) n$ S2 T- O/ J6 ^4 i1 O0 ppid->deadband = dead_band;
7 g- b3 V7 \3 Upid->integral= integral_val;
( B5 p& f* F) R! ]- Z1 Z6 gpid->last_error=0; " x( d9 T) N9 H8 F# F
} ; {1 W7 Z5 ~& O I2 Q
9 ~1 ?- |) ~9 ]8 O) s J
//------------------------
) j. j0 Y% H5 W' d: M+ f# s---------------------- pid_setinteg DESCRIPTION Set a new value for the
. N% m; ? l$ I' V' U) Bintegral term of the pid equation. 0 z3 a/ b& k5 m; q8 C/ [! R/ h
This is useful for setting the initial output of the - a; Y* B0 c6 u& ~" |/ L
pid controller at start up.
6 F8 l) A, n; r, O. ` O/ H; i" h$ W U+ e4 D; Y# G/ d
设定输出初始值
9 y7 I( H& x! H//------------------------
3 @. Q8 j0 W* J' M+ l2 T2 X" n5 m3 d---------------------- 3 y* F, g" C: o! N
* f+ h T4 ^2 ]# ~
void pid_setinteg(struct _pid *pid,float new_integ)
! Y4 e8 H# W% \: M1 {) W{ ) j: c4 [8 X1 W% m7 j1 Z
pid->integral = new_integ;
( H6 x* } r v5 l" w' S3 Upid->last_error = 0;
- P3 u, I Q! w t. ^0 u} 0 |+ y5 G! b. g% M# @; B
# x# c! a/ ^; Y' X- [//------------------------
0 i4 M$ U; `) ~5 V/ e" H----------------------
- V; v6 F7 Y2 T+ s. ppid_bumpless DESCRIPTION Bumpless transfer
2 @( u* G0 J+ E( @algorithim.
4 c2 `1 t0 l$ O- O7 zWhen suddenly changing setpoints, or when restarting - _9 [2 ^7 q6 U) I
the PID equation after an extended pause,
1 q* z+ ?1 S# J% }6 p- ]the derivative of the equation can cause a bump in the controller output. This function will help smooth out
2 d8 @* l+ b! r7 X+ l8 R: z" kthat bump.
) u3 g- A3 T- Y8 }' p# c0 kThe process value in *pv should be the updated just
T- V% s; b+ O$ E. X* d+ j: T3 O6 `before this function is used.
0 F; C# K/ B/ B) G9 `: Y
: ?% T6 {; F9 g/ O1 ]pid_bumpless 实现无扰切换 . x( J3 e6 R( q! D
当突然改变设定值时,或重新启动后,将引起扰动输出。这' |5 [4 _" {. _8 y c6 K
个函数将能实现平顺扰动, 在调用该函数之前需要先更新 PV值
2 C% j3 N2 U' b, p, j# }4 N+ N//------------------------
/ [0 w& u* C' t/ k% m9 L---------------------- * D6 u2 G+ P0 f/ `' e
, E3 R) @3 c$ V' K/ S2 z. uvoid pid_bumpless(struct _pid *pid)
8 d( M9 r# \( {/ v+ I7 @{ 7 B2 c4 d8 Q4 ]+ e% n
pid->last_error = (pid->sp)-(pid->pv); //设定值与反馈值偏差 ' h+ {/ O. h7 p
}
2 [; H- \. K2 f3 `) z- n) w& ^3 N1 P$ |+ e# U! w: W- P
//------------------------/ h- w: Y( \# h4 f9 ^. m+ k2 y1 o/ D
---------------------- 3 c- R( f# @6 [+ p" g1 q
pid_calc DESCRIPTION Performs PID calculations for the : b- d0 @: P- d/ }9 Y# B
_pid structure *a. This function uses the positional form of the pid $ G/ y3 g) S* F- `
equation, and incorporates an integral windup , S" Q9 }" G2 I% @: }
prevention algorithim.
# |0 d4 {( C: P3 \8 T6 HRectangular integration is used, so this function must
, u. z6 s" j1 [be repeated on a consistent time basis for accurate ) H( t4 ^+ w* s' V. }6 p
control.
& o) I( A y! z# q. u) CRETURN VALUE The new output value for the pid loop.
: C1 R3 a: @8 K( j2 V6 iUSAGE #include "control.h" # U$ E3 a8 U! ]+ ] o6 E
本函数使用位置式PID计算方式,并且采取了积分饱和限制运算
- z# ]* d9 Z* u. P1 |0 {PID计算 . y2 D3 B) V* z) f, l" l( C
//------------------------
- ]. l. q$ v" p! q---------------------- 5 ?: h& B1 `4 m% p6 F
$ x5 c4 q, l" j
float pid_calc(struct _pid *pid)
/ x0 H# Q4 x9 D9 [& [{· " P1 g* Z9 ~* K3 E. `
int err; $ G- R, n# q" J( C
float pterm, dterm, result, ferror; ! T0 S1 L; |9 N" n) z
+ [8 D+ F# \7 M
// 计算偏差
* X1 Z' `/ H8 @* I, {5 Werr = (pid->sp) - (pid->pv);
* H$ c g8 Q* a! N- b7 r // 判断是否大于死区
* R) H8 {) e5 h8 S6 D k4 }- Aif (abs(err) > pid->deadband)
; v) M0 t P! Z4 a{ , h. y$ ~* V. h5 @2 Z& ~% i
ferror = (float) err; //do integer to float
( g) P9 h5 d! t& |! Q* @conversion only once 数据类型转换 " G( `0 P' j3 j4 t
( ~1 K4 J' E) U i// 比例项
) h. d5 y7 w! K C( F* K$ l) B0 ypterm = pid->pgain * ferror; , u8 ^8 V7 p# W d
6 @" `+ h0 u) _5 z8 F0 r7 Q0 rif (pterm > 100 || pterm < -100)
' m+ D! c6 a( r: j, D; S{
y* H6 Y! w/ x! }0 @# a5 ~pid->integral = 0.0; - k: i: i5 r6 P4 R& d
}
7 R, }# A; k1 k" H: }( M, telse
2 Q. v& h' B- \ V* A. D, }5 E7 J9 H{ 3 y) ]( r+ C5 D* J3 Y: C
// 积分项 1 X. h8 X9 J- M- |9 b
pid->integral += pid->igain * ferror;
t& ~4 P" K5 H/ L6 R- m1 g( l. N2 r" j# Z" q
// 输出为0--100%
( y( a. R$ O5 z) q// 如果计算结果大于100,则等于100
7 v. X7 Z$ S" dif (pid->integral > 100.0)
/ F- B% m3 b" y{ pid->integral = 100.0;
3 d% L) \5 _8 Z8 i% ?! B} 1 H8 }: P) t. G' J5 L
// 如果计算结果小于0.0,则等于0
0 w; t- b% u6 W; n& qelse if (pid->integral < 0.0) , I: S3 {4 O0 o( E8 V
pid->integral = 0.0;
, }6 L3 Q: A H x6 W7 r5 w& R5 U3 |+ s# c" |. z1 {
}
" T5 f" m$ S7 M+ j8 a0 _1 \. o H8 w) G; p' a0 m
// 微分项
3 \# [$ @ C: b% w0 Idterm = ((float)(err - pid->last_error)) * pid->dgain; ! L% m6 h* D! t2 z
. W9 `+ ~' a0 T$ rresult = pterm + pid->integral + dterm;
: h: g* H5 x G1 X5 ~& u s) N; E0 `- B}
! M. p( [) H3 N; j1 @' }: ]else 8 ~. f) C9 [1 T2 u" H
result = pid->integral; // 在死区范围内,保持现有输出 . A8 y' ~$ k( T/ v, M
% d! q F% U' B! d0 X// 保存上次偏差 + j3 V$ f9 ^4 [( o* u+ L5 G( d
pid->last_error = err;
, O5 J8 @; U7 B n7 k* z( _9 i1 t
9 j2 u5 ?4 w( F9 i// 输出PID值(0-100) $ C# P" _$ ]" R( F" u4 K; p1 ?* c+ G, O
return (result); } ) f: S' V l8 w9 i3 n& c
* T; z, [: X- Q* s* {+ ^1 ^
//------------------------
* O# V) L1 J( P! ^" e" r----------------------
# E0 E' e. I* m4 ]void main(void) . h. p/ D8 r" }! W' ?7 k7 j" J0 ~' {
{ , h: N9 }, {4 U% {. O" b/ m
float display_value;
7 H% e) S* L( w+ F8 `' }int count=0; 7 W+ M8 D$ c6 Z
pid = &warm; 0 H/ a W0 S8 v- |
2 c) @! d4 s: L8 b// printf("Enter the values of Process point, Set
, Y* L- U) R0 p) X! lpoint, P gain, I gain, D gain \n");
5 Y9 y) m" }/ j8 B. N& Q// scanf("%d%d%f%f%f", &process_point, &set_point, + \3 v7 ^. F3 ?0 M
&p_gain, &i_gain, &d_gain); : \; ~/ I9 T/ }/ L y! G/ F
F' @7 `. B% K* e/ P" o$ J
// 初始化参数
$ k! S, g" c+ r* R7 hprocess_point = 30; * `9 H: V- s1 y' G% B
set_point = 40; ( [0 j! G+ q4 z0 \& H1 q& q9 l
p_gain = (float)(5.2); 8 `) j6 {% x- O: T! [% j
i_gain = (float)(0.77); $ |7 Y, i& R& |5 ^' n/ o* r
d_gain = (float)(0.18); : _5 z& w: \, N. g! `. b( l
dead_band = 2;
4 k( V9 u+ A" X" W/ Q- Aintegral_val =(float)(0.01);
! v6 e$ j3 I/ F; s5 {, s; f, u+ M+ c+ ?8 d
printf("The values of Process point, Set point, P gain, ) W) G( }* n' J% p- I# L) S- F# i
I gain, D gain \n");
- J3 T" a2 `5 _/ r y1 T7 \printf(" %6d %6d %4f %4f %4f\n", process_point,
. D# |, H3 C" [& B6 o% Tset_point, p_gain, i_gain, d_gain);
) v5 W! `. w1 s ]/ S) jprintf("Enter the values of Process point\n"); / M# X, Q+ r0 Y3 M/ j, u2 o& c8 o
while(count<=20) , d* A$ i+ n. \1 p9 J) N1 A1 i
{ 5 G. u+ v: Z# X0 F$ W% ^5 d/ K
scanf("%d",&process_point);
G3 Y! d. r/ q( i. e: R( o, G% l- {: q4 a
// 设定PV,SP 值
6 t- j; [4 U5 Dpid_init(&warm, process_point, set_point);
: C6 ]% K% }6 o* `* n9 K; ^. _. K. B* I; q' T
// 初始化PID 参数值
8 t5 L0 t( O1 v- d4 j: v: Dpid_tune(&warm, p_gain,i_gain,d_gain,dead_band); 7 p2 a" U. f3 C3 C) r
; P! B, A: a1 d4 A. {
// 初始化PID 输出值 6 e4 t5 Y& ?- v$ \" }( m
pid_setinteg(&warm,0.0); m+ a7 U1 v# N {0 R5 d
//pid_setinteg(&warm,30.0);
$ m6 f( V0 @' A ^) J6 Y; U8 T3 _ //Get input value for process point
( i% ^; W, Y0 b/ R3 k, o, j# E( |: Gpid_bumpless(&warm);
% @: ^& v/ z. ?. D; [# `% d+ o
5 M8 g3 p1 e# [3 B5 [& a8 T& u; c// how to display output
! ^( Z2 X$ J, e8 V V6 g5 Ydisplay_value = pid_calc(&warm); " t7 x5 `5 W9 P8 i6 X* L" J; @
( r) a& ~5 m$ M; | c0 tprintf("%f\n", display_value);
/ J7 w6 K. b q1 s+ R* S( X! p5 o//printf("\n%f%f%f%f",warm.pv,warm.sp,warm.igain,wa
0 a8 l$ _0 L8 V+ _' r9 grm.dgain);
' o- F5 w6 a; _
) g5 W: h; Z& u- ~7 ^ F5 Fcount++;
& e2 N% ]" j( k& j}
% `" \ t# Z8 @( x3 a}, t; W: j# D p1 Q
# A1 P$ R" {8 y2 z
|
|