Add Hysteresis to pid controllers
Add hysteresis to pid controllers to lower pwm changes.
It is defaulted to 0 so it should be transparent
to any controller that choses not to implement it.
This is the same pattern used by the stepwise controller.
Tested-by: Unit tests passed
Change-Id: Ib47114285b0017258b7f77eaf067d310f95a0c60
Signed-off-by: James Feist <james.feist@linux.intel.com>
diff --git a/pid/ec/pid.hpp b/pid/ec/pid.hpp
index 779ced5..3ab64cd 100644
--- a/pid/ec/pid.hpp
+++ b/pid/ec/pid.hpp
@@ -31,6 +31,8 @@
limits_t out_lim; // clamp of output
double slew_neg;
double slew_pos;
+ double positiveHysteresis;
+ double negativeHysteresis;
} pid_info_t;
double pid(pid_info_t* pidinfoptr, double input, double setpoint);
@@ -47,6 +49,8 @@
ec::limits_t out_lim; // clamp of output
double slew_neg;
double slew_pos;
+ double positiveHysteresis;
+ double negativeHysteresis;
};
} // namespace ec
diff --git a/pid/pidcontroller.cpp b/pid/pidcontroller.cpp
index 7be6ceb..e3eaaff 100644
--- a/pid/pidcontroller.cpp
+++ b/pid/pidcontroller.cpp
@@ -20,6 +20,7 @@
#include <algorithm>
#include <chrono>
+#include <cmath>
#include <iostream>
#include <map>
#include <memory>
@@ -38,8 +39,39 @@
// Get input value
input = inputProc();
- // Calculate new output
- output = ec::pid(getPIDInfo(), input, setpt);
+ auto info = getPIDInfo();
+
+ // if no hysteresis, maintain previous behavior
+ if (info->positiveHysteresis == 0 && info->negativeHysteresis == 0)
+ {
+ // Calculate new output
+ output = ec::pid(info, input, setpt);
+
+ // this variable isn't actually used in this context, but we're setting
+ // it here incase somebody uses it later it's the correct value
+ lastInput = input;
+ }
+ else
+ {
+ // initialize if not set yet
+ if (std::isnan(lastInput))
+ {
+ lastInput = input;
+ }
+
+ // if reading is outside of hysteresis bounds, use it for reading,
+ // otherwise use last reading without updating it first
+ else if ((input - lastInput) > info->positiveHysteresis)
+ {
+ lastInput = input;
+ }
+ else if ((lastInput - input) > info->negativeHysteresis)
+ {
+ lastInput = input;
+ }
+
+ output = ec::pid(info, lastInput, setpt);
+ }
// Output new value
outputProc(output);
diff --git a/pid/pidcontroller.hpp b/pid/pidcontroller.hpp
index 9ed3be2..3d38c2a 100644
--- a/pid/pidcontroller.hpp
+++ b/pid/pidcontroller.hpp
@@ -49,6 +49,11 @@
return &_pid_info;
}
+ double getLastInput(void)
+ {
+ return lastInput;
+ }
+
protected:
ZoneInterface* _owner;
@@ -57,4 +62,5 @@
ec::pid_info_t _pid_info;
double _setpoint;
std::string _id;
+ double lastInput = std::numeric_limits<double>::quiet_NaN();
};
diff --git a/pid/util.cpp b/pid/util.cpp
index 9d666ef..a5936b0 100644
--- a/pid/util.cpp
+++ b/pid/util.cpp
@@ -34,6 +34,8 @@
info->out_lim.max = initial.out_lim.max;
info->slew_neg = initial.slew_neg;
info->slew_pos = initial.slew_pos;
+ info->negativeHysteresis = initial.negativeHysteresis;
+ info->positiveHysteresis = initial.positiveHysteresis;
}
void dumpPIDStruct(ec::pid_info_t* info)