版主
主题
回帖0
积分10609
阅读权限200
注册时间2008-11-22
最后登录1970-1-1
在线时间 小时
|
PID算法(c 语言)
, p3 g9 x4 l( B6 @#include <stdio.h> % y9 |+ r7 P/ ]
#include<math.h> , k8 Z; O. @$ d# _- {! {# I
//定义PID 的结构体
& q: I5 @! o- ?3 Tstruct _pid
: y7 P! N& t* m+ k) H9 Q9 z+ E9 ^{ ) R, G- d; E2 \& t. v8 G
int pv; //integer that contains the process value 过 S0 `, a) ?7 q$ T/ e2 l' z
程量 0 u0 W2 R+ C# u* G0 H9 l5 g1 r, Z& Q
int sp; //*integer that contains the set point 设
0 C* l. A; U: \, o定值
* Y1 L% ~' m0 A$ Efloat integral; // 积分值 -- 偏差累计值
$ Z* S0 W8 }- q8 t) afloat pgain; # y6 g2 c# L: i$ b, J% A8 z
float igain;
; ]' {! r$ P: D5 Afloat dgain;
2 o6 E# w g2 [$ q* W4 I' ]9 fint deadband; //死区 9 u: p0 q3 b( e$ d8 W2 S' b/ L
int last_error; : N5 V# a# o- o5 E
};
% U' P' U. d* d- K
( K( x2 U7 \0 } j2 Istruct _pid warm,*pid; 4 i, L( H: v+ J; y) |* L
int process_point, set_point,dead_band; float p_gain, i_gain, d_gain,
. A) d3 U3 F$ V! u8 V7 gintegral_val,new_integ;;
; u% Y5 I: F) a# T g' _) s4 i1 \' F4 p, V) x7 a5 `$ v
//------------------------
8 Q9 t) M/ T! {" \! a; w3 g----------------------
1 |$ {7 O' u1 i5 l% s6 ^pid_init DESCRIPTION This function initializes the
! c' x2 K2 o0 q, j+ b0 J! Gpointers in the _pid structure to the process variable
' Y8 l5 I& r. P7 X7 ~9 Dand the setpoint. *pv and *sp are integer pointers. 9 X. G+ f- R. A
//------------------------
& L; [! R" R3 |0 o---------------------- 4 }( a# m9 H; v
2 Q6 |. k7 K ]' X
void pid_init(struct _pid *warm, int process_point,
! b+ r2 w. T$ I Gint set_point) ( c7 V9 S6 u8 ^, O0 }
{
6 f% B: n" {- Z) C' C7 g: @struct _pid *pid; # c5 e7 p. S, S- t, @4 t. h/ K
pid = warm;
) j; j2 y6 |) Q( tpid->pv = process_point;
' T8 F# z! a! j ?pid->sp = set_point;
! y7 U& s8 c: ~! X2 U} 3 v. T, k! e$ e# `
4 Q+ v5 i( q9 A
//------------------------ f# n' |) p" p# A0 `
----------------------pid_tune DESCRIPTION Sets the proportional gain
3 V9 O7 s" L6 W- [* B3 t- G(p_gain), integral gain (i_gain),
, T2 P+ \. H1 `derivitive gain (d_gain), and the dead band (dead_band)
' n9 h& M8 ~( R' `. c% N& Kof a pid control structure _pid. 8 ^ Q# T7 ^: C! J
: j% [. \4 j0 o& }0 A
设定PID参数 ---- P,I,D,死区 % P7 u+ \3 A' F0 v8 r7 _
//------------------------( K1 _5 Q3 _7 z! g2 L9 G* I. c/ u$ b
----------------------
6 g4 I* B, b; T! G: J U9 G1 N1 \1 y! z. G- g$ y! W1 A: a
void pid_tune(struct _pid *pid, float p_gain, float / S/ _2 |4 D2 F X; i0 W
i_gain, float d_gain, int dead_band) $ U7 a: q5 Q% ]" K* f1 F4 b# X
{
0 C+ ~$ Y: d( p- L! h# z* Z$ x+ Q4 J. mpid->pgain = p_gain; 1 f8 N, D+ t [3 k# K: Q5 F- q. C, o
pid->igain = i_gain; * r: o/ c6 p& V: Q. h% c6 P
pid->dgain = d_gain;
, E! W3 Q" _% C- wpid->deadband = dead_band; ) \ s4 }8 L5 ~5 J8 P8 M
pid->integral= integral_val; 3 T3 U; f) P/ z
pid->last_error=0; * ]( n% K) Q$ c5 p
}
3 F+ k6 j$ ^+ z2 X3 B, s: Q E8 @. L) m- }3 `7 ]* b
//------------------------9 n9 u/ `$ N/ B! \- p, ~& w8 C: ~: u
---------------------- pid_setinteg DESCRIPTION Set a new value for the
; V% ]" H1 e/ N: u0 I# q) J( E' `* Y" kintegral term of the pid equation.
% c0 C# b: t" E3 X9 S7 P6 yThis is useful for setting the initial output of the ; I# G- i0 \; f; T5 N
pid controller at start up. 8 F; w/ d3 ^7 ]2 y+ E- n
8 y/ z- B* I9 ~- w) @& c设定输出初始值 ' C- g/ x5 ]0 b3 D
//------------------------
: U) Q2 d! m3 N: @---------------------- : g: K& i. Z7 W& w& p# E
" F2 T7 U! M0 Z0 @& }
void pid_setinteg(struct _pid *pid,float new_integ)
; g8 h& ^& P! N i. W% d1 y{ 4 ?* U, d' k/ R M- J3 v. `2 b
pid->integral = new_integ; ' k8 w1 Y( A% U8 c! ^, j
pid->last_error = 0; . V# z& y* d5 k) o, k
}
# O1 t$ M ]' g. r2 E# D. e: C0 u* l/ E0 b) u& }' D3 S2 U" i# G J- [! W
//------------------------
5 p! m0 z) q- m* M4 Z---------------------- $ l) L% l5 e: a+ C* A. H
pid_bumpless DESCRIPTION Bumpless transfer
. H/ v9 P& F# dalgorithim.
% {' g* ]1 {, B) y0 N1 j" OWhen suddenly changing setpoints, or when restarting ) }0 z1 s: X4 W
the PID equation after an extended pause, 8 i' p, N: n6 N9 @/ X
the derivative of the equation can cause a bump in the controller output. This function will help smooth out % ~: m; h; Y; v
that bump.
4 s3 ` O- ~0 }9 e( e ^8 QThe process value in *pv should be the updated just / N; W0 x8 q* ?/ [/ f+ f
before this function is used.
]/ Y9 v. n* v4 H8 s% _+ y7 K( b( o; m- H1 R
pid_bumpless 实现无扰切换
4 }' A& z1 k% g9 q当突然改变设定值时,或重新启动后,将引起扰动输出。这
9 y% u( O1 f" X- K) O, H" s O% _个函数将能实现平顺扰动, 在调用该函数之前需要先更新 PV值
( v4 _: }6 i* g3 _9 u//------------------------. k! N l, a, {4 E% s
---------------------- : n2 H k' `8 R: N$ ?; l+ d9 S0 B
: n$ E3 ?& O" h3 h, w' P% Jvoid pid_bumpless(struct _pid *pid) 7 a+ A0 G' W7 O5 G
{ / E( S- `. ?! ^
pid->last_error = (pid->sp)-(pid->pv); //设定值与反馈值偏差 7 f( j- f& G; \ B
} ; X6 ~7 I8 C/ u' M: A4 |
' { g* e6 E6 o( A
//------------------------
6 b6 _0 E( T& W7 v---------------------- 5 R% \- `) N: x* k2 r' V
pid_calc DESCRIPTION Performs PID calculations for the
/ f" G; B8 q% F/ k_pid structure *a. This function uses the positional form of the pid " z& D( ~' f. w8 D+ W( ^1 d
equation, and incorporates an integral windup
; v3 U; z! D* r# s" g+ Y# _3 kprevention algorithim. + o* \0 Y/ l/ N* L
Rectangular integration is used, so this function must . H7 g/ A! ~1 L" C6 ]! f
be repeated on a consistent time basis for accurate
8 ]7 O% W) |. F2 H7 `9 Ncontrol.
, U/ o& {2 D+ `) W2 \1 C1 nRETURN VALUE The new output value for the pid loop. 3 {1 c) q, K: Q' u6 ^
USAGE #include "control.h" & s/ G# b, f$ J- L& F1 K* u% }) T- f# L8 y
本函数使用位置式PID计算方式,并且采取了积分饱和限制运算
' n# I! Q8 j8 H& q' n vPID计算 9 I' ^2 h f* a" r5 p
//------------------------
# M% X0 h' N' B. I5 @---------------------- " |+ n" S5 v3 B- \6 X
p6 ~: y9 [& }6 u, H# ~9 y1 ~float pid_calc(struct _pid *pid)
6 ?6 O; j: ~7 s+ \$ {7 ?( v{· 6 x* Q) U+ K0 `0 ~
int err; / E3 T! [, A$ q* _/ n/ m
float pterm, dterm, result, ferror; 1 ~" m# y: _8 W* `5 |
: f0 s- _ _% I/ ? R9 j// 计算偏差 ) f, j( f/ s' d
err = (pid->sp) - (pid->pv);
1 S$ t3 Q" B5 d1 ~" M // 判断是否大于死区
: L7 p& p0 N+ r* oif (abs(err) > pid->deadband) 7 J$ ^% s) i( Z \9 P- S
{ 1 p- O$ v: R6 b' _. q6 w& x3 |8 H
ferror = (float) err; //do integer to float
7 _8 U2 C* j- t4 p9 S# xconversion only once 数据类型转换 6 `1 r; A f2 y4 R
+ j- U1 [/ I/ U8 b
// 比例项 7 y+ d6 n' v4 ~/ S" _, k
pterm = pid->pgain * ferror; " Q8 x# I1 c; s' v/ P/ e. h
, k6 ?/ d. O" x) C: o [
if (pterm > 100 || pterm < -100)
( H) C! H/ z- I{
7 v# {4 V/ f# E& ~% d( Opid->integral = 0.0;
' _4 w9 s4 Z' a* @# k} & {3 L' x: }6 B# U8 {
else
! W4 G! c R# s8 M{
0 b( b5 [$ Q5 S6 d, ~ d5 v// 积分项 4 c, N4 }3 g. x# ~) Q
pid->integral += pid->igain * ferror; 1 G6 \5 ~4 V q& t7 a- J
, X1 R/ E5 ^7 |! n$ G// 输出为0--100%
) A5 i: M3 F& a$ A/ ^% M' q+ N c// 如果计算结果大于100,则等于100
: ?2 y6 H" a/ ~; e/ [1 V0 vif (pid->integral > 100.0) 0 j) O, _. e ]9 Z* ?: Q& F# {
{ pid->integral = 100.0;
/ k( j) b( o( ]. a( d# n5 r( N m} 6 ^. h7 W9 w ]% j+ w P) Z
// 如果计算结果小于0.0,则等于0
* K- c( [ y9 Q5 C, Z, Qelse if (pid->integral < 0.0) ( l% i( x% v& j
pid->integral = 0.0;
0 X8 }+ p& j# A+ r* K1 R2 u. \& C! y4 s# {# f8 e: U# j5 h7 a3 O: I
}
4 s8 t! {2 {8 \/ Y: Z: W+ e+ @9 G2 v: f5 |( x1 E1 E
// 微分项 + ?. u1 ]! A/ N( T
dterm = ((float)(err - pid->last_error)) * pid->dgain;
$ n7 I7 V. y+ c8 }
2 N7 g- I0 z( A; d( L' o' p% hresult = pterm + pid->integral + dterm;
. h; m/ g8 E) u6 u' O. a}
3 x0 {* |* i( U: E3 Q( zelse
' Q$ Q' E2 v0 n% h* dresult = pid->integral; // 在死区范围内,保持现有输出 7 b3 p% b7 I/ Z2 ?+ {0 d
9 R/ }( c& R% ^! b9 F% Y% f( g
// 保存上次偏差
6 C% F! o b7 ~5 Y# wpid->last_error = err; . c6 o/ k* N* Z- _ i% t* c. A5 ]
& j7 G7 k5 E, {- O/ G# y5 X3 h0 {// 输出PID值(0-100)
/ {# N3 b, g2 J* V, ~7 ^" x$ ireturn (result); }
& F1 x0 ^$ d' r4 ]6 p4 f |; n$ R" x/ g r/ R
//------------------------: c$ ?$ z7 q3 E
----------------------
$ c3 d# e* g' evoid main(void) ! e8 ^$ j& j3 o9 d
{
! a8 }9 j% o5 C) `8 `2 p! e0 b( bfloat display_value; 7 ?4 w0 R* e: X- h
int count=0; 7 a9 f1 E7 ~) r# K
pid = &warm; 3 k+ N# A2 b8 }- m4 z2 ^9 C
0 V" a+ Z/ Z+ r5 Z/ s- d+ Q// printf("Enter the values of Process point, Set
. q3 u# e4 \' G4 e0 K8 ~point, P gain, I gain, D gain \n"); " P) L: a, c- X! t' j1 \% |2 i+ d
// scanf("%d%d%f%f%f", &process_point, &set_point, 9 M' A% T4 o# v j0 L* s; G3 c
&p_gain, &i_gain, &d_gain); 4 k V3 V; ^; H6 O! S: T% }
3 M+ a1 v) o8 {1 ], C1 F6 C G, \
// 初始化参数 / x0 E8 O* E; w4 s( x, a& A* T
process_point = 30; 0 o: t/ t7 o: E
set_point = 40;
: Z3 X, [! {+ |: Zp_gain = (float)(5.2); " J1 w R3 U! `& D# \% E
i_gain = (float)(0.77);
. M/ i& R: V+ B9 V; o4 hd_gain = (float)(0.18); , d# k! z0 n f0 Y) ]& ?
dead_band = 2;
" C, b! B: v( Y6 j1 sintegral_val =(float)(0.01);
4 b$ E4 C( R" ?" l+ ?
4 J( W. K# w {printf("The values of Process point, Set point, P gain, - `9 D. I5 R1 T
I gain, D gain \n");
( j- E: e" }3 s. r! o7 Eprintf(" %6d %6d %4f %4f %4f\n", process_point, & [* N) g0 N Q5 x( s
set_point, p_gain, i_gain, d_gain);
. }, Y( e8 I$ F8 J, t1 H. hprintf("Enter the values of Process point\n");
! m$ ?, r: d% O% iwhile(count<=20)
0 t% D: Q& u- |2 l$ g2 d& U{
; i/ T. u4 L( C! q1 Ascanf("%d",&process_point); , a$ p' i: W& d4 A/ b
. ~8 ?. a2 U G. @& I: B; b// 设定PV,SP 值 ( l; k h- q. d
pid_init(&warm, process_point, set_point); + P- |/ \: d; Z+ H
/ h! |8 W6 n# d0 ~# C2 T
// 初始化PID 参数值
) O; | i8 e) _% ?# y% ^& }pid_tune(&warm, p_gain,i_gain,d_gain,dead_band); 6 b2 m' Q C r/ y: h- x c
7 p/ g8 R4 g8 o6 |& Z9 q5 X// 初始化PID 输出值 9 m( M) B7 T- B" D
pid_setinteg(&warm,0.0);
4 U1 o5 y2 C5 g0 z6 S0 x' M5 i//pid_setinteg(&warm,30.0); 2 Y! @9 F" O. b% W0 @$ E
//Get input value for process point D- k2 G7 f- \9 D3 ?
pid_bumpless(&warm); 2 ]5 a* P8 X, v1 ^, O8 C3 ?
$ H9 E9 J0 ?5 h9 t8 R; N& S5 ^// how to display output ; }$ @" i7 q' a! [: u) A4 ]
display_value = pid_calc(&warm); g1 M& M0 _) Y* v
5 h& Q" B% c& W4 _) L
printf("%f\n", display_value); ( Q* B* G7 e4 k& k7 B9 U. ~: d
//printf("\n%f%f%f%f",warm.pv,warm.sp,warm.igain,wa
3 Z, F6 G! v* }rm.dgain);
/ z6 ?$ }5 O8 s
, C' d0 _; A& a3 ]2 Ucount++; 9 a% F# B: y5 f4 h8 {
}
: r( X0 Z9 \( [/ b5 M9 J- N2 @. x4 ]}
/ f0 `+ j3 }1 r& R7 }! M/ ?0 O6 S- G3 n9 K" U6 W. A4 r' V
|
|