|
1 |
| -[CPROVER Manual TOC](../../) |
| 1 | +[CPROVER Manual TOC](../) |
2 | 2 |
|
3 | 3 | ## Test Suite Generation with CBMC
|
4 | 4 |
|
5 | 5 | ### A Small Tutorial with a Case Study
|
6 | 6 |
|
7 | 7 | We assume that CBMC is installed on your system. If not, follow
|
8 |
| -\ref man_install-cbmc "these instructions". |
| 8 | +[these instructions](../../installation/). |
9 | 9 |
|
10 | 10 | CBMC can be used to automatically generate test cases that satisfy a
|
11 | 11 | certain [code coverage](https://en.wikipedia.org/wiki/Code_coverage)
|
@@ -36,83 +36,83 @@ the figure below.
|
36 | 36 | 
|
37 | 37 |
|
38 | 38 | ```
|
39 |
| - 01: // CONSTANTS: |
40 |
| - 02: #define MAX_CLIMB_SUM_ERR 10 |
41 |
| - 03: #define MAX_CLIMB 1 |
42 |
| - 04: |
43 |
| - 05: #define CLOCK 16 |
44 |
| - 06: #define MAX_PPRZ (CLOCK*600) |
45 |
| - 07: |
46 |
| - 08: #define CLIMB_LEVEL_GAZ 0.31 |
47 |
| - 09: #define CLIMB_GAZ_OF_CLIMB 0.75 |
48 |
| - 10: #define CLIMB_PITCH_OF_VZ_PGAIN 0.05 |
49 |
| - 11: #define CLIMB_PGAIN -0.03 |
50 |
| - 12: #define CLIMB_IGAIN 0.1 |
51 |
| - 13: |
52 |
| - 14: const float pitch_of_vz_pgain=CLIMB_PITCH_OF_VZ_PGAIN; |
53 |
| - 15: const float climb_pgain=CLIMB_PGAIN; |
54 |
| - 16: const float climb_igain=CLIMB_IGAIN; |
55 |
| - 17: const float nav_pitch=0; |
56 |
| - 18: |
57 |
| - 19: /** PID function INPUTS */ |
58 |
| - 20: // The user input: target speed in vertical direction |
59 |
| - 21: float desired_climb; |
60 |
| - 22: // Vertical speed of the UAV detected by GPS sensor |
61 |
| - 23: float estimator_z_dot; |
62 |
| - 24: |
63 |
| - 25: /** PID function OUTPUTS */ |
64 |
| - 26: float desired_gaz; |
65 |
| - 27: float desired_pitch; |
66 |
| - 28: |
67 |
| - 29: /** The state variable: accumulated error in the control */ |
68 |
| - 30: float climb_sum_err=0; |
69 |
| - 31: |
70 |
| - 32: /** Computes desired_gaz and desired_pitch */ |
71 |
| - 33: void climb_pid_run() |
72 |
| - 34: { |
73 |
| - 35: |
74 |
| - 36: float err=estimator_z_dot-desired_climb; |
75 |
| - 37: |
76 |
| - 38: float fgaz=climb_pgain*(err+climb_igain*climb_sum_err)+CLIMB_LEVEL_GAZ+CLIMB_GAZ_OF_CLIMB*desired_climb; |
77 |
| - 39: |
78 |
| - 40: float pprz=fgaz*MAX_PPRZ; |
79 |
| - 41: desired_gaz=((pprz>=0 && pprz<=MAX_PPRZ) ? pprz : (pprz>MAX_PPRZ ? MAX_PPRZ : 0)); |
80 |
| - 42: |
81 |
| - 43: /** pitch offset for climb */ |
82 |
| - 44: float pitch_of_vz=(desired_climb>0) ? desired_climb*pitch_of_vz_pgain : 0; |
83 |
| - 45: desired_pitch=nav_pitch+pitch_of_vz; |
84 |
| - 46: |
85 |
| - 47: climb_sum_err=err+climb_sum_err; |
86 |
| - 48: if (climb_sum_err>MAX_CLIMB_SUM_ERR) climb_sum_err=MAX_CLIMB_SUM_ERR; |
87 |
| - 49: if (climb_sum_err<-MAX_CLIMB_SUM_ERR) climb_sum_err=-MAX_CLIMB_SUM_ERR; |
88 |
| - 50: |
89 |
| - 51: } |
90 |
| - 52: |
91 |
| - 53: int main() |
92 |
| - 54: { |
93 |
| - 55: |
94 |
| - 56: while(1) |
95 |
| - 57: { |
96 |
| - 58: /** Non-deterministic input values */ |
97 |
| - 59: desired_climb=nondet_float(); |
98 |
| - 60: estimator_z_dot=nondet_float(); |
99 |
| - 61: |
100 |
| - 62: /** Range of input values */ |
101 |
| - 63: __CPROVER_assume(desired_climb>=-MAX_CLIMB && desired_climb<=MAX_CLIMB); |
102 |
| - 64: __CPROVER_assume(estimator_z_dot>=-MAX_CLIMB && estimator_z_dot<=MAX_CLIMB); |
103 |
| - 65: |
104 |
| - 66: __CPROVER_input("desired_climb", desired_climb); |
105 |
| - 67: __CPROVER_input("estimator_z_dot", estimator_z_dot); |
106 |
| - 68: |
107 |
| - 69: climb_pid_run(); |
108 |
| - 70: |
109 |
| - 71: __CPROVER_output("desired_gaz", desired_gaz); |
110 |
| - 72: __CPROVER_output("desired_pitch", desired_pitch); |
111 |
| - 73: |
112 |
| - 74: } |
113 |
| - 75: |
114 |
| - 76: return 0; |
115 |
| - 77: } |
| 39 | +01: // CONSTANTS: |
| 40 | +02: #define MAX_CLIMB_SUM_ERR 10 |
| 41 | +03: #define MAX_CLIMB 1 |
| 42 | +04: |
| 43 | +05: #define CLOCK 16 |
| 44 | +06: #define MAX_PPRZ (CLOCK*600) |
| 45 | +07: |
| 46 | +08: #define CLIMB_LEVEL_GAZ 0.31 |
| 47 | +09: #define CLIMB_GAZ_OF_CLIMB 0.75 |
| 48 | +10: #define CLIMB_PITCH_OF_VZ_PGAIN 0.05 |
| 49 | +11: #define CLIMB_PGAIN -0.03 |
| 50 | +12: #define CLIMB_IGAIN 0.1 |
| 51 | +13: |
| 52 | +14: const float pitch_of_vz_pgain=CLIMB_PITCH_OF_VZ_PGAIN; |
| 53 | +15: const float climb_pgain=CLIMB_PGAIN; |
| 54 | +16: const float climb_igain=CLIMB_IGAIN; |
| 55 | +17: const float nav_pitch=0; |
| 56 | +18: |
| 57 | +19: /** PID function INPUTS */ |
| 58 | +20: // The user input: target speed in vertical direction |
| 59 | +21: float desired_climb; |
| 60 | +22: // Vertical speed of the UAV detected by GPS sensor |
| 61 | +23: float estimator_z_dot; |
| 62 | +24: |
| 63 | +25: /** PID function OUTPUTS */ |
| 64 | +26: float desired_gaz; |
| 65 | +27: float desired_pitch; |
| 66 | +28: |
| 67 | +29: /** The state variable: accumulated error in the control */ |
| 68 | +30: float climb_sum_err=0; |
| 69 | +31: |
| 70 | +32: /** Computes desired_gaz and desired_pitch */ |
| 71 | +33: void climb_pid_run() |
| 72 | +34: { |
| 73 | +35: |
| 74 | +36: float err=estimator_z_dot-desired_climb; |
| 75 | +37: |
| 76 | +38: float fgaz=climb_pgain*(err+climb_igain*climb_sum_err)+CLIMB_LEVEL_GAZ+CLIMB_GAZ_OF_CLIMB*desired_climb; |
| 77 | +39: |
| 78 | +40: float pprz=fgaz*MAX_PPRZ; |
| 79 | +41: desired_gaz=((pprz>=0 && pprz<=MAX_PPRZ) ? pprz : (pprz>MAX_PPRZ ? MAX_PPRZ : 0)); |
| 80 | +42: |
| 81 | +43: /** pitch offset for climb */ |
| 82 | +44: float pitch_of_vz=(desired_climb>0) ? desired_climb*pitch_of_vz_pgain : 0; |
| 83 | +45: desired_pitch=nav_pitch+pitch_of_vz; |
| 84 | +46: |
| 85 | +47: climb_sum_err=err+climb_sum_err; |
| 86 | +48: if (climb_sum_err>MAX_CLIMB_SUM_ERR) climb_sum_err=MAX_CLIMB_SUM_ERR; |
| 87 | +49: if (climb_sum_err<-MAX_CLIMB_SUM_ERR) climb_sum_err=-MAX_CLIMB_SUM_ERR; |
| 88 | +50: |
| 89 | +51: } |
| 90 | +52: |
| 91 | +53: int main() |
| 92 | +54: { |
| 93 | +55: |
| 94 | +56: while(1) |
| 95 | +57: { |
| 96 | +58: /** Non-deterministic input values */ |
| 97 | +59: desired_climb=nondet_float(); |
| 98 | +60: estimator_z_dot=nondet_float(); |
| 99 | +61: |
| 100 | +62: /** Range of input values */ |
| 101 | +63: __CPROVER_assume(desired_climb>=-MAX_CLIMB && desired_climb<=MAX_CLIMB); |
| 102 | +64: __CPROVER_assume(estimator_z_dot>=-MAX_CLIMB && estimator_z_dot<=MAX_CLIMB); |
| 103 | +65: |
| 104 | +66: __CPROVER_input("desired_climb", desired_climb); |
| 105 | +67: __CPROVER_input("estimator_z_dot", estimator_z_dot); |
| 106 | +68: |
| 107 | +69: climb_pid_run(); |
| 108 | +70: |
| 109 | +71: __CPROVER_output("desired_gaz", desired_gaz); |
| 110 | +72: __CPROVER_output("desired_pitch", desired_pitch); |
| 111 | +73: |
| 112 | +74: } |
| 113 | +75: |
| 114 | +76: return 0; |
| 115 | +77: } |
116 | 116 | ```
|
117 | 117 |
|
118 | 118 | To test the PID controller, we construct a main control loop,
|
@@ -196,7 +196,8 @@ instrumented goals in the PID function `climb_pid_run`, the loop must be
|
196 | 196 | unwound enough times. For example, `climb_pid_run` needs to
|
197 | 197 | be called at least six times for evaluating the condition
|
198 | 198 | `climb_sum_err>MAX_CLIMB_SUM_ERR` in line 48 to *true*. This corresponds
|
199 |
| -to Test 5. To learn more about loop unwinding take a look at [Understanding Loop Unwinding](cbmc-loops.shtml). |
| 199 | +to Test 5. To learn more about loop unwinding take a look at [Understanding Loop |
| 200 | +Unwinding](../../cbmc-unwinding/). |
200 | 201 |
|
201 | 202 | In this tutorial, we present the automatic test suite generation
|
202 | 203 | functionality of CBMC, by applying the MC/DC code coverage criterion to
|
|
0 commit comments