Instrument Neutral Distributed Interface INDI 2.2.5
pid.cpp
Go to the documentation of this file.
1
25#include <iostream>
26#include <cmath>
27#include "pid.h"
28
29using namespace std;
30
32{
33 public:
34 PIDImpl( double dt, double max, double min, double Kp, double Kd, double Ki );
35 ~PIDImpl();
36 void setIntegratorLimits(double min, double max)
37 {
38 m_IntegratorMin = min;
39 m_IntegratorMax = max;
40 }
41 void setTau(double value)
42 {
43 m_Tau = value;
44 }
45 double calculate( double setpoint, double measurement );
46 void reset();
47 double proportionalTerm() const
48 {
49 return m_ProportionalTerm;
50 }
51 double integralTerm() const
52 {
53 return m_IntegralTerm;
54 }
55 double derivativeTerm() const
56 {
57 return m_DerivativeTerm;
58 }
59
60 void setKp(double Kp)
61 {
62 m_Kp = Kp;
63 }
64 void setKi(double Ki)
65 {
66 m_Ki = Ki;
67 }
68 void setKd(double Kd)
69 {
70 m_Kd = Kd;
71 }
72 void getGains(double &Kp, double &Ki, double &Kd) const
73 {
74 Kp = m_Kp;
75 Ki = m_Ki;
76 Kd = m_Kd;
77 }
78
79 private:
80 // Sample Time
81 double m_T {1};
82 // Derivative Low-Pass filter time constant */
83 double m_Tau {2};
84
85 // Output limits
86 double m_Max {0};
87 double m_Min {0};
88
89 // Integrator Limits
90 double m_IntegratorMin {0};
91 double m_IntegratorMax {0};
92
93 // Gains
94 double m_Kp {0};
95 double m_Kd {0};
96 double m_Ki {0};
97
98 // Controller volatile data
99 double m_PreviousError {0};
100 double m_PreviousMeasurement {0};
101
102 // Terms
103 double m_ProportionalTerm {0};
104 double m_IntegralTerm {0};
105 double m_DerivativeTerm {0};
106
107};
108
109
110PID::PID( double dt, double max, double min, double Kp, double Kd, double Ki )
111{
112 pimpl = new PIDImpl(dt, max, min, Kp, Kd, Ki);
113}
114void PID::setIntegratorLimits(double min, double max)
115{
116 pimpl->setIntegratorLimits(min, max);
117}
118void PID::setTau(double value)
119{
120 pimpl->setTau(value);
121}
122double PID::calculate( double setpoint, double pv )
123{
124 return pimpl->calculate(setpoint, pv);
125}
127{
128 pimpl->reset();
129}
131{
132 return pimpl->proportionalTerm();
133}
134double PID::integralTerm() const
135{
136 return pimpl->integralTerm();
137}
139{
140 return pimpl->derivativeTerm();
141}
142
143void PID::setKp(double Kp)
144{
145 pimpl->setKp(Kp);
146}
147void PID::setKi(double Ki)
148{
149 pimpl->setKi(Ki);
150}
151void PID::setKd(double Kd)
152{
153 pimpl->setKd(Kd);
154}
155void PID::getGains(double &Kp, double &Ki, double &Kd) const
156{
157 pimpl->getGains(Kp, Ki, Kd);
158}
159
161{
162 delete pimpl;
163}
164
165
169PIDImpl::PIDImpl( double dt, double max, double min, double Kp, double Kd, double Ki ) :
170 m_T(dt),
171 m_Max(max),
172 m_Min(min),
173 m_Kp(Kp),
174 m_Kd(Kd),
175 m_Ki(Ki)
176{
177}
178
179double PIDImpl::calculate(double setpoint, double measurement )
180{
181 // Calculate error
182 double error = setpoint - measurement;
183
184 // Proportional term
185 m_ProportionalTerm = m_Kp * error;
186
187 // Integral term (with trapezoidal integration)
188 m_IntegralTerm = m_IntegralTerm + 0.5 * m_Ki * m_T * (error + m_PreviousError);
189
190 // Clamp Integral (anti-windup for integrator limits)
191 // Check if integrator limits are actually set (different from each other)
192 if (m_IntegratorMin != m_IntegratorMax)
193 m_IntegralTerm = std::min(m_IntegratorMax, std::max(m_IntegratorMin, m_IntegralTerm));
194
195 // Derivative term (N.B. on measurement NOT error to prevent derivative kick)
196 // Low-pass filtered derivative
197 m_DerivativeTerm = -(2.0 * m_Kd * (measurement - m_PreviousMeasurement) + (2.0 * m_Tau - m_T) * m_DerivativeTerm)
198 / (2.0 * m_Tau + m_T);
199
200 // Calculate total output
201 double output = m_ProportionalTerm + m_IntegralTerm + m_DerivativeTerm;
202
203 // Clamp Output
204 double outputBeforeSaturation = output;
205 output = std::min(m_Max, std::max(m_Min, output));
206
207 // Anti-windup: Back-calculate integral if output is saturated
208 // This prevents integrator windup when output hits limits
209 if (output != outputBeforeSaturation && m_Ki != 0.0)
210 {
211 // Remove the last integral contribution that caused saturation
212 m_IntegralTerm = output - m_ProportionalTerm - m_DerivativeTerm;
213 }
214
215 // Save error and measurement for next iteration
216 m_PreviousError = error;
217 m_PreviousMeasurement = measurement;
218
219 return output;
220}
221
223{
224 m_PreviousError = 0.0;
225 m_PreviousMeasurement = 0.0;
226 m_IntegralTerm = 0.0;
227 m_DerivativeTerm = 0.0;
228 m_ProportionalTerm = 0.0;
229}
230
double calculate(double setpoint, double measurement)
Definition pid.cpp:179
void setIntegratorLimits(double min, double max)
Definition pid.cpp:36
double proportionalTerm() const
Definition pid.cpp:47
void getGains(double &Kp, double &Ki, double &Kd) const
Definition pid.cpp:72
void setTau(double value)
Definition pid.cpp:41
void setKi(double Ki)
Definition pid.cpp:64
~PIDImpl()
Definition pid.cpp:231
void setKp(double Kp)
Definition pid.cpp:60
PIDImpl(double dt, double max, double min, double Kp, double Kd, double Ki)
Definition pid.cpp:169
double derivativeTerm() const
Definition pid.cpp:55
void setKd(double Kd)
Definition pid.cpp:68
void reset()
Definition pid.cpp:222
double integralTerm() const
Definition pid.cpp:51
double derivativeTerm() const
Definition pid.cpp:138
double integralTerm() const
Definition pid.cpp:134
void getGains(double &Kp, double &Ki, double &Kd) const
Definition pid.cpp:155
PID(double dt, double max, double min, double Kp, double Kd, double Ki)
Definition pid.cpp:110
void setTau(double value)
Definition pid.cpp:118
void setKd(double Kd)
Definition pid.cpp:151
double proportionalTerm() const
Definition pid.cpp:130
~PID()
Definition pid.cpp:160
void setKi(double Ki)
Definition pid.cpp:147
double calculate(double setpoint, double pv)
Definition pid.cpp:122
void setKp(double Kp)
Definition pid.cpp:143
void setIntegratorLimits(double min, double max)
Definition pid.cpp:114
void reset()
Definition pid.cpp:126
double max(void)
#define min(a, b)