blob: 49e0ef6a9db85f90fe82967dce6b3ab20d21807b [file] [log] [blame]
Josh Lehan31058fd2023-01-13 11:06:16 -08001#include "conf.hpp"
Patrick Ventureda4a5dd2018-08-31 09:42:48 -07002#include "pid/ec/pid.hpp"
Ed Tanousf8b6e552025-06-27 13:27:50 -07003#include "pid/pidcontroller.hpp"
Patrick Venture3349ef22018-06-12 14:09:29 -07004#include "pid/thermalcontroller.hpp"
Patrick Ventureda4a5dd2018-08-31 09:42:48 -07005#include "test/zone_mock.hpp"
Patrick Venture3349ef22018-06-12 14:09:29 -07006
Ed Tanousf8b6e552025-06-27 13:27:50 -07007#include <exception>
8#include <memory>
Patrick Venture3349ef22018-06-12 14:09:29 -07009#include <string>
10#include <vector>
11
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070012#include <gmock/gmock.h>
13#include <gtest/gtest.h>
Patrick Venture3349ef22018-06-12 14:09:29 -070014
Patrick Venturea0764872020-08-08 07:48:43 -070015namespace pid_control
16{
17namespace
18{
19
James Feist572c43d2019-01-31 15:52:22 -080020using ::testing::_;
Patrick Venture3349ef22018-06-12 14:09:29 -070021using ::testing::Return;
22using ::testing::StrEq;
23
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070024TEST(ThermalControllerTest, BoringFactoryTest)
25{
Patrick Venture3349ef22018-06-12 14:09:29 -070026 // Verifies building a ThermalPIDController with the factory works as
27 // expected in the boring (uninteresting) case.
28
29 ZoneMock z;
30
Josh Lehan31058fd2023-01-13 11:06:16 -080031 std::vector<pid_control::conf::SensorInput> inputs = {{"fleeting0"}};
Patrick Venture5f59c0f2018-11-11 12:55:14 -080032 double setpoint = 10.0;
Patrick Venture3349ef22018-06-12 14:09:29 -070033 ec::pidinfo initial;
34
Patrick Venture563a3562018-10-30 09:31:26 -070035 std::unique_ptr<PIDController> p = ThermalController::createThermalPid(
James Feist734f9532018-11-15 12:13:18 -080036 &z, "therm1", inputs, setpoint, initial, ThermalType::margin);
Patrick Venture3349ef22018-06-12 14:09:29 -070037 // Success
38 EXPECT_FALSE(p == nullptr);
39}
40
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070041TEST(ThermalControllerTest, VerifyFactoryFailsWithZeroInputs)
42{
Patrick Venture3349ef22018-06-12 14:09:29 -070043 // A thermal controller needs at least one input.
44
45 ZoneMock z;
46
Josh Lehan31058fd2023-01-13 11:06:16 -080047 std::vector<pid_control::conf::SensorInput> inputs = {};
Patrick Venture5f59c0f2018-11-11 12:55:14 -080048 double setpoint = 10.0;
Patrick Venture3349ef22018-06-12 14:09:29 -070049 ec::pidinfo initial;
James Feist734f9532018-11-15 12:13:18 -080050 std::unique_ptr<PIDController> p;
51 EXPECT_THROW(
52 {
53 p = ThermalController::createThermalPid(
54 &z, "therm1", inputs, setpoint, initial, ThermalType::margin);
55 },
56 std::exception);
Patrick Venture3349ef22018-06-12 14:09:29 -070057 EXPECT_TRUE(p == nullptr);
58}
59
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070060TEST(ThermalControllerTest, InputProc_BehavesAsExpected)
61{
Patrick Venture563a3562018-10-30 09:31:26 -070062 // This test just verifies inputProc behaves as expected.
Patrick Venture3349ef22018-06-12 14:09:29 -070063
64 ZoneMock z;
65
Josh Lehan31058fd2023-01-13 11:06:16 -080066 std::vector<pid_control::conf::SensorInput> inputs = {{"fleeting0"}};
Patrick Venture5f59c0f2018-11-11 12:55:14 -080067 double setpoint = 10.0;
Patrick Venture3349ef22018-06-12 14:09:29 -070068 ec::pidinfo initial;
69
Patrick Venture563a3562018-10-30 09:31:26 -070070 std::unique_ptr<PIDController> p = ThermalController::createThermalPid(
James Feist734f9532018-11-15 12:13:18 -080071 &z, "therm1", inputs, setpoint, initial, ThermalType::margin);
Patrick Venture3349ef22018-06-12 14:09:29 -070072 EXPECT_FALSE(p == nullptr);
73
74 EXPECT_CALL(z, getCachedValue(StrEq("fleeting0"))).WillOnce(Return(5.0));
75
Patrick Venture563a3562018-10-30 09:31:26 -070076 EXPECT_EQ(5.0, p->inputProc());
Patrick Venture3349ef22018-06-12 14:09:29 -070077}
78
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070079TEST(ThermalControllerTest, SetPtProc_BehavesAsExpected)
80{
Patrick Venture563a3562018-10-30 09:31:26 -070081 // This test just verifies inputProc behaves as expected.
Patrick Venture3349ef22018-06-12 14:09:29 -070082
83 ZoneMock z;
84
Josh Lehan31058fd2023-01-13 11:06:16 -080085 std::vector<pid_control::conf::SensorInput> inputs = {{"fleeting0"}};
Patrick Venture5f59c0f2018-11-11 12:55:14 -080086 double setpoint = 10.0;
Patrick Venture3349ef22018-06-12 14:09:29 -070087 ec::pidinfo initial;
88
Patrick Venture563a3562018-10-30 09:31:26 -070089 std::unique_ptr<PIDController> p = ThermalController::createThermalPid(
James Feist734f9532018-11-15 12:13:18 -080090 &z, "therm1", inputs, setpoint, initial, ThermalType::margin);
Patrick Venture3349ef22018-06-12 14:09:29 -070091 EXPECT_FALSE(p == nullptr);
92
Patrick Venture563a3562018-10-30 09:31:26 -070093 EXPECT_EQ(setpoint, p->setptProc());
Patrick Venture3349ef22018-06-12 14:09:29 -070094}
95
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070096TEST(ThermalControllerTest, OutputProc_BehavesAsExpected)
97{
James Feist734f9532018-11-15 12:13:18 -080098 // This test just verifies outputProc behaves as expected.
Patrick Venture3349ef22018-06-12 14:09:29 -070099
100 ZoneMock z;
101
Josh Lehan31058fd2023-01-13 11:06:16 -0800102 std::vector<pid_control::conf::SensorInput> inputs = {{"fleeting0"}};
Patrick Venture5f59c0f2018-11-11 12:55:14 -0800103 double setpoint = 10.0;
Patrick Venture3349ef22018-06-12 14:09:29 -0700104 ec::pidinfo initial;
105
Patrick Venture563a3562018-10-30 09:31:26 -0700106 std::unique_ptr<PIDController> p = ThermalController::createThermalPid(
James Feist734f9532018-11-15 12:13:18 -0800107 &z, "therm1", inputs, setpoint, initial, ThermalType::margin);
Patrick Venture3349ef22018-06-12 14:09:29 -0700108 EXPECT_FALSE(p == nullptr);
109
Patrick Venture5f59c0f2018-11-11 12:55:14 -0800110 double value = 90.0;
Nirav Shahccc8bb62022-02-17 21:06:51 -0800111 EXPECT_CALL(z, addSetPoint(value, "therm1"));
Patrick Venture3349ef22018-06-12 14:09:29 -0700112
Patrick Venture563a3562018-10-30 09:31:26 -0700113 p->outputProc(value);
Patrick Venture3349ef22018-06-12 14:09:29 -0700114}
James Feist734f9532018-11-15 12:13:18 -0800115
116TEST(ThermalControllerTest, InputProc_MultipleInputsAbsolute)
117{
118 // This test verifies inputProc behaves as expected with multiple absolute
119 // inputs.
120
121 ZoneMock z;
122
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400123 std::vector<pid_control::conf::SensorInput> inputs = {
124 {"fleeting0"}, {"fleeting1"}};
James Feist734f9532018-11-15 12:13:18 -0800125 double setpoint = 10.0;
126 ec::pidinfo initial;
127
128 std::unique_ptr<PIDController> p = ThermalController::createThermalPid(
129 &z, "therm1", inputs, setpoint, initial, ThermalType::absolute);
130 EXPECT_FALSE(p == nullptr);
131
132 EXPECT_CALL(z, getCachedValue(StrEq("fleeting0"))).WillOnce(Return(5.0));
133 EXPECT_CALL(z, getCachedValue(StrEq("fleeting1"))).WillOnce(Return(10.0));
134
135 EXPECT_EQ(10.0, p->inputProc());
136}
137
138TEST(ThermalControllerTest, InputProc_MultipleInputsMargin)
139{
140 // This test verifies inputProc behaves as expected with multiple margin
141 // inputs.
142
143 ZoneMock z;
144
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400145 std::vector<pid_control::conf::SensorInput> inputs = {
146 {"fleeting0"}, {"fleeting1"}};
James Feist734f9532018-11-15 12:13:18 -0800147 double setpoint = 10.0;
148 ec::pidinfo initial;
149
150 std::unique_ptr<PIDController> p = ThermalController::createThermalPid(
151 &z, "therm1", inputs, setpoint, initial, ThermalType::margin);
152 EXPECT_FALSE(p == nullptr);
153
154 EXPECT_CALL(z, getCachedValue(StrEq("fleeting0"))).WillOnce(Return(5.0));
155 EXPECT_CALL(z, getCachedValue(StrEq("fleeting1"))).WillOnce(Return(10.0));
156
157 EXPECT_EQ(5.0, p->inputProc());
James Feist572c43d2019-01-31 15:52:22 -0800158}
159
Josh Lehan23e22b92022-11-12 22:37:58 -0800160TEST(ThermalControllerTest, InputProc_MultipleInputsSummation)
161{
162 // This test verifies inputProc behaves as expected with multiple summation
163 // inputs.
164
165 ZoneMock z;
166
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400167 std::vector<pid_control::conf::SensorInput> inputs = {
168 {"fleeting0"}, {"fleeting1"}};
Josh Lehan23e22b92022-11-12 22:37:58 -0800169 double setpoint = 10.0;
170 ec::pidinfo initial;
171
172 std::unique_ptr<PIDController> p = ThermalController::createThermalPid(
173 &z, "therm1", inputs, setpoint, initial, ThermalType::summation);
174 EXPECT_FALSE(p == nullptr);
175
176 EXPECT_CALL(z, getCachedValue(StrEq("fleeting0"))).WillOnce(Return(5.0));
177 EXPECT_CALL(z, getCachedValue(StrEq("fleeting1"))).WillOnce(Return(10.0));
178
179 EXPECT_EQ(15.0, p->inputProc());
180}
181
Josh Lehan31058fd2023-01-13 11:06:16 -0800182TEST(ThermalControllerTest, InputProc_MultipleInputsTempToMargin)
183{
184 // This test verifies inputProc behaves as expected with multiple margin
185 // inputs and TempToMargin in use.
186
187 ZoneMock z;
188
189 std::vector<pid_control::conf::SensorInput> inputs = {
190 {"absolute0", 85.0, true}, {"margin1"}};
191 double setpoint = 10.0;
192 ec::pidinfo initial;
193
194 std::unique_ptr<PIDController> p = ThermalController::createThermalPid(
195 &z, "therm1", inputs, setpoint, initial, ThermalType::margin);
196 EXPECT_FALSE(p == nullptr);
197
198 EXPECT_CALL(z, getCachedValue(StrEq("absolute0"))).WillOnce(Return(82.0));
199 EXPECT_CALL(z, getCachedValue(StrEq("margin1"))).WillOnce(Return(5.0));
200
201 // 82 degrees temp, 85 degrees Tjmax => 3 degrees of safety margin
202 EXPECT_EQ(3.0, p->inputProc());
203}
204
James Feist572c43d2019-01-31 15:52:22 -0800205TEST(ThermalControllerTest, NegHysteresis_BehavesAsExpected)
206{
James Feist572c43d2019-01-31 15:52:22 -0800207 // This test verifies Negative hysteresis behaves as expected by
208 // crossing the setpoint and noticing readings don't change until past the
209 // hysteresis value
210
211 ZoneMock z;
212
Josh Lehan31058fd2023-01-13 11:06:16 -0800213 std::vector<pid_control::conf::SensorInput> inputs = {{"fleeting0"}};
James Feist572c43d2019-01-31 15:52:22 -0800214 double setpoint = 10.0;
215 ec::pidinfo initial;
Delphine CC Chiu97889632023-11-06 11:32:46 +0800216 initial.checkHysterWithSetpt = false;
James Feist572c43d2019-01-31 15:52:22 -0800217 initial.negativeHysteresis = 4.0;
218
219 std::unique_ptr<PIDController> p = ThermalController::createThermalPid(
220 &z, "therm1", inputs, setpoint, initial, ThermalType::margin);
221 EXPECT_FALSE(p == nullptr);
222
223 EXPECT_CALL(z, getCachedValue(StrEq("fleeting0")))
224 .Times(3)
225 .WillOnce(Return(12.0))
226 .WillOnce(Return(9.0))
227 .WillOnce(Return(7.0));
228
Nirav Shahccc8bb62022-02-17 21:06:51 -0800229 EXPECT_CALL(z, addSetPoint(_, "therm1")).Times(3);
James Feist572c43d2019-01-31 15:52:22 -0800230
231 std::vector<double> lastReadings = {12.0, 12.0, 7.0};
232 for (auto& reading : lastReadings)
233 {
234 p->process();
235 EXPECT_EQ(p->getLastInput(), reading);
236 }
237}
238
239TEST(ThermalControllerTest, PosHysteresis_BehavesAsExpected)
240{
241 // This test verifies Positive hysteresis behaves as expected by
242 // crossing the setpoint and noticing readings don't change until past the
243 // hysteresis value
244
245 ZoneMock z;
246
Josh Lehan31058fd2023-01-13 11:06:16 -0800247 std::vector<pid_control::conf::SensorInput> inputs = {{"fleeting0"}};
James Feist572c43d2019-01-31 15:52:22 -0800248 double setpoint = 10.0;
249 ec::pidinfo initial;
Delphine CC Chiu97889632023-11-06 11:32:46 +0800250 initial.checkHysterWithSetpt = false;
James Feist572c43d2019-01-31 15:52:22 -0800251 initial.positiveHysteresis = 5.0;
252
253 std::unique_ptr<PIDController> p = ThermalController::createThermalPid(
254 &z, "therm1", inputs, setpoint, initial, ThermalType::margin);
255 EXPECT_FALSE(p == nullptr);
256
257 EXPECT_CALL(z, getCachedValue(StrEq("fleeting0")))
258 .Times(3)
259 .WillOnce(Return(8.0))
260 .WillOnce(Return(13.0))
261 .WillOnce(Return(14.0));
262
Nirav Shahccc8bb62022-02-17 21:06:51 -0800263 EXPECT_CALL(z, addSetPoint(_, "therm1")).Times(3);
James Feist572c43d2019-01-31 15:52:22 -0800264
265 std::vector<double> lastReadings = {8.0, 8.0, 14.0};
266 for (auto& reading : lastReadings)
267 {
268 p->process();
269 EXPECT_EQ(p->getLastInput(), reading);
270 }
Patrick Venturea0764872020-08-08 07:48:43 -0700271}
272
273} // namespace
274} // namespace pid_control