GCC Code Coverage Report


Directory: ./
File: unit_tests/tests/test_pid.cpp
Date: 2025-10-03 00:57:22
Coverage Exec Excl Total
Lines: 100.0% 69 0 69
Functions: 100.0% 11 0 11
Branches: 42.2% 87 0 206
Decisions: -% 0 - 0

Line Branch Decision Exec Source
1 /*
2 * @file test_pid_auto.cpp
3 *
4 * @date Sep 29, 2019
5 * @author Andrey Belomutskiy, (c) 2012-2020
6 */
7
8 // see also idle.timingPid test
9
10 #include "pch.h"
11
12 #include "efi_pid.h"
13
14 4 TEST(util, pid) {
15 1 pid_s pidS;
16 1 pidS.pFactor = 50;
17 1 pidS.iFactor = 0.5;
18 1 pidS.dFactor = 0;
19 1 pidS.offset = 0;
20 1 pidS.minValue = 10;
21 1 pidS.maxValue = 90;
22 1 pidS.periodMs = 1;
23
24
1/1
✓ Branch 2 taken 1 time.
1 Pid pid(&pidS);
25
26
4/10
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 12 not taken.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
✓ Branch 30 taken 1 time.
✗ Branch 31 not taken.
1 ASSERT_FLOAT_EQ( 90, pid.getOutput(14, 12, 0.1)) << "getValue#90";
27
28
29
4/10
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 12 not taken.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
✓ Branch 30 taken 1 time.
✗ Branch 31 not taken.
1 ASSERT_FLOAT_EQ( 10, pid.getOutput(14, 16, 0.1)) << "getValue#10";
30
4/9
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
✓ Branch 27 taken 1 time.
✗ Branch 28 not taken.
1 ASSERT_FLOAT_EQ(10, pid.getOutput(14, 16, 1));
31
32
1/1
✓ Branch 1 taken 1 time.
1 pid.updateFactors(29, 0, 0);
33
4/9
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
✓ Branch 27 taken 1 time.
✗ Branch 28 not taken.
1 ASSERT_FLOAT_EQ(10, pid.getOutput(14, 16, 1));
34 // ASSERT_FLOAT_EQ(68, pid.getIntegration());
35
36
4/9
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
✓ Branch 27 taken 1 time.
✗ Branch 28 not taken.
1 ASSERT_FLOAT_EQ(10, pid.getOutput(14, 16, 1));
37 // ASSERT_FLOAT_EQ(0, pid.getIntegration());
38
39
4/9
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
✓ Branch 27 taken 1 time.
✗ Branch 28 not taken.
1 ASSERT_FLOAT_EQ(10, pid.getOutput(14, 16, 1));
40 // ASSERT_FLOAT_EQ(68, pid.getIntegration());
41
42
43
44 1 pidS.pFactor = 1;
45 1 pidS.iFactor = 0;
46 1 pidS.dFactor = 0;
47 1 pidS.offset = 0;
48 1 pidS.minValue = 0;
49 1 pidS.maxValue = 100;
50 1 pidS.periodMs = 1;
51
52
1/1
✓ Branch 1 taken 1 time.
1 pid.reset();
53
54
4/10
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 12 not taken.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
✓ Branch 30 taken 1 time.
✗ Branch 31 not taken.
1 ASSERT_FLOAT_EQ( 50, pid.getOutput(/*target*/50, /*input*/0)) << "target=50, input=0";
55
3/9
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 9 not taken.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
✓ Branch 27 taken 1 time.
✗ Branch 28 not taken.
1 ASSERT_FLOAT_EQ( 0, pid.iTerm) << "target=50, input=0 iTerm";
56
57
4/10
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 12 not taken.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
✓ Branch 30 taken 1 time.
✗ Branch 31 not taken.
1 ASSERT_FLOAT_EQ( 0, pid.getOutput(/*target*/50, /*input*/70)) << "target=50, input=70";
58
3/9
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 9 not taken.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
✓ Branch 27 taken 1 time.
✗ Branch 28 not taken.
1 ASSERT_FLOAT_EQ( 0, pid.iTerm) << "target=50, input=70 iTerm";
59
60
4/10
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 12 not taken.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
✓ Branch 30 taken 1 time.
✗ Branch 31 not taken.
1 ASSERT_FLOAT_EQ( 0, pid.getOutput(/*target*/50, /*input*/70)) << "target=50, input=70 #2";
61
3/9
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 9 not taken.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
✓ Branch 27 taken 1 time.
✗ Branch 28 not taken.
1 ASSERT_FLOAT_EQ( 0, pid.iTerm) << "target=50, input=70 iTerm #2";
62
63
4/10
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 12 not taken.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
✓ Branch 30 taken 1 time.
✗ Branch 31 not taken.
1 ASSERT_FLOAT_EQ( 0, pid.getOutput(/*target*/50, /*input*/50)) << "target=50, input=50";
64
3/9
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 9 not taken.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
✓ Branch 27 taken 1 time.
✗ Branch 28 not taken.
1 ASSERT_FLOAT_EQ( 0, pid.iTerm) << "target=50, input=50 iTerm";
65 }
66
67 2 static void commonPidTestParameters(pid_s * pidS) {
68 2 pidS->pFactor = 0;
69 2 pidS->iFactor = 50;
70 2 pidS->dFactor = 0;
71 2 pidS->offset = 0;
72 2 pidS->minValue = 10;
73 2 pidS->maxValue = 40;
74 2 pidS->periodMs = 1;
75 2 }
76
77 2 static void commonPidTest(Pid *pid) {
78 2 pid->iTermMax = 45;
79
80
4/10
✓ Branch 2 taken 2 times.
✓ Branch 5 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 2 times.
✗ Branch 12 not taken.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
✓ Branch 30 taken 2 times.
✗ Branch 31 not taken.
2 ASSERT_FLOAT_EQ( 12.5, pid->getOutput(/*target*/50, /*input*/0)) << "target=50, input=0 #0";
81
4/9
✓ Branch 2 taken 2 times.
✓ Branch 5 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 2 times.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
✓ Branch 27 taken 2 times.
✗ Branch 28 not taken.
2 ASSERT_FLOAT_EQ( 12.5, pid->getIntegration());
82
4/10
✓ Branch 2 taken 2 times.
✓ Branch 5 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 2 times.
✗ Branch 12 not taken.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
✓ Branch 30 taken 2 times.
✗ Branch 31 not taken.
2 ASSERT_FLOAT_EQ( 25 , pid->getOutput(/*target*/50, /*input*/0)) << "target=50, input=0 #1";
83
84
4/10
✓ Branch 2 taken 2 times.
✓ Branch 5 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 2 times.
✗ Branch 12 not taken.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
✓ Branch 30 taken 2 times.
✗ Branch 31 not taken.
2 ASSERT_FLOAT_EQ( 37.5, pid->getOutput(/*target*/50, /*input*/0)) << "target=50, input=0 #2";
85
4/9
✓ Branch 2 taken 2 times.
✓ Branch 5 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 2 times.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
✓ Branch 27 taken 2 times.
✗ Branch 28 not taken.
2 ASSERT_FLOAT_EQ( 37.5, pid->getIntegration());
86
87
4/10
✓ Branch 2 taken 2 times.
✓ Branch 5 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 2 times.
✗ Branch 12 not taken.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
✓ Branch 30 taken 2 times.
✗ Branch 31 not taken.
2 ASSERT_FLOAT_EQ( 40.0, pid->getOutput(/*target*/50, /*input*/0)) << "target=50, input=0 #3";
88
4/9
✓ Branch 2 taken 2 times.
✓ Branch 5 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 2 times.
✗ Branch 12 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
✓ Branch 27 taken 2 times.
✗ Branch 28 not taken.
2 ASSERT_FLOAT_EQ( 45, pid->getIntegration());
89 }
90
91 4 TEST(util, parallelPidLimits) {
92 1 pid_s pidS;
93 1 commonPidTestParameters(&pidS);
94
95
1/1
✓ Branch 2 taken 1 time.
1 Pid pid(&pidS);
96
1/1
✓ Branch 1 taken 1 time.
1 commonPidTest(&pid);
97 1 }
98
99 4 TEST(util, industrialPidLimits) {
100 1 pid_s pidS;
101 1 commonPidTestParameters(&pidS);
102
103
1/1
✓ Branch 2 taken 1 time.
1 PidIndustrial pid(&pidS);
104
1/1
✓ Branch 1 taken 1 time.
1 commonPidTest(&pid);
105 1 }
106
107 TEST(util, pidIndustrial) {
108 pid_s pidS;
109 pidS.pFactor = 1.0;
110 pidS.iFactor = 1.0;
111 pidS.dFactor = 1.0;
112 pidS.offset = 0;
113 pidS.minValue = 0;
114 pidS.maxValue = 100;
115 pidS.periodMs = 1;
116
117 PidIndustrial pid;
118 pid.initPidClass(&pidS);
119
120 // we want to compare with the "normal" PID controller
121 Pid pid0(&pidS);
122
123 // no additional features
124 pid.derivativeFilterLoss = 0;
125 pid.antiwindupFreq = 0;
126
127 float industValue = pid.getOutput(/*target*/1, /*input*/0);
128 // check if the first output is clamped because of large deviative
129 ASSERT_FLOAT_EQ(100.0, industValue);
130
131 // check if all output of the 'zeroed' PidIndustrial (w/o new features) is the same as our "normal" Pid
132 for (int i = 0; i < 10; i++) {
133 float normalValue = pid0.getOutput(1, 0);
134 ASSERT_FLOAT_EQ(normalValue, industValue) << "[" << i << "]";
135 industValue = pid.getOutput(1, 0);
136 }
137
138 pid.reset();
139
140 // now test the "derivative filter loss" param (some small value)
141 pid.derivativeFilterLoss = 0.01;
142
143 // now the first value is less (and not clipped!) due to the derivative filtering
144 ASSERT_FLOAT_EQ(67.671669f, pid.getOutput(1, 0));
145 // here we still have some leftovers of the initial D-term
146 ASSERT_FLOAT_EQ(45.4544487f, pid.getOutput(1, 0));
147 // but the value is quickly fading
148 ASSERT_FLOAT_EQ(30.6446342f, pid.getOutput(1, 0));
149
150 pid.reset();
151
152 // now test much stronger "derivative filter loss"
153 pid.derivativeFilterLoss = 0.1;
154
155 // now the first value is much less due to the derivative filtering
156 ASSERT_NEAR(10.5288095f, pid.getOutput(1, 0), EPS4D);
157 // here we still have some leftovers of the initial D-term
158 ASSERT_NEAR(10.0802946f, pid.getOutput(1, 0), EPS4D);
159 // but the fading is slower than with 'weaker' derivative filter above
160 ASSERT_NEAR(9.65337563f, pid.getOutput(1, 0), EPS4D);
161
162 pid.reset();
163 pid.derivativeFilterLoss = 0;
164
165 // now test "anti-windup" param
166 pid.antiwindupFreq = 0.1;
167
168 // the first value is clipped, and that's when the anti-windup comes into effect
169 ASSERT_FLOAT_EQ(100.0f, pid.getOutput(1, 0));
170 // it stores a small negative offset in the I-term to avoid it's saturation!
171 ASSERT_NEAR(-0.0455025025f, pid.getIntegration(), EPS4D);
172 // and that's why the second output is smaller then that of normal PID (=1.00999999)
173 ASSERT_NEAR(0.959497511f, pid.getOutput(1, 0), EPS4D);
174
175 }
176