版主
主题
回帖0
积分10609
阅读权限200
注册时间2008-11-22
最后登录1970-1-1
在线时间 小时
|
PID算法(c 语言)2 d! |, c- a4 I4 x
#include <stdio.h> , J" n* p/ K+ T" c+ t, h0 B
#include<math.h>
! y2 s7 ]- r8 D* c- A; E//定义PID 的结构体
! L: \: M& k9 ~) e4 [struct _pid
5 P- V3 {0 V8 j: {{ : L$ G9 U9 @7 _4 E8 L, K
int pv; //integer that contains the process value 过& T4 K+ I/ z; D
程量
3 ], e; I$ o5 J+ M9 `int sp; //*integer that contains the set point 设
9 I5 N0 C5 @% C, M7 N- a, L* g定值
8 S8 ~6 |% U( a( I6 u7 U; ~9 P1 rfloat integral; // 积分值 -- 偏差累计值
9 `$ q! _% s& Z9 D3 S2 @float pgain;
9 I" `7 x, f1 tfloat igain;
- f% V0 B6 o3 m Q X$ J7 ufloat dgain;
4 t5 J0 W8 n7 p* o) [int deadband; //死区
: u' r; B; J- Sint last_error;
3 ]( H. q' [. D}; + ~, X6 k z2 b
' \+ u' `; `9 ?+ @1 `struct _pid warm,*pid;
7 |0 U6 e) l A6 g( b5 b7 G: ~int process_point, set_point,dead_band; float p_gain, i_gain, d_gain,
' g4 S* n% @2 X7 S/ a- q0 Kintegral_val,new_integ;;
$ E- A/ a( g" v8 f% a& o
$ n0 x+ z: a9 P! @//------------------------1 |- T! ~2 o) T( c$ o L
----------------------
! g1 K" g3 Q2 b+ F4 S- h* @- apid_init DESCRIPTION This function initializes the 7 h. M$ y0 Z# P- `
pointers in the _pid structure to the process variable
2 p0 s/ k/ U( ?- _/ ]* D' Qand the setpoint. *pv and *sp are integer pointers.
: ^- d. O% S! P, Q9 a8 X6 g% m2 V//------------------------* p2 a* d7 x! F) E9 x
---------------------- 6 l3 h! O$ O7 ^" e, C4 ?( M0 l9 r
: Q" q, u- \3 j x9 ]" }3 pvoid pid_init(struct _pid *warm, int process_point, 8 ^& t# S+ l. L0 _7 a7 I
int set_point)
' G3 l* D* `8 ?0 ~# F2 N{ . K- E" I* U& O
struct _pid *pid; ) B; B4 \% a5 P: g
pid = warm; , ~- ~4 e) P. F
pid->pv = process_point;
0 t# |; d- [7 Kpid->sp = set_point; / Y- ^/ G6 [) x- a+ k3 o( t+ }
} + [- C" g1 Q; W6 `, L! e( Y" M
5 K0 J* X' o' i K# t
//------------------------7 L/ V. g& [: u5 l
----------------------pid_tune DESCRIPTION Sets the proportional gain
) C" h& ~$ n8 Y(p_gain), integral gain (i_gain),
8 G! G7 X6 ]9 R7 K. P8 l l% bderivitive gain (d_gain), and the dead band (dead_band)
! @7 c7 v6 |) C. V9 F: V$ lof a pid control structure _pid. + {2 L2 f: P/ M* }7 i$ M
8 M3 w1 C+ e5 P2 G4 W设定PID参数 ---- P,I,D,死区 8 y+ y9 |! k5 A, W
//------------------------
( [3 S4 D! ^ o X l8 _0 g----------------------
- m2 E% A" h' O& V/ p; P/ ]2 f8 G! U* N
void pid_tune(struct _pid *pid, float p_gain, float
5 B/ C( X* u6 c. v* O! Ni_gain, float d_gain, int dead_band) - F% m) h4 u* H
{
; [, g4 J9 f! s! lpid->pgain = p_gain;
/ G& Y- ^) h" O+ I2 ?4 V* Zpid->igain = i_gain;
8 F6 n7 I% I) I% R# f9 y* a, V/ cpid->dgain = d_gain; ) E( s3 P4 Y) Y* q0 c2 v( r
pid->deadband = dead_band;
+ [0 n6 A$ Q7 C" ^3 @pid->integral= integral_val;
6 Q0 c( _) O$ r2 @pid->last_error=0;
+ V# d5 r, X! J9 ]0 Z t}
% e1 _* a& A, W5 F( x e4 s. h4 c
- D# Z$ ?8 Q: e0 o0 R2 X//------------------------; B( G0 ~* B$ r/ {5 a5 g( J; o7 @" e
---------------------- pid_setinteg DESCRIPTION Set a new value for the
9 L! b" G. e" D! f0 X' yintegral term of the pid equation. ' {* z' C& J" N9 O3 ?( v1 n
This is useful for setting the initial output of the
, u# K; U3 Y% Q& d8 U. _+ \/ Rpid controller at start up. $ V+ W, ^- \$ S. k. F
8 D2 u: H" S9 B# A* T+ c1 P设定输出初始值
3 w3 m" g( n: Q2 y//------------------------
- u6 v- @- y1 m3 d+ a4 W' w% p----------------------
! o8 h" c4 V) b' `3 _* N( ^2 A3 p3 y6 h: P
void pid_setinteg(struct _pid *pid,float new_integ) $ v7 [& O, c; O5 I' ]2 |7 L2 _6 k8 v+ c
{ ( Z$ w9 O7 E4 k$ y' N6 g% u: T% h
pid->integral = new_integ; 1 h2 v/ q7 j1 y1 m* n
pid->last_error = 0; 4 O$ ] l2 c8 a7 [+ f( g
} # [" I/ B, n" d( K0 g0 T) ?* ]
B: W* o; [+ ^4 S5 ]* @' y7 c//------------------------: Y; @( b2 T2 G, n. b1 e0 M
---------------------- . u( |3 S9 }2 o% Y3 n
pid_bumpless DESCRIPTION Bumpless transfer 1 r& K5 A3 U" ~& L; s
algorithim.
0 p& t- M8 p. x( U* J9 N3 JWhen suddenly changing setpoints, or when restarting
$ U" u: ?0 C$ u, @the PID equation after an extended pause, 9 Y6 K; G! _0 D- y
the derivative of the equation can cause a bump in the controller output. This function will help smooth out
8 m% j* M: k. q ]that bump.
; \1 O P+ s# [/ vThe process value in *pv should be the updated just / C" v B& z' J5 [
before this function is used.
' Y5 ` y h& x
* b4 A2 j1 E8 Upid_bumpless 实现无扰切换
* ~8 D0 U6 S- y当突然改变设定值时,或重新启动后,将引起扰动输出。这
& k+ {) N; `) z5 w6 E3 o3 Y个函数将能实现平顺扰动, 在调用该函数之前需要先更新 PV值
2 o5 n, ?: d" L//------------------------- D/ t& r- g; K/ i
---------------------- , m& {1 i) z4 c3 t ~1 z
3 H( k5 X ~6 {9 c$ W7 y, yvoid pid_bumpless(struct _pid *pid) ) f+ M0 _$ k! [
{ ) s3 K: n) D7 P. ]
pid->last_error = (pid->sp)-(pid->pv); //设定值与反馈值偏差
; y1 o5 v# _7 N7 l8 N' [0 T# p Q}
\+ E1 t% z0 J0 E( }# c' V+ E+ M) ]; U- _8 `/ g: j
//------------------------' t4 _* }7 o3 ~5 M( I- i
----------------------
, ]% j" ?3 Q- b! Mpid_calc DESCRIPTION Performs PID calculations for the
$ v8 z5 M/ k- I& o# F_pid structure *a. This function uses the positional form of the pid 9 i( T0 t; h3 k$ x* W' {
equation, and incorporates an integral windup * Q4 }5 C( Z% V# y5 l+ K/ W
prevention algorithim.
! r( u/ o% I% q% rRectangular integration is used, so this function must
* W! h( ~- Q8 Sbe repeated on a consistent time basis for accurate : P/ O: a% t( |8 T- Q9 [8 t
control.
3 s+ b7 r9 D& j2 S, s: @; ^$ NRETURN VALUE The new output value for the pid loop.
- I/ ~$ E1 Z/ C9 o+ ^USAGE #include "control.h" $ \, X& o0 J: Y ~8 _3 ~5 k% x
本函数使用位置式PID计算方式,并且采取了积分饱和限制运算
# p+ k1 B1 g# l5 t2 c1 qPID计算 $ v% }( y$ ^/ x* b) q" l! J- g2 P
//------------------------6 D6 ^: I8 d# ]& s/ j
---------------------- ( G- X7 L# i7 @9 h2 A! g
* k0 `# r+ g8 X7 ?& Q: v" B D/ j) bfloat pid_calc(struct _pid *pid)
0 n6 [$ t0 J2 F6 E+ t ]{·
6 s/ J, N: J, W G( Q2 J* {int err;
% W. h' x8 d) T& ufloat pterm, dterm, result, ferror;
g: F# o( l- X/ \* u. K+ W6 M+ K$ z
// 计算偏差 6 N# W K% Y' f" o) `" V) u8 K
err = (pid->sp) - (pid->pv); U/ u; |" D# R( n6 ?( o
// 判断是否大于死区
& k' s2 [6 Y$ \( P3 X! F! Xif (abs(err) > pid->deadband)
; x: F* n- ~0 N9 A{ 9 b; z; M' {1 |7 z4 f1 A; N/ M
ferror = (float) err; //do integer to float , U5 ?, M, ]& P) Y+ a4 A# z
conversion only once 数据类型转换
q, j0 Z3 g7 U9 r/ X7 p3 d4 m4 b& ^2 ~; s
// 比例项 6 e. R! B& b( i$ A5 ?
pterm = pid->pgain * ferror;
/ V% B% v2 a& p& p6 x$ z
" \: r+ K6 C& x. `! _+ @. W+ ?if (pterm > 100 || pterm < -100)
' [ p6 c7 p9 G9 s{ 8 W9 d; B7 ?- H# f/ G5 }( U
pid->integral = 0.0;
: R% n1 Z9 l( {# H}
2 @+ I1 J9 \8 S- q* \else 9 X" C |" A5 r4 c" _
{
9 d1 _8 D; N, p# [( G" o, l0 J5 \// 积分项
2 P8 D/ p- k( D G7 _/ `pid->integral += pid->igain * ferror; * q1 j% ~2 R" H# I% d' z3 z V" l o
% k# Q5 y' D! e, k
// 输出为0--100% # f7 Q5 M- y# C+ n4 S2 E
// 如果计算结果大于100,则等于100 & I( X! x* H6 h( F i+ \
if (pid->integral > 100.0)
W( h a P1 Y- A8 r# i7 S' p{ pid->integral = 100.0; ) H* b4 i3 t9 ]$ K1 s
} ) H: {, x6 v" Z# Y6 ^
// 如果计算结果小于0.0,则等于0 5 _+ p% K0 u# ]9 U! d# H
else if (pid->integral < 0.0) / l- g- q. v$ {
pid->integral = 0.0;
) M( J" ?5 U0 o. u# a+ ?$ ?& k3 l R- @# F+ b/ O1 I
}
) A( p [6 v# s0 M. ^7 e4 B+ y' E0 [' C* j) Z# v$ j
// 微分项 ; X9 x% j# q' Q5 `7 W
dterm = ((float)(err - pid->last_error)) * pid->dgain; ' u9 U1 i7 J" X' \
9 h) L! v9 {/ O
result = pterm + pid->integral + dterm; 4 r( y- q! M4 l/ A: _* O
}
. ~; p# r7 n1 M4 J' Uelse
4 _( [+ P Z: H6 gresult = pid->integral; // 在死区范围内,保持现有输出
) t# y U. F1 Y+ F4 G% j, y2 q0 L+ j
3 O' N& i. S4 f& t' l// 保存上次偏差 / u1 D+ |* _' A9 E
pid->last_error = err; , s+ R g4 F6 L
* u( V: q# S J& M% C: m+ J3 d
// 输出PID值(0-100)
: c1 ?. _* x4 A! j7 z7 treturn (result); }
1 @2 T- j1 h. z0 u% e5 D) G5 e" z N q
//------------------------
, \2 y9 w- i6 U4 x----------------------
' L; |4 m0 A4 B& a+ x7 ivoid main(void)
* p5 x. k! c8 m. L) x{ 8 z. P8 E, Y* d# c& L/ A- U
float display_value;
, Z {, g% v7 Q$ y$ H, V3 ?3 fint count=0;
% E% ~2 n# F3 `8 c2 y7 ]* G7 H( |pid = &warm;
% x3 W$ S: ~. ]6 e2 Z' }
0 W j `% _' n. t2 v4 _3 ~% @// printf("Enter the values of Process point, Set
5 I, E! @6 _7 n& d9 V1 Ipoint, P gain, I gain, D gain \n"); 3 U% l2 _% s$ I _0 J
// scanf("%d%d%f%f%f", &process_point, &set_point, " k* F9 C; Y9 O: V% _
&p_gain, &i_gain, &d_gain); 3 R2 S- n: k' _
8 q/ S# t8 L, h) L1 `$ \( K$ g
// 初始化参数 & `! {( f' b( h' U, E) T
process_point = 30;
, L9 ^$ Z4 D. ~) b) O7 Fset_point = 40; , D; ?( u$ b+ h; I; V. `% A
p_gain = (float)(5.2);
( S' X5 J2 k9 d8 x, Q( Bi_gain = (float)(0.77); 9 [ ?' }, @7 O; K
d_gain = (float)(0.18); . @. `/ e* u4 T/ S
dead_band = 2;
$ _% T- ~1 v4 r/ E. Qintegral_val =(float)(0.01); - X' S/ N3 E5 H( {3 S/ k- g
' R# G, |/ P k! J
printf("The values of Process point, Set point, P gain,
1 z! W0 k- N+ i$ M( Z% n% JI gain, D gain \n");
4 g+ K+ T r+ O: Bprintf(" %6d %6d %4f %4f %4f\n", process_point, - m: p" m) s) |5 F8 [) b
set_point, p_gain, i_gain, d_gain);
( s% {) l; r1 E/ h, q$ I/ g, Cprintf("Enter the values of Process point\n"); ( O0 t0 ^( x; ?# v9 O
while(count<=20) + @$ H: {4 `8 F5 R, \% R
{ . \( H' G% B* G- ?
scanf("%d",&process_point); 8 m' X0 v* X4 `3 d N! y
5 S. A. _8 O3 Q# I// 设定PV,SP 值
6 ~4 E' A1 }! V) ppid_init(&warm, process_point, set_point); ; W- A/ N9 _0 B. r# M
6 i# U6 ?, n& [: a0 ~! w$ x// 初始化PID 参数值
$ u0 I; [ O ~+ N0 m% ypid_tune(&warm, p_gain,i_gain,d_gain,dead_band);
* V2 |, O2 j! J. [7 t9 ~$ V: Y# S6 E5 j
// 初始化PID 输出值
+ l f& ^+ ?- j6 h* Jpid_setinteg(&warm,0.0);
5 {- s! U2 I6 Q1 O& q4 h//pid_setinteg(&warm,30.0);
: n# i6 C' \8 F& ]3 ~5 R4 Q //Get input value for process point
R5 t. u$ C+ D) v" [: K7 |' {pid_bumpless(&warm); - u4 V4 F n2 S9 Q+ F
" \/ }4 M$ U6 A& J9 `# F8 R
// how to display output
# ?9 f6 S9 u" O! p2 R! \0 H5 \5 zdisplay_value = pid_calc(&warm);
% x/ [' G* I; [, u+ s3 L# {* x! h6 P7 B2 P5 a8 I) h) i6 M
printf("%f\n", display_value);
f5 z/ y. p# j* Q6 L) J% N//printf("\n%f%f%f%f",warm.pv,warm.sp,warm.igain,wa
0 d, p& N( [4 i# {/ crm.dgain);
+ v! K5 N" V# Y8 [2 @; @
& |- N$ @: j4 n! \1 n4 t' icount++;
' V- r o" [6 {: O9 I O# }} - @" X& j S/ t) _! z% n
}+ w8 x" p d8 n x
: I1 D2 ]& j0 ?0 g5 W! S |
|