2 * This file is part of INAV Project.
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
6 * You can obtain one at http://mozilla.org/MPL/2.0/.
8 * Alternatively, the contents of this file may be used under the terms
9 * of the GNU General Public License Version 3, as described below:
11 * This file is free software: you may copy, redistribute and/or modify
12 * it under the terms of the GNU General Public License as published by the
13 * Free Software Foundation, either version 3 of the License, or (at your
14 * option) any later version.
16 * This file is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
19 * Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program. If not, see http://www.gnu.org/licenses/.
29 #include "build/debug.h"
30 #include "drivers/time.h"
31 #include "common/calibration.h"
34 void zeroCalibrationStartS(zeroCalibrationScalar_t
* s
, timeMs_t window
, float threshold
, bool allowFailure
)
36 // Reset parameters and state
37 s
->params
.state
= ZERO_CALIBRATION_IN_PROGRESS
;
38 s
->params
.startTimeMs
= 0;
39 s
->params
.windowSizeMs
= window
;
40 s
->params
.stdDevThreshold
= threshold
;
41 s
->params
.allowFailure
= allowFailure
;
43 s
->params
.sampleCount
= 0;
44 s
->val
.accumulatedValue
= 0;
45 devClear(&s
->val
.stdDev
);
48 bool zeroCalibrationIsCompleteS(zeroCalibrationScalar_t
* s
)
50 return !(s
->params
.state
== ZERO_CALIBRATION_IN_PROGRESS
);
53 bool zeroCalibrationIsSuccessfulS(zeroCalibrationScalar_t
* s
)
55 return (s
->params
.state
== ZERO_CALIBRATION_DONE
);
58 void zeroCalibrationAddValueS(zeroCalibrationScalar_t
* s
, const float v
)
60 if (s
->params
.state
!= ZERO_CALIBRATION_IN_PROGRESS
) {
64 // An unknown delay may have passed between `zeroCalibrationStartS` and first sample acquisition
65 // therefore our window measurement might be incorrect
66 // To account for that we reset the startTimeMs when acquiring the first sample
67 if (s
->params
.sampleCount
== 0 && s
->params
.startTimeMs
== 0) {
68 s
->params
.startTimeMs
= millis();
72 s
->val
.accumulatedValue
+= v
;
73 s
->params
.sampleCount
++;
74 devPush(&s
->val
.stdDev
, v
);
76 // Check if calibration is complete
77 if ((millis() - s
->params
.startTimeMs
) > s
->params
.windowSizeMs
) {
78 const float stddev
= devStandardDeviation(&s
->val
.stdDev
);
80 if (stddev
> s
->params
.stdDevThreshold
) {
81 if (!s
->params
.allowFailure
) {
82 // If deviation is too big && no failure allowed - restart calibration
83 // TODO :: some safeguard should exist which will not allow to keep on calibrating for ever
84 s
->params
.startTimeMs
= millis();
85 s
->params
.sampleCount
= 0;
86 s
->val
.accumulatedValue
= 0;
87 devClear(&s
->val
.stdDev
);
90 // We are allowed to fail
91 s
->params
.state
= ZERO_CALIBRATION_FAIL
;
95 // All seems ok - calculate average value
96 s
->val
.accumulatedValue
= s
->val
.accumulatedValue
/ s
->params
.sampleCount
;
97 s
->params
.state
= ZERO_CALIBRATION_DONE
;
102 void zeroCalibrationGetZeroS(zeroCalibrationScalar_t
* s
, float * v
)
104 if (s
->params
.state
!= ZERO_CALIBRATION_DONE
) {
108 *v
= s
->val
.accumulatedValue
;
112 void zeroCalibrationStartV(zeroCalibrationVector_t
* s
, timeMs_t window
, float threshold
, bool allowFailure
)
114 // Reset parameters and state
115 s
->params
.state
= ZERO_CALIBRATION_IN_PROGRESS
;
116 s
->params
.startTimeMs
= millis();
117 s
->params
.windowSizeMs
= window
;
118 s
->params
.stdDevThreshold
= threshold
;
119 s
->params
.allowFailure
= allowFailure
;
121 s
->params
.sampleCount
= 0;
122 for (int i
= 0; i
< 3; i
++) {
123 s
->val
[i
].accumulatedValue
= 0;
124 devClear(&s
->val
[i
].stdDev
);
128 bool zeroCalibrationIsCompleteV(zeroCalibrationVector_t
* s
)
130 return !(s
->params
.state
== ZERO_CALIBRATION_IN_PROGRESS
);
133 bool zeroCalibrationIsSuccessfulV(zeroCalibrationVector_t
* s
)
135 return (s
->params
.state
== ZERO_CALIBRATION_DONE
);
138 void zeroCalibrationAddValueV(zeroCalibrationVector_t
* s
, const fpVector3_t
* v
)
140 if (s
->params
.state
!= ZERO_CALIBRATION_IN_PROGRESS
) {
145 for (int i
= 0; i
< 3; i
++) {
146 s
->val
[i
].accumulatedValue
+= v
->v
[i
];
147 devPush(&s
->val
[i
].stdDev
, v
->v
[i
]);
150 s
->params
.sampleCount
++;
152 // Check if calibration is complete
153 if ((millis() - s
->params
.startTimeMs
) > s
->params
.windowSizeMs
) {
154 bool needRecalibration
= false;
156 for (int i
= 0; i
< 3 && !needRecalibration
; i
++) {
157 const float stddev
= devStandardDeviation(&s
->val
[i
].stdDev
);
159 if (stddev
> s
->params
.stdDevThreshold
) {
160 needRecalibration
= true;
164 if (needRecalibration
) {
165 if (!s
->params
.allowFailure
) {
166 // If deviation is too big - restart calibration
167 s
->params
.startTimeMs
= millis();
168 s
->params
.sampleCount
= 0;
169 for (int i
= 0; i
< 3; i
++) {
170 s
->val
[i
].accumulatedValue
= 0;
171 devClear(&s
->val
[i
].stdDev
);
175 // We are allowed to fail
176 s
->params
.state
= ZERO_CALIBRATION_FAIL
;
180 // All seems ok - calculate average value
181 s
->val
[0].accumulatedValue
= s
->val
[0].accumulatedValue
/ s
->params
.sampleCount
;
182 s
->val
[1].accumulatedValue
= s
->val
[1].accumulatedValue
/ s
->params
.sampleCount
;
183 s
->val
[2].accumulatedValue
= s
->val
[2].accumulatedValue
/ s
->params
.sampleCount
;
184 s
->params
.state
= ZERO_CALIBRATION_DONE
;
189 void zeroCalibrationGetZeroV(zeroCalibrationVector_t
* s
, fpVector3_t
* v
)
191 if (s
->params
.state
!= ZERO_CALIBRATION_DONE
) {
195 v
->v
[0] = s
->val
[0].accumulatedValue
;
196 v
->v
[1] = s
->val
[1].accumulatedValue
;
197 v
->v
[2] = s
->val
[2].accumulatedValue
;