@@ -53,13 +53,13 @@ is plotted in the Figure below.
53
53
54
54
</center>
55
55
56
- <pre><code class="c numbered">01: // CONSTANTS:
57
- 02: #define MAX_CLIMB_SUM_ERR 100
56
+ <pre><code class="c numbered">01: // CONSTANTS:
57
+ 02: #define MAX_CLIMB_SUM_ERR 10
58
58
03: #define MAX_CLIMB 1
59
59
04:
60
60
05: #define CLOCK 16
61
61
06: #define MAX_PPRZ (CLOCK*600)
62
- 07:
62
+ 07:
63
63
08: #define CLIMB_LEVEL_GAZ 0.31
64
64
09: #define CLIMB_GAZ_OF_CLIMB 0.75
65
65
10: #define CLIMB_PITCH_OF_VZ_PGAIN 0.05
@@ -70,88 +70,99 @@ is plotted in the Figure below.
70
70
15: const float climb_pgain=CLIMB_PGAIN;
71
71
16: const float climb_igain=CLIMB_IGAIN;
72
72
17: const float nav_pitch=0;
73
- 18:
74
- 19: // 1) the target speed in vertical direction
75
- 20: float desired_climb;
76
- 21: // 2) vertical speed of the UAV, estimated by a control function
77
- 22: float estimator_z_dot;
78
- 23:
79
- 24: /** PID funciton OUTPUTS */
80
- 25: float desired_gaz;
81
- 26: float desired_pitch ;
82
- 27: // Accumulated error in the system
83
- 28: float climb_sum_err;
84
- 29:
85
- 30: /** Computes desired_gaz and desired_pitch */
86
- 31: void climb_pid_run()
87
- 32: {
88
- 33:
89
- 34: float err=estimator_z_dot-desired_climb;
90
- 35:
91
- 36: float fgaz=climb_pgain*( err+climb_igain*climb_sum_err)+CLIMB_LEVEL_GAZ+CLIMB_GAZ_OF_CLIMB* desired_climb;
92
- 37:
93
- 38: float pprz= fgaz*MAX_PPRZ ;
94
- 39: desired_gaz=((pprz>=0 && pprz<=MAX_PPRZ) ? pprz : (pprz>MAX_PPRZ ? MAX_PPRZ : 0));
95
- 40:
96
- 41: /** pitch offset for climb */
97
- 42: float pitch_of_vz=(desired_climb>0) ? desired_climb*pitch_of_vz_pgain : 0;
98
- 43: desired_pitch=nav_pitch+pitch_of_vz;
99
- 44:
100
- 45: climb_sum_err=err+climb_sum_err ;
101
- 46: if (climb_sum_err>MAX_CLIMB_SUM_ERR) climb_sum_err=MAX_CLIMB_SUM_ERR;
102
- 47: if ( climb_sum_err<-MAX_CLIMB_SUM_ERR) climb_sum_err=-MAX_CLIMB_SUM_ERR ;
103
- 48:
104
- 49: /** Estimates the vertical speed */
105
- 50: estimator_z_dot=climb_pgain * err + desired_climb;
73
+ 18:
74
+ 19: /** PID function INPUTS */
75
+ 20: // The user input: target speed in vertical direction
76
+ 21: float desired_climb;
77
+ 22: // Vertical speed of the UAV detected by GPS sensor
78
+ 23: float estimator_z_dot;
79
+ 24:
80
+ 25: /** PID function OUTPUTS */
81
+ 26: float desired_gaz ;
82
+ 27: float desired_pitch;
83
+ 28:
84
+ 29: /** The state variable: accumulated error in the control */
85
+ 30: float climb_sum_err=0;
86
+ 31:
87
+ 32: /** Computes desired_gaz and desired_pitch */
88
+ 33: void climb_pid_run()
89
+ 34: {
90
+ 35:
91
+ 36: float err=estimator_z_dot- desired_climb;
92
+ 37:
93
+ 38: float fgaz=climb_pgain*(err+climb_igain*climb_sum_err)+CLIMB_LEVEL_GAZ+CLIMB_GAZ_OF_CLIMB*desired_climb ;
94
+ 39:
95
+ 40: float pprz=fgaz*MAX_PPRZ;
96
+ 41: desired_gaz=((pprz>=0 && pprz<=MAX_PPRZ) ? pprz : (pprz>MAX_PPRZ ? MAX_PPRZ : 0));
97
+ 42:
98
+ 43: /** pitch offset for climb */
99
+ 44: float pitch_of_vz=(desired_climb>0) ? desired_climb*pitch_of_vz_pgain : 0;
100
+ 45: desired_pitch=nav_pitch+pitch_of_vz ;
101
+ 46:
102
+ 47: climb_sum_err=err+climb_sum_err ;
103
+ 48: if (climb_sum_err>MAX_CLIMB_SUM_ERR) climb_sum_err=MAX_CLIMB_SUM_ERR;
104
+ 49: if (climb_sum_err<-MAX_CLIMB_SUM_ERR) climb_sum_err=-MAX_CLIMB_SUM_ERR;
105
+ 50:
106
106
51: }
107
107
52:
108
108
53: int main()
109
109
54: {
110
- 55: /** Non-deterministic initialisation */
111
- 56: desired_climb=nondet_float();
112
- 57: estimator_z_dot=nondet_float();
113
- 58:
114
- 59: /** Range of initial values of variables */
115
- 60: __CPROVER_assume(desired_climb>=-MAX_CLIMB && desired_climb<=MAX_CLIMB);
116
- 61: __CPROVER_assume(estimator_z_dot>=-MAX_CLIMB && estimator_z_dot<=MAX_CLIMB);
117
- 62:
118
- 63: while(1)
119
- 64: {
120
- 65: climb_pid_run();
121
- 66: }
122
- 67:
123
- 68: return 0;
124
- 69: }
110
+ 55:
111
+ 56: while(1)
112
+ 57: {
113
+ 58: /** Non-deterministic input values */
114
+ 59: desired_climb=nondet_float();
115
+ 60: estimator_z_dot=nondet_float();
116
+ 61:
117
+ 62: /** Range of input values */
118
+ 63: __CPROVER_assume(desired_climb>=-MAX_CLIMB && desired_climb<=MAX_CLIMB);
119
+ 64: __CPROVER_assume(estimator_z_dot>=-MAX_CLIMB && estimator_z_dot<=MAX_CLIMB);
120
+ 65:
121
+ 66: __CPROVER_input("desired_climb", desired_climb);
122
+ 67: __CPROVER_input("estimator_z_dot", estimator_z_dot);
123
+ 68:
124
+ 69: climb_pid_run();
125
+ 70:
126
+ 71: __CPROVER_output("desired_gaz", desired_gaz);
127
+ 72: __CPROVER_output("desired_pitch", desired_pitch);
128
+ 73:
129
+ 74: }
130
+ 75:
131
+ 76: return 0;
132
+ 77: }
125
133
</code></pre>
126
134
127
135
<p class="justified">
128
136
In order to test the PID controller, we construct a main control loop,
129
- which repeatedly invokes the function <code>climb_pid_run</code> (line 65).
130
- In the beginning of the main function, the values of the desired speed <code>desired_climb</code>
131
- and the estimated speed <code>estimated_z_dot</code> are initialised non-deterministically.
132
- Subsequently, the <code>__CPROVER_assume</code> statement in lines 60 and 61 guarantees that
133
- their values are bounded within a range.
137
+ which repeatedly invokes the function <code>climb_pid_run</code> (line 69).
138
+ This PID function has two input variables: the desired speed <code>desired_climb</code>
139
+ and the estimated speed <code>estimated_z_dot</code>.
140
+ In the beginning of each loop iteration, values of the inputs are assigned non-deterministically.
141
+ Subsequently, the <code>__CPROVER_assume</code> statement in lines 63 and 64 guarantees that
142
+ both values are bounded within a valid range.
143
+ The <code>__CPROVER_input</code> and <code>__CPROVER_output</code> will help clarify the inputs
144
+ and outputs of interest for generating test suites.
134
145
</p>
135
146
136
147
<p class="justified">
137
148
To demonstrate the automatic test suite generation in CBMC,
138
- we call the following command
149
+ we call the following command and we are going to explain the command line options one by one.
139
150
</p>
140
151
141
- <pre><code>cbmc pid.c --cover mcdc --unwind 25 --trace --xml-ui
152
+ <pre><code>cbmc pid.c --cover mcdc --unwind 6 --trace --xml-ui
142
153
</code></pre>
143
154
144
155
<p class="justified">
145
156
The option <code>--cover mcdc</code> specifies the code coverage criterion.
146
- There are four conditional statements in the PID function: in line 39 , line 42 ,
147
- line 46 and line 47 .
157
+ There are four conditional statements in the PID function: in line 41 , line 44 ,
158
+ line 48 and line 49 .
148
159
To satisfy MC/DC, the test suite has to meet multiple requirements.
149
160
For instance, each conditional statement needs to evaluate to <em>true</em> and <em>false</em>.
150
- Consider the condition <code>"pprz>=0 && pprz<=MAX_PPRZ"</code> at line 39 . CBMC
161
+ Consider the condition <code>"pprz>=0 && pprz<=MAX_PPRZ"</code> in line 41 . CBMC
151
162
instruments three coverage goals to control the respective evaluated results of <code>"pprz>=0"</code> and
152
163
<code>"pprz<=MAX_PPRZ"</code>.
153
164
We list them in below and they satisfy the MC/DC rules.
154
- Note that <code>MAX_PPRZ</code> is defined as 16 * 600 at line 06 of the program.
165
+ Note that <code>MAX_PPRZ</code> is defined as 16 * 600 in line 06 of the program.
155
166
</p>
156
167
157
168
<pre>
@@ -170,21 +181,48 @@ goals at the same time. Each trace corresponds to a test case.
170
181
</p>
171
182
172
183
<p class="justified">
173
- For the example above, the following test suites are generated.
184
+ In the end, the following test suites are automatically generated for testing the PID controller.
185
+ A test suite consists of a sequence of input parameters that are
186
+ passed to the PID function <code>climb_pid_run</code> at each loop iteration.
187
+ For example, Test 1 covers the MC/DC goal with id="climb_pid_run.coverage.1".
174
188
<pre><code>Test suite:
175
- T1: desired_climb=-1.000000f, estimator_z_dot=1.000000f
176
- (goal id: climb_pid_run.coverage.1)
177
- T2: desired_climb=1.000000f, estimator_z_dot=-1.000000f
178
- (goal id: climb_pid_run.coverage.2)
179
- T3: desired_climb=0.000000f, estimator_z_dot=0.000000f
180
- (goal id: climb_pid_run.coverage.3)
189
+ Test 1.
190
+ (iteration 1) desired_climb=-1.000000f, estimator_z_dot=1.000000f
191
+
192
+ Test 2.
193
+ (iteration 1) desired_climb=-1.000000f, estimator_z_dot=1.000000f
194
+ (iteration 2) desired_climb=1.000000f, estimator_z_dot=-1.000000f
195
+
196
+ Test 3.
197
+ (iteration 1) desired_climb=0.000000f, estimator_z_dot=-1.000000f
198
+ (iteration 2) desired_climb=1.000000f, estimator_z_dot=-1.000000f
199
+
200
+ Test 4.
201
+ (iteration 1) desired_climb=1.000000f, estimator_z_dot=-1.000000f
202
+ (iteration 2) desired_climb=1.000000f, estimator_z_dot=-1.000000f
203
+ (iteration 3) desired_climb=1.000000f, estimator_z_dot=-1.000000f
204
+ (iteration 4) desired_climb=1.000000f, estimator_z_dot=-1.000000f
205
+ (iteration 5) desired_climb=0.000000f, estimator_z_dot=-1.000000f
206
+ (iteration 6) desired_climb=1.000000f, estimator_z_dot=-1.000000f
207
+
208
+ Test 5.
209
+ (iteration 1) desired_climb=-1.000000f, estimator_z_dot=1.000000f
210
+ (iteration 2) desired_climb=-1.000000f, estimator_z_dot=1.000000f
211
+ (iteration 3) desired_climb=-1.000000f, estimator_z_dot=1.000000f
212
+ (iteration 4) desired_climb=-1.000000f, estimator_z_dot=1.000000f
213
+ (iteration 5) desired_climb=-1.000000f, estimator_z_dot=1.000000f
214
+ (iteration 6) desired_climb=-1.000000f, estimator_z_dot=1.000000f
181
215
</code></pre>
182
216
</p>
183
217
184
218
<p class="justified">
185
- The option <code>--unwind 25</code> unwinds the loop inside the main
186
- function body 25 times. The number of the unwinding operation is
187
- adjustable, and an introduction to the use of loop unwinding can be found
219
+ The option <code>--unwind 6</code> unwinds the loop inside the main
220
+ function body six times. In order to achieve the complete coverage on all the instrumented goals
221
+ in the PID function <code>climb_pid_run</code>, the loop must be unwound sufficient enough times.
222
+ For example, <code>climb_pid_run</code> needs to be called at least six times for evaluating the
223
+ condition <code>climb_sum_err>MAX_CLIMB_SUM_ERR</code> in line 48 to <em>true</em>.
224
+ This corresponds to the Test 5.
225
+ An introduction to the use of loop unwinding can be found
188
226
in <a href="cbmc-loops.shtml">Understanding Loop Unwinding</a>.
189
227
</p>
190
228
0 commit comments