版主
主题
回帖0
积分10609
阅读权限200
注册时间2008-11-22
最后登录1970-1-1
在线时间 小时
|
PID算法(c 语言)
% V5 i" M0 b. n. n5 ~1 {#include <stdio.h>
) D0 g+ f/ t1 V0 W+ I; ~! L0 f3 ]#include<math.h>
; u& A7 `8 X$ L3 [* M//定义PID 的结构体
. j& q3 s! }/ G& i" N3 {struct _pid ! X- q+ d0 _! l( r& T9 c
{ . R [) k( K' p" Z6 w) u
int pv; //integer that contains the process value 过, L* z5 p9 {/ }7 D8 C. p
程量 9 e. _- l' h1 K0 ]- _
int sp; //*integer that contains the set point 设8 }$ q5 u3 r8 Q! K$ J, K
定值
! f4 D* b2 m+ Sfloat integral; // 积分值 -- 偏差累计值
5 H1 T, ], @) a$ u6 H9 s/ _* gfloat pgain; 1 i& n! G) q: f t0 G4 {! S0 D' N# b
float igain; + O7 j9 v5 f2 C9 `8 m
float dgain; ; O5 B$ E k( c$ g
int deadband; //死区
/ y- w# \7 e* @- ]/ e$ Y5 Qint last_error; . Z1 V6 G, C, U) y/ T1 S, `
}; : Z" M2 J5 S8 N9 h, G
- X" E+ p; D4 d) j; [struct _pid wARM,*pid; 2 U9 K: a' F" d" S/ X
int process_point, set_point,dead_band; float p_gain, i_gain, d_gain,
7 m1 u, ^6 v6 C. C0 `8 ?9 |integral_val,new_integ;; ) a# P$ n; a+ v2 W: ^0 i5 v- a9 Z. y
( @* a; V$ p0 M1 v+ H- _//------------------------
8 t# E! S) n0 B/ q6 }---------------------- 7 C7 H I) S2 J2 k* f* B$ p
pid_init DESCRIPTION This function initializes the
1 Y( s! l" g& l. Q7 ipointers in the _pid structure to the process variable 4 L, s5 v9 @( j% K1 L
and the setpoint. *pv and *sp are integer pointers.
! }) x' l( ?: u3 I//------------------------
$ ?, x1 ]% M3 v* R4 Q: ^7 ]---------------------- 8 @8 k# D& R$ f! G n7 \ Y! @
4 C& v; V; a5 [% avoid pid_init(struct _pid *warm, int process_point,
* J- t1 t0 g3 o; O6 H8 zint set_point) & ]2 s: { O; f9 y2 ~. E2 O
{ % j/ j% m" P# z: V G. U
struct _pid *pid; 9 e I& Q6 M& j
pid = warm; 6 H, u, ?7 C5 Q2 q
pid->pv = process_point; ; M$ [ u2 A9 z, ~2 j9 F$ d% m$ E/ y
pid->sp = set_point;
+ C2 Z1 J* R' L4 {; h4 _} 9 f0 [$ Y; T0 R# W1 z' Q
$ D$ `0 {; M& u# n* L2 g4 R3 L//------------------------& x1 `7 X$ M! K' J# ^2 l
----------------------pid_tune DESCRIPTION Sets the proportional gain ' j$ A" w- J, `7 m! Y
(p_gain), integral gain (i_gain),
/ B4 s% J) ]3 ^' S! Hderivitive gain (d_gain), and the dead band (dead_band) ( m% ~0 V' ]6 L' r+ G$ X, K/ E
of a pid control structure _pid.
5 P" R" B0 @: m$ ]1 {/ p( M9 m a- o4 n, H, S2 a
设定PID参数 ---- P,I,D,死区 % U! `! n+ X( a2 I
//------------------------" q7 i ] Q, Y$ o' w5 Q
----------------------
" @6 d, K- I- @$ F# q5 ^
: e( b" e/ c' [7 V i( ovoid pid_tune(struct _pid *pid, float p_gain, float / N4 H; Y. U, g" B' ^
i_gain, float d_gain, int dead_band) 3 w# p; x! e! T g% _
{ 9 t4 P- r7 K: g, j4 F( V% u4 h
pid->pgain = p_gain; ) u3 f9 N- x/ U6 C, ]6 d
pid->igain = i_gain; , ^% j! Y9 s* X
pid->dgain = d_gain; . k3 L9 ?' L- ?, B( r/ [) ]
pid->deadband = dead_band; ) R5 V: X: k- L; l
pid->integral= integral_val; 9 e( u7 Y4 \ ]6 X" ^( r
pid->last_error=0; / O5 Y: r- ^. l. e' h7 I
} ! U, T+ b5 C9 }8 p% C! x4 Q
& i# I' D( r$ A% p8 |//------------------------
. p8 l) D3 L; m4 @9 n---------------------- pid_setinteg DESCRIPTION Set a new value for the : p8 l* U' C3 c3 l. ~5 V
integral term of the pid equation. 5 r& [% N3 |+ U, P
This is useful for setting the initial output of the
# O6 A( ^8 ` I5 ipid controller at start up.
" Y3 O7 c# B* w/ n2 o. d4 O* \! A% w7 M& {2 o8 X
设定输出初始值 % J$ y5 G) U2 U b: U$ O
//------------------------" L5 V0 V* g2 y6 b5 o; b- j' i
---------------------- & O. J; h: h S. h- G
( e' J- J: v6 x/ a; Q' e2 N9 p- ~void pid_setinteg(struct _pid *pid,float new_integ)
6 ~' l- Y& y* b4 z( h9 Y {{
# W- Z0 n& s2 n, a+ }& ?pid->integral = new_integ;
) q! F6 l' l, c- v6 Vpid->last_error = 0; : n* k9 q+ ~2 k" {: Z
} & |, }- C" d R. _9 Q) H% o
" U2 W. H; w6 r
//------------------------
! ]: ?! q$ M8 S/ ]4 f----------------------
1 t. c& q1 z; w4 L' ]9 jpid_bumpless DESCRIPTION Bumpless transfer ; ?+ q8 v3 {0 O# G9 ]
algorithim. % k% k' T2 | l. v! c: w& W7 X' j
When suddenly changing setpoints, or when restarting
! o2 r! `( S8 N$ W0 Dthe PID equation after an extended pause, - f. _+ }9 ]( |% P; W
the derivative of the equation can cause a bump in the controller output. This function will help smooth out e: N. V6 O8 \" ?
that bump.
1 C2 u& B! y7 \9 [1 ~The process value in *pv should be the updated just , s- |, D+ B; g- T+ C
before this function is used. * G9 n# _6 V2 D! J; N
0 u' s, k3 f9 l% H1 k npid_bumpless 实现无扰切换
6 S. n/ f% A. j" t' A9 m# _当突然改变设定值时,或重新启动后,将引起扰动输出。这' J$ {8 T1 R! F2 Z+ T: D& t
个函数将能实现平顺扰动, 在调用该函数之前需要先更新 PV值 # \1 B) u" N# N; H
//------------------------! k# D. Y6 F ?( F) ]
---------------------- 9 x% }: ^2 R h8 @
2 i5 A) S2 X+ Qvoid pid_bumpless(struct _pid *pid) ; q0 t/ X/ |3 d' I7 B& J5 X
{ / G) _/ q: O8 h$ V3 o1 `
pid->last_error = (pid->sp)-(pid->pv); //设定值与反馈值偏差 % D R# r. w: A2 r- W( @3 e
} 3 S. \0 B7 b1 R- L
) J( k# y- w) j" F4 w//------------------------
: S3 i5 e, h1 I& b( g4 A+ q2 u---------------------- ) m6 r1 n) H/ i
pid_calc DESCRIPTION Performs PID calculations for the ! P. S d, I' L/ X: @/ c
_pid structure *a. This function uses the positional form of the pid
; a- x, u* U# @9 c7 ~equation, and incorporates an integral windup 9 ]4 c7 U" \7 C) R
prevention algorithim. 7 n+ S" d/ m+ `) y8 l, D
Rectangular integration is used, so this function must
+ ~' e6 F: D- J5 xbe repeated on a consistent time basis for accurate % {9 @: i" `9 P2 x3 {
control. ; ~9 E; H- @6 F/ C) b
RETURN VALUE The new output value for the pid loop. 1 m3 X0 D) }/ `
USAGE #include "control.h"
0 s2 S1 k9 z! s+ H2 V" `5 o7 k本函数使用位置式PID计算方式,并且采取了积分饱和限制运算 ) y. P5 O: X+ H
PID计算 8 d4 Q: f7 x/ q4 W: b
//------------------------5 u! E* [ A* K& h3 @
---------------------- 3 i& a! W$ r" R; p; S: G
1 k$ l) E! a' ~9 [) Y, |! l9 Ofloat pid_calc(struct _pid *pid)
. e! }; ^: y5 D S{· " [+ M0 E( p; @5 O
int err; % N$ ^4 F# l |# u6 p
float pterm, dterm, result, ferror;
! _1 E' L U- f+ U3 c0 i- ]7 X
. C" C) a3 h- r! E// 计算偏差 4 U) G5 R% }) D
err = (pid->sp) - (pid->pv);
! e% L9 s _6 o. n, ? ` // 判断是否大于死区
/ a- ^7 Y+ q" d6 |! Y. Z4 `if (abs(err) > pid->deadband)
# O. s$ a5 Q( t% ~2 s{
" `8 N& {9 y% h6 @( x/ gferror = (float) err; //do integer to float
$ C5 S4 c+ I4 v# Uconversion only once 数据类型转换
4 U X/ }- l6 m% P/ M8 N' ~& n8 g: B1 J- @0 K% v
// 比例项 + L+ Y3 z2 l; H1 m4 f/ U
pterm = pid->pgain * ferror; + I1 y4 {& G4 q" y/ y" w
! s! u6 ~! W( O: i) N
if (pterm > 100 || pterm < -100) 7 u! p' b5 J" T4 K
{ : G0 a' P% @' n/ _- o% y* z( c
pid->integral = 0.0;
+ @7 ], \% Z' ?2 ]' ?4 W} ' y" ]6 m# L" w$ P, G
else
+ F3 Z+ H* m P0 N9 o; S{
2 @" `5 Y) h4 [$ `0 |% u// 积分项 7 b( W) U, p- W$ O* ]" b
pid->integral += pid->igain * ferror; 8 I$ w' d/ b/ I' L* k f0 E0 W3 p+ I
# o- t( H6 y: ^! b
// 输出为0--100%
) Y; G4 H5 B) I& T6 p1 ], w// 如果计算结果大于100,则等于100
4 U, ]" \: l( v9 v1 q9 ?5 k5 jif (pid->integral > 100.0) 0 R- Y. T4 o& X* l$ j
{ pid->integral = 100.0;
/ R! \/ R' A& v: I- Y} " [# R' \; s2 ~; s5 _8 F5 E
// 如果计算结果小于0.0,则等于0 4 m9 \" Y- \; h
else if (pid->integral < 0.0)
2 s6 H6 \- b N% T) `+ o5 E1 Rpid->integral = 0.0; ) K; Z8 F) _: u' A1 g
' u$ r% t! o5 [
}
4 U0 ?- [; X: j9 A6 S4 _# M" Z& m8 z; E& a! P
// 微分项 & g$ z: t4 Y: s& e
dterm = ((float)(err - pid->last_error)) * pid->dgain; * c1 V6 H) I& i) x+ J. @
2 D- W0 k7 X9 N9 S. ?result = pterm + pid->integral + dterm;
8 o' E5 P6 n! {: K1 ]# K} 9 f/ F! q2 a0 L' w8 K
else 8 d8 S+ d% H- X
result = pid->integral; // 在死区范围内,保持现有输出
4 _ C, u" C7 ] s. W1 R, w* ~1 l! f
9 Q% G1 L: v5 Q/ t% g' r a// 保存上次偏差 % ^& L* b" Z+ X6 T" N: N
pid->last_error = err;
) x7 H- B2 N- }* r6 m
# p; T' ^( M: }. G/ U! T// 输出PID值(0-100)
4 w. L, w# ~, w3 |3 rreturn (result); }
, I" d0 X t' M& ?* k2 V. q
, l+ p$ V. o, V7 ?" X//------------------------( Q- O9 @* Q5 g' I; w
---------------------- 9 b5 D; F' s) U' @! `
void main(void)
3 D8 a0 K% u' m! C5 [5 c! y{
3 Z1 ]' W% _- Q* I/ Gfloat display_value; % s" h0 b( q0 E! H a7 p
int count=0; 6 g6 X: W* g' [ x
pid = &warm; 1 |( O7 s4 [9 Q! R, @- d- M# K
; v) z) Y( V( A7 W2 w( x0 `; J
// printf("Enter the values of Process point, Set
* s; R. L. K2 \; K" [point, P gain, I gain, D gain \n"); ' ?& j- A- @( H& x, o4 L" z" x. d
// scanf("%d%d%f%f%f", &process_point, &set_point,
( v; [; T6 q- q- M1 N&p_gain, &i_gain, &d_gain);
" |+ B$ a( `% ]$ A/ c7 Y& o; S* a) p* X4 X9 a2 G. q
// 初始化参数 7 h8 q" x' Z9 D; g! K' y( K5 s$ j+ d
process_point = 30; 1 t- F4 n3 x& E9 U/ u
set_point = 40;
1 t1 c3 { L& S( Tp_gain = (float)(5.2); ' l T# p" j0 }8 t% y. v8 @
i_gain = (float)(0.77); 0 |! p9 d' a2 W% r& q0 @! M" {
d_gain = (float)(0.18); 9 Y8 m/ S- ~& r4 d( v/ ?, U
dead_band = 2;
2 Y3 t1 J2 w4 ^, j8 Q2 X, xintegral_val =(float)(0.01); 6 b7 D7 `3 `' w1 a, g( z
6 Z8 }( x! d) z6 r4 J9 d+ b% K/ z2 eprintf("The values of Process point, Set point, P gain, - I/ P. K0 I6 A% t4 Y9 X
I gain, D gain \n"); ! F2 B2 [# u1 b" K9 G' }: T
printf(" %6d %6d %4f %4f %4f\n", process_point, % P- s4 o, |0 w y" G* L
set_point, p_gain, i_gain, d_gain);
1 m A' k( f8 m7 b6 ?% Vprintf("Enter the values of Process point\n");
! `- q. [- D: k Pwhile(count<=20)
5 w+ I3 H, W2 D. L{ & y* g) o! E o/ ?0 r
scanf("%d",&process_point); " A* ^& a. X7 a2 e- V
( j5 f8 v- J0 P* V( P( J// 设定PV,SP 值
7 x- p- ]4 i/ s: b$ Apid_init(&warm, process_point, set_point); 3 u$ }4 w ^( X
. h3 l9 E/ r. m% p
// 初始化PID 参数值 / \' C( H3 d7 q6 |
pid_tune(&warm, p_gain,i_gain,d_gain,dead_band);
/ i! o/ i! R- k) l3 V$ R; _0 A" A# e* M1 O- J
// 初始化PID 输出值
$ ?" t( w- G* K) S# ppid_setinteg(&warm,0.0); * d* S) O. k- ~" P4 D4 V, P/ ]
//pid_setinteg(&warm,30.0);
* V6 C6 r# E& h4 l- R7 A2 H) m6 V //Get input value for process point 4 j8 Y# R. T6 L' g2 r
pid_bumpless(&warm); ) i- F9 J( h" l$ O0 @
8 N8 K) t6 @% c& B3 Y// how to display output / r) W1 v w) x6 w
display_value = pid_calc(&warm);
6 ?, j. C+ F; h( R( k7 ~. U3 Z/ A, [5 c
printf("%f\n", display_value); p; A* u9 \, |' Z; O! v
//printf("\n%f%f%f%f",warm.pv,warm.sp,warm.igain,wa3 P5 u5 _8 Y8 L
rm.dgain);
* T9 a* u" F2 m5 {7 s! `+ Z( i) j, \2 h4 Q" D! }0 s% D
count++;
; M% U4 U' z8 F' b! |$ @}
" B w; N0 Y9 w( L* f. x}8 _" E/ M2 _8 r
7 x" F# n& j4 A9 o2 _# V
|
|