sensirion_voc_algorithm.c revision 1.1 1 1.1 brad /*
2 1.1 brad * $NetBSD: sensirion_voc_algorithm.c,v 1.1 2021/10/14 13:54:46 brad Exp $
3 1.1 brad */
4 1.1 brad
5 1.1 brad /*
6 1.1 brad * Copyright (c) 2021, Sensirion AG
7 1.1 brad * All rights reserved.
8 1.1 brad *
9 1.1 brad * Redistribution and use in source and binary forms, with or without
10 1.1 brad * modification, are permitted provided that the following conditions are met:
11 1.1 brad *
12 1.1 brad * * Redistributions of source code must retain the above copyright notice, this
13 1.1 brad * list of conditions and the following disclaimer.
14 1.1 brad *
15 1.1 brad * * Redistributions in binary form must reproduce the above copyright notice,
16 1.1 brad * this list of conditions and the following disclaimer in the documentation
17 1.1 brad * and/or other materials provided with the distribution.
18 1.1 brad *
19 1.1 brad * * Neither the name of Sensirion AG nor the names of its
20 1.1 brad * contributors may be used to endorse or promote products derived from
21 1.1 brad * this software without specific prior written permission.
22 1.1 brad *
23 1.1 brad * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 1.1 brad * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 1.1 brad * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 1.1 brad * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27 1.1 brad * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 1.1 brad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 1.1 brad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 1.1 brad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 1.1 brad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 1.1 brad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 1.1 brad * POSSIBILITY OF SUCH DAMAGE.
34 1.1 brad */
35 1.1 brad
36 1.1 brad #include "sensirion_voc_algorithm.h"
37 1.1 brad
38 1.1 brad /* The fixed point arithmetic parts of this code were originally created by
39 1.1 brad * https://github.com/PetteriAimonen/libfixmath
40 1.1 brad */
41 1.1 brad
42 1.1 brad /*!< the maximum value of fix16_t */
43 1.1 brad #define FIX16_MAXIMUM 0x7FFFFFFF
44 1.1 brad /*!< the minimum value of fix16_t */
45 1.1 brad #define FIX16_MINIMUM 0x80000000
46 1.1 brad /*!< the value used to indicate overflows when FIXMATH_NO_OVERFLOW is not
47 1.1 brad * specified */
48 1.1 brad #define FIX16_OVERFLOW 0x80000000
49 1.1 brad /*!< fix16_t value of 1 */
50 1.1 brad #define FIX16_ONE 0x00010000
51 1.1 brad
52 1.1 brad static inline fix16_t fix16_from_int(int32_t a) {
53 1.1 brad return a * FIX16_ONE;
54 1.1 brad }
55 1.1 brad
56 1.1 brad static inline int32_t fix16_cast_to_int(fix16_t a) {
57 1.1 brad return (a >= 0) ? (a >> 16) : -((-a) >> 16);
58 1.1 brad }
59 1.1 brad
60 1.1 brad /*! Multiplies the two given fix16_t's and returns the result. */
61 1.1 brad static fix16_t fix16_mul(fix16_t inArg0, fix16_t inArg1);
62 1.1 brad
63 1.1 brad /*! Divides the first given fix16_t by the second and returns the result. */
64 1.1 brad static fix16_t fix16_div(fix16_t inArg0, fix16_t inArg1);
65 1.1 brad
66 1.1 brad /*! Returns the square root of the given fix16_t. */
67 1.1 brad static fix16_t fix16_sqrt(fix16_t inValue);
68 1.1 brad
69 1.1 brad /*! Returns the exponent (e^) of the given fix16_t. */
70 1.1 brad static fix16_t fix16_exp(fix16_t inValue);
71 1.1 brad
72 1.1 brad static fix16_t fix16_mul(fix16_t inArg0, fix16_t inArg1) {
73 1.1 brad // Each argument is divided to 16-bit parts.
74 1.1 brad // AB
75 1.1 brad // * CD
76 1.1 brad // -----------
77 1.1 brad // BD 16 * 16 -> 32 bit products
78 1.1 brad // CB
79 1.1 brad // AD
80 1.1 brad // AC
81 1.1 brad // |----| 64 bit product
82 1.1 brad uint32_t absArg0 = (uint32_t)((inArg0 >= 0) ? inArg0 : (-inArg0));
83 1.1 brad uint32_t absArg1 = (uint32_t)((inArg1 >= 0) ? inArg1 : (-inArg1));
84 1.1 brad uint32_t A = (absArg0 >> 16), C = (absArg1 >> 16);
85 1.1 brad uint32_t B = (absArg0 & 0xFFFF), D = (absArg1 & 0xFFFF);
86 1.1 brad
87 1.1 brad uint32_t AC = A * C;
88 1.1 brad uint32_t AD_CB = A * D + C * B;
89 1.1 brad uint32_t BD = B * D;
90 1.1 brad
91 1.1 brad uint32_t product_hi = AC + (AD_CB >> 16);
92 1.1 brad
93 1.1 brad // Handle carry from lower 32 bits to upper part of result.
94 1.1 brad uint32_t ad_cb_temp = AD_CB << 16;
95 1.1 brad uint32_t product_lo = BD + ad_cb_temp;
96 1.1 brad if (product_lo < BD)
97 1.1 brad product_hi++;
98 1.1 brad
99 1.1 brad #ifndef FIXMATH_NO_OVERFLOW
100 1.1 brad // The upper 17 bits should all be zero.
101 1.1 brad if (product_hi >> 15)
102 1.1 brad return (fix16_t)FIX16_OVERFLOW;
103 1.1 brad #endif
104 1.1 brad
105 1.1 brad #ifdef FIXMATH_NO_ROUNDING
106 1.1 brad fix16_t result = (fix16_t)((product_hi << 16) | (product_lo >> 16));
107 1.1 brad if ((inArg0 < 0) != (inArg1 < 0))
108 1.1 brad result = -result;
109 1.1 brad return result;
110 1.1 brad #else
111 1.1 brad // Adding 0x8000 (= 0.5) and then using right shift
112 1.1 brad // achieves proper rounding to result.
113 1.1 brad // Handle carry from lower to upper part.
114 1.1 brad uint32_t product_lo_tmp = product_lo;
115 1.1 brad product_lo += 0x8000;
116 1.1 brad if (product_lo < product_lo_tmp)
117 1.1 brad product_hi++;
118 1.1 brad
119 1.1 brad // Discard the lowest 16 bits and convert back to signed result.
120 1.1 brad fix16_t result = (fix16_t)((product_hi << 16) | (product_lo >> 16));
121 1.1 brad if ((inArg0 < 0) != (inArg1 < 0))
122 1.1 brad result = -result;
123 1.1 brad return result;
124 1.1 brad #endif
125 1.1 brad }
126 1.1 brad
127 1.1 brad static fix16_t fix16_div(fix16_t a, fix16_t b) {
128 1.1 brad // This uses the basic binary restoring division algorithm.
129 1.1 brad // It appears to be faster to do the whole division manually than
130 1.1 brad // trying to compose a 64-bit divide out of 32-bit divisions on
131 1.1 brad // platforms without hardware divide.
132 1.1 brad
133 1.1 brad if (b == 0)
134 1.1 brad return (fix16_t)FIX16_MINIMUM;
135 1.1 brad
136 1.1 brad uint32_t remainder = (uint32_t)((a >= 0) ? a : (-a));
137 1.1 brad uint32_t divider = (uint32_t)((b >= 0) ? b : (-b));
138 1.1 brad
139 1.1 brad uint32_t quotient = 0;
140 1.1 brad uint32_t bit = 0x10000;
141 1.1 brad
142 1.1 brad /* The algorithm requires D >= R */
143 1.1 brad while (divider < remainder) {
144 1.1 brad divider <<= 1;
145 1.1 brad bit <<= 1;
146 1.1 brad }
147 1.1 brad
148 1.1 brad #ifndef FIXMATH_NO_OVERFLOW
149 1.1 brad if (!bit)
150 1.1 brad return (fix16_t)FIX16_OVERFLOW;
151 1.1 brad #endif
152 1.1 brad
153 1.1 brad if (divider & 0x80000000) {
154 1.1 brad // Perform one step manually to avoid overflows later.
155 1.1 brad // We know that divider's bottom bit is 0 here.
156 1.1 brad if (remainder >= divider) {
157 1.1 brad quotient |= bit;
158 1.1 brad remainder -= divider;
159 1.1 brad }
160 1.1 brad divider >>= 1;
161 1.1 brad bit >>= 1;
162 1.1 brad }
163 1.1 brad
164 1.1 brad /* Main division loop */
165 1.1 brad while (bit && remainder) {
166 1.1 brad if (remainder >= divider) {
167 1.1 brad quotient |= bit;
168 1.1 brad remainder -= divider;
169 1.1 brad }
170 1.1 brad
171 1.1 brad remainder <<= 1;
172 1.1 brad bit >>= 1;
173 1.1 brad }
174 1.1 brad
175 1.1 brad #ifndef FIXMATH_NO_ROUNDING
176 1.1 brad if (remainder >= divider) {
177 1.1 brad quotient++;
178 1.1 brad }
179 1.1 brad #endif
180 1.1 brad
181 1.1 brad fix16_t result = (fix16_t)quotient;
182 1.1 brad
183 1.1 brad /* Figure out the sign of result */
184 1.1 brad if ((a < 0) != (b < 0)) {
185 1.1 brad #ifndef FIXMATH_NO_OVERFLOW
186 1.1 brad if (result == FIX16_MINIMUM)
187 1.1 brad return (fix16_t)FIX16_OVERFLOW;
188 1.1 brad #endif
189 1.1 brad
190 1.1 brad result = -result;
191 1.1 brad }
192 1.1 brad
193 1.1 brad return result;
194 1.1 brad }
195 1.1 brad
196 1.1 brad static fix16_t fix16_sqrt(fix16_t x) {
197 1.1 brad // It is assumed that x is not negative
198 1.1 brad
199 1.1 brad uint32_t num = (uint32_t)x;
200 1.1 brad uint32_t result = 0;
201 1.1 brad uint32_t bit;
202 1.1 brad uint8_t n;
203 1.1 brad
204 1.1 brad bit = (uint32_t)1 << 30;
205 1.1 brad while (bit > num)
206 1.1 brad bit >>= 2;
207 1.1 brad
208 1.1 brad // The main part is executed twice, in order to avoid
209 1.1 brad // using 64 bit values in computations.
210 1.1 brad for (n = 0; n < 2; n++) {
211 1.1 brad // First we get the top 24 bits of the answer.
212 1.1 brad while (bit) {
213 1.1 brad if (num >= result + bit) {
214 1.1 brad num -= result + bit;
215 1.1 brad result = (result >> 1) + bit;
216 1.1 brad } else {
217 1.1 brad result = (result >> 1);
218 1.1 brad }
219 1.1 brad bit >>= 2;
220 1.1 brad }
221 1.1 brad
222 1.1 brad if (n == 0) {
223 1.1 brad // Then process it again to get the lowest 8 bits.
224 1.1 brad if (num > 65535) {
225 1.1 brad // The remainder 'num' is too large to be shifted left
226 1.1 brad // by 16, so we have to add 1 to result manually and
227 1.1 brad // adjust 'num' accordingly.
228 1.1 brad // num = a - (result + 0.5)^2
229 1.1 brad // = num + result^2 - (result + 0.5)^2
230 1.1 brad // = num - result - 0.5
231 1.1 brad num -= result;
232 1.1 brad num = (num << 16) - 0x8000;
233 1.1 brad result = (result << 16) + 0x8000;
234 1.1 brad } else {
235 1.1 brad num <<= 16;
236 1.1 brad result <<= 16;
237 1.1 brad }
238 1.1 brad
239 1.1 brad bit = 1 << 14;
240 1.1 brad }
241 1.1 brad }
242 1.1 brad
243 1.1 brad #ifndef FIXMATH_NO_ROUNDING
244 1.1 brad // Finally, if next bit would have been 1, round the result upwards.
245 1.1 brad if (num > result) {
246 1.1 brad result++;
247 1.1 brad }
248 1.1 brad #endif
249 1.1 brad
250 1.1 brad return (fix16_t)result;
251 1.1 brad }
252 1.1 brad
253 1.1 brad static fix16_t fix16_exp(fix16_t x) {
254 1.1 brad // Function to approximate exp(); optimized more for code size than speed
255 1.1 brad
256 1.1 brad // exp(x) for x = +/- {1, 1/8, 1/64, 1/512}
257 1.1 brad #define NUM_EXP_VALUES 4
258 1.1 brad static const fix16_t exp_pos_values[NUM_EXP_VALUES] = {
259 1.1 brad F16(2.7182818), F16(1.1331485), F16(1.0157477), F16(1.0019550)};
260 1.1 brad static const fix16_t exp_neg_values[NUM_EXP_VALUES] = {
261 1.1 brad F16(0.3678794), F16(0.8824969), F16(0.9844964), F16(0.9980488)};
262 1.1 brad const fix16_t* exp_values;
263 1.1 brad
264 1.1 brad fix16_t res, arg;
265 1.1 brad uint16_t i;
266 1.1 brad
267 1.1 brad if (x >= F16(10.3972))
268 1.1 brad return FIX16_MAXIMUM;
269 1.1 brad if (x <= F16(-11.7835))
270 1.1 brad return 0;
271 1.1 brad
272 1.1 brad if (x < 0) {
273 1.1 brad x = -x;
274 1.1 brad exp_values = exp_neg_values;
275 1.1 brad } else {
276 1.1 brad exp_values = exp_pos_values;
277 1.1 brad }
278 1.1 brad
279 1.1 brad res = FIX16_ONE;
280 1.1 brad arg = FIX16_ONE;
281 1.1 brad for (i = 0; i < NUM_EXP_VALUES; i++) {
282 1.1 brad while (x >= arg) {
283 1.1 brad res = fix16_mul(res, exp_values[i]);
284 1.1 brad x -= arg;
285 1.1 brad }
286 1.1 brad arg >>= 3;
287 1.1 brad }
288 1.1 brad return res;
289 1.1 brad }
290 1.1 brad
291 1.1 brad static void VocAlgorithm__init_instances(VocAlgorithmParams* params);
292 1.1 brad static void
293 1.1 brad VocAlgorithm__mean_variance_estimator__init(VocAlgorithmParams* params);
294 1.1 brad static void VocAlgorithm__mean_variance_estimator___init_instances(
295 1.1 brad VocAlgorithmParams* params);
296 1.1 brad static void VocAlgorithm__mean_variance_estimator__set_parameters(
297 1.1 brad VocAlgorithmParams* params, fix16_t std_initial,
298 1.1 brad fix16_t tau_mean_variance_hours, fix16_t gating_max_duration_minutes);
299 1.1 brad static void
300 1.1 brad VocAlgorithm__mean_variance_estimator__set_states(VocAlgorithmParams* params,
301 1.1 brad fix16_t mean, fix16_t std,
302 1.1 brad fix16_t uptime_gamma);
303 1.1 brad static fix16_t
304 1.1 brad VocAlgorithm__mean_variance_estimator__get_std(VocAlgorithmParams* params);
305 1.1 brad static fix16_t
306 1.1 brad VocAlgorithm__mean_variance_estimator__get_mean(VocAlgorithmParams* params);
307 1.1 brad static void VocAlgorithm__mean_variance_estimator___calculate_gamma(
308 1.1 brad VocAlgorithmParams* params, fix16_t voc_index_from_prior);
309 1.1 brad static void VocAlgorithm__mean_variance_estimator__process(
310 1.1 brad VocAlgorithmParams* params, fix16_t sraw, fix16_t voc_index_from_prior);
311 1.1 brad static void VocAlgorithm__mean_variance_estimator___sigmoid__init(
312 1.1 brad VocAlgorithmParams* params);
313 1.1 brad static void VocAlgorithm__mean_variance_estimator___sigmoid__set_parameters(
314 1.1 brad VocAlgorithmParams* params, fix16_t L, fix16_t X0, fix16_t K);
315 1.1 brad static fix16_t VocAlgorithm__mean_variance_estimator___sigmoid__process(
316 1.1 brad VocAlgorithmParams* params, fix16_t sample);
317 1.1 brad static void VocAlgorithm__mox_model__init(VocAlgorithmParams* params);
318 1.1 brad static void VocAlgorithm__mox_model__set_parameters(VocAlgorithmParams* params,
319 1.1 brad fix16_t SRAW_STD,
320 1.1 brad fix16_t SRAW_MEAN);
321 1.1 brad static fix16_t VocAlgorithm__mox_model__process(VocAlgorithmParams* params,
322 1.1 brad fix16_t sraw);
323 1.1 brad static void VocAlgorithm__sigmoid_scaled__init(VocAlgorithmParams* params);
324 1.1 brad static void
325 1.1 brad VocAlgorithm__sigmoid_scaled__set_parameters(VocAlgorithmParams* params,
326 1.1 brad fix16_t offset);
327 1.1 brad static fix16_t VocAlgorithm__sigmoid_scaled__process(VocAlgorithmParams* params,
328 1.1 brad fix16_t sample);
329 1.1 brad static void VocAlgorithm__adaptive_lowpass__init(VocAlgorithmParams* params);
330 1.1 brad static void
331 1.1 brad VocAlgorithm__adaptive_lowpass__set_parameters(VocAlgorithmParams* params);
332 1.1 brad static fix16_t
333 1.1 brad VocAlgorithm__adaptive_lowpass__process(VocAlgorithmParams* params,
334 1.1 brad fix16_t sample);
335 1.1 brad
336 1.1 brad void VocAlgorithm_init(VocAlgorithmParams* params) {
337 1.1 brad
338 1.1 brad params->mVoc_Index_Offset = F16(VocAlgorithm_VOC_INDEX_OFFSET_DEFAULT);
339 1.1 brad params->mTau_Mean_Variance_Hours =
340 1.1 brad F16(VocAlgorithm_TAU_MEAN_VARIANCE_HOURS);
341 1.1 brad params->mGating_Max_Duration_Minutes =
342 1.1 brad F16(VocAlgorithm_GATING_MAX_DURATION_MINUTES);
343 1.1 brad params->mSraw_Std_Initial = F16(VocAlgorithm_SRAW_STD_INITIAL);
344 1.1 brad params->mUptime = F16(0.);
345 1.1 brad params->mSraw = F16(0.);
346 1.1 brad params->mVoc_Index = 0;
347 1.1 brad VocAlgorithm__init_instances(params);
348 1.1 brad }
349 1.1 brad
350 1.1 brad static void VocAlgorithm__init_instances(VocAlgorithmParams* params) {
351 1.1 brad
352 1.1 brad VocAlgorithm__mean_variance_estimator__init(params);
353 1.1 brad VocAlgorithm__mean_variance_estimator__set_parameters(
354 1.1 brad params, params->mSraw_Std_Initial, params->mTau_Mean_Variance_Hours,
355 1.1 brad params->mGating_Max_Duration_Minutes);
356 1.1 brad VocAlgorithm__mox_model__init(params);
357 1.1 brad VocAlgorithm__mox_model__set_parameters(
358 1.1 brad params, VocAlgorithm__mean_variance_estimator__get_std(params),
359 1.1 brad VocAlgorithm__mean_variance_estimator__get_mean(params));
360 1.1 brad VocAlgorithm__sigmoid_scaled__init(params);
361 1.1 brad VocAlgorithm__sigmoid_scaled__set_parameters(params,
362 1.1 brad params->mVoc_Index_Offset);
363 1.1 brad VocAlgorithm__adaptive_lowpass__init(params);
364 1.1 brad VocAlgorithm__adaptive_lowpass__set_parameters(params);
365 1.1 brad }
366 1.1 brad
367 1.1 brad void VocAlgorithm_get_states(VocAlgorithmParams* params, int32_t* state0,
368 1.1 brad int32_t* state1) {
369 1.1 brad
370 1.1 brad *state0 = VocAlgorithm__mean_variance_estimator__get_mean(params);
371 1.1 brad *state1 = VocAlgorithm__mean_variance_estimator__get_std(params);
372 1.1 brad return;
373 1.1 brad }
374 1.1 brad
375 1.1 brad void VocAlgorithm_set_states(VocAlgorithmParams* params, int32_t state0,
376 1.1 brad int32_t state1) {
377 1.1 brad
378 1.1 brad VocAlgorithm__mean_variance_estimator__set_states(
379 1.1 brad params, state0, state1, F16(VocAlgorithm_PERSISTENCE_UPTIME_GAMMA));
380 1.1 brad params->mSraw = state0;
381 1.1 brad }
382 1.1 brad
383 1.1 brad void VocAlgorithm_set_tuning_parameters(VocAlgorithmParams* params,
384 1.1 brad int32_t voc_index_offset,
385 1.1 brad int32_t learning_time_hours,
386 1.1 brad int32_t gating_max_duration_minutes,
387 1.1 brad int32_t std_initial) {
388 1.1 brad
389 1.1 brad params->mVoc_Index_Offset = (fix16_from_int(voc_index_offset));
390 1.1 brad params->mTau_Mean_Variance_Hours = (fix16_from_int(learning_time_hours));
391 1.1 brad params->mGating_Max_Duration_Minutes =
392 1.1 brad (fix16_from_int(gating_max_duration_minutes));
393 1.1 brad params->mSraw_Std_Initial = (fix16_from_int(std_initial));
394 1.1 brad VocAlgorithm__init_instances(params);
395 1.1 brad }
396 1.1 brad
397 1.1 brad void VocAlgorithm_process(VocAlgorithmParams* params, int32_t sraw,
398 1.1 brad int32_t* voc_index) {
399 1.1 brad
400 1.1 brad if ((params->mUptime <= F16(VocAlgorithm_INITIAL_BLACKOUT))) {
401 1.1 brad params->mUptime =
402 1.1 brad (params->mUptime + F16(VocAlgorithm_SAMPLING_INTERVAL));
403 1.1 brad } else {
404 1.1 brad if (((sraw > 0) && (sraw < 65000))) {
405 1.1 brad if ((sraw < 20001)) {
406 1.1 brad sraw = 20001;
407 1.1 brad } else if ((sraw > 52767)) {
408 1.1 brad sraw = 52767;
409 1.1 brad }
410 1.1 brad params->mSraw = (fix16_from_int((sraw - 20000)));
411 1.1 brad }
412 1.1 brad params->mVoc_Index =
413 1.1 brad VocAlgorithm__mox_model__process(params, params->mSraw);
414 1.1 brad params->mVoc_Index =
415 1.1 brad VocAlgorithm__sigmoid_scaled__process(params, params->mVoc_Index);
416 1.1 brad params->mVoc_Index =
417 1.1 brad VocAlgorithm__adaptive_lowpass__process(params, params->mVoc_Index);
418 1.1 brad if ((params->mVoc_Index < F16(0.5))) {
419 1.1 brad params->mVoc_Index = F16(0.5);
420 1.1 brad }
421 1.1 brad if ((params->mSraw > F16(0.))) {
422 1.1 brad VocAlgorithm__mean_variance_estimator__process(
423 1.1 brad params, params->mSraw, params->mVoc_Index);
424 1.1 brad VocAlgorithm__mox_model__set_parameters(
425 1.1 brad params, VocAlgorithm__mean_variance_estimator__get_std(params),
426 1.1 brad VocAlgorithm__mean_variance_estimator__get_mean(params));
427 1.1 brad }
428 1.1 brad }
429 1.1 brad *voc_index = (fix16_cast_to_int((params->mVoc_Index + F16(0.5))));
430 1.1 brad return;
431 1.1 brad }
432 1.1 brad
433 1.1 brad static void
434 1.1 brad VocAlgorithm__mean_variance_estimator__init(VocAlgorithmParams* params) {
435 1.1 brad
436 1.1 brad VocAlgorithm__mean_variance_estimator__set_parameters(params, F16(0.),
437 1.1 brad F16(0.), F16(0.));
438 1.1 brad VocAlgorithm__mean_variance_estimator___init_instances(params);
439 1.1 brad }
440 1.1 brad
441 1.1 brad static void VocAlgorithm__mean_variance_estimator___init_instances(
442 1.1 brad VocAlgorithmParams* params) {
443 1.1 brad
444 1.1 brad VocAlgorithm__mean_variance_estimator___sigmoid__init(params);
445 1.1 brad }
446 1.1 brad
447 1.1 brad static void VocAlgorithm__mean_variance_estimator__set_parameters(
448 1.1 brad VocAlgorithmParams* params, fix16_t std_initial,
449 1.1 brad fix16_t tau_mean_variance_hours, fix16_t gating_max_duration_minutes) {
450 1.1 brad
451 1.1 brad params->m_Mean_Variance_Estimator__Gating_Max_Duration_Minutes =
452 1.1 brad gating_max_duration_minutes;
453 1.1 brad params->m_Mean_Variance_Estimator___Initialized = false;
454 1.1 brad params->m_Mean_Variance_Estimator___Mean = F16(0.);
455 1.1 brad params->m_Mean_Variance_Estimator___Sraw_Offset = F16(0.);
456 1.1 brad params->m_Mean_Variance_Estimator___Std = std_initial;
457 1.1 brad params->m_Mean_Variance_Estimator___Gamma =
458 1.1 brad (fix16_div(F16((VocAlgorithm_MEAN_VARIANCE_ESTIMATOR__GAMMA_SCALING *
459 1.1 brad (VocAlgorithm_SAMPLING_INTERVAL / 3600.))),
460 1.1 brad (tau_mean_variance_hours +
461 1.1 brad F16((VocAlgorithm_SAMPLING_INTERVAL / 3600.)))));
462 1.1 brad params->m_Mean_Variance_Estimator___Gamma_Initial_Mean =
463 1.1 brad F16(((VocAlgorithm_MEAN_VARIANCE_ESTIMATOR__GAMMA_SCALING *
464 1.1 brad VocAlgorithm_SAMPLING_INTERVAL) /
465 1.1 brad (VocAlgorithm_TAU_INITIAL_MEAN + VocAlgorithm_SAMPLING_INTERVAL)));
466 1.1 brad params->m_Mean_Variance_Estimator___Gamma_Initial_Variance = F16(
467 1.1 brad ((VocAlgorithm_MEAN_VARIANCE_ESTIMATOR__GAMMA_SCALING *
468 1.1 brad VocAlgorithm_SAMPLING_INTERVAL) /
469 1.1 brad (VocAlgorithm_TAU_INITIAL_VARIANCE + VocAlgorithm_SAMPLING_INTERVAL)));
470 1.1 brad params->m_Mean_Variance_Estimator__Gamma_Mean = F16(0.);
471 1.1 brad params->m_Mean_Variance_Estimator__Gamma_Variance = F16(0.);
472 1.1 brad params->m_Mean_Variance_Estimator___Uptime_Gamma = F16(0.);
473 1.1 brad params->m_Mean_Variance_Estimator___Uptime_Gating = F16(0.);
474 1.1 brad params->m_Mean_Variance_Estimator___Gating_Duration_Minutes = F16(0.);
475 1.1 brad }
476 1.1 brad
477 1.1 brad static void
478 1.1 brad VocAlgorithm__mean_variance_estimator__set_states(VocAlgorithmParams* params,
479 1.1 brad fix16_t mean, fix16_t std,
480 1.1 brad fix16_t uptime_gamma) {
481 1.1 brad
482 1.1 brad params->m_Mean_Variance_Estimator___Mean = mean;
483 1.1 brad params->m_Mean_Variance_Estimator___Std = std;
484 1.1 brad params->m_Mean_Variance_Estimator___Uptime_Gamma = uptime_gamma;
485 1.1 brad params->m_Mean_Variance_Estimator___Initialized = true;
486 1.1 brad }
487 1.1 brad
488 1.1 brad static fix16_t
489 1.1 brad VocAlgorithm__mean_variance_estimator__get_std(VocAlgorithmParams* params) {
490 1.1 brad
491 1.1 brad return params->m_Mean_Variance_Estimator___Std;
492 1.1 brad }
493 1.1 brad
494 1.1 brad static fix16_t
495 1.1 brad VocAlgorithm__mean_variance_estimator__get_mean(VocAlgorithmParams* params) {
496 1.1 brad
497 1.1 brad return (params->m_Mean_Variance_Estimator___Mean +
498 1.1 brad params->m_Mean_Variance_Estimator___Sraw_Offset);
499 1.1 brad }
500 1.1 brad
501 1.1 brad static void VocAlgorithm__mean_variance_estimator___calculate_gamma(
502 1.1 brad VocAlgorithmParams* params, fix16_t voc_index_from_prior) {
503 1.1 brad
504 1.1 brad fix16_t uptime_limit;
505 1.1 brad fix16_t sigmoid_gamma_mean;
506 1.1 brad fix16_t gamma_mean;
507 1.1 brad fix16_t gating_threshold_mean;
508 1.1 brad fix16_t sigmoid_gating_mean;
509 1.1 brad fix16_t sigmoid_gamma_variance;
510 1.1 brad fix16_t gamma_variance;
511 1.1 brad fix16_t gating_threshold_variance;
512 1.1 brad fix16_t sigmoid_gating_variance;
513 1.1 brad
514 1.1 brad uptime_limit = F16((VocAlgorithm_MEAN_VARIANCE_ESTIMATOR__FIX16_MAX -
515 1.1 brad VocAlgorithm_SAMPLING_INTERVAL));
516 1.1 brad if ((params->m_Mean_Variance_Estimator___Uptime_Gamma < uptime_limit)) {
517 1.1 brad params->m_Mean_Variance_Estimator___Uptime_Gamma =
518 1.1 brad (params->m_Mean_Variance_Estimator___Uptime_Gamma +
519 1.1 brad F16(VocAlgorithm_SAMPLING_INTERVAL));
520 1.1 brad }
521 1.1 brad if ((params->m_Mean_Variance_Estimator___Uptime_Gating < uptime_limit)) {
522 1.1 brad params->m_Mean_Variance_Estimator___Uptime_Gating =
523 1.1 brad (params->m_Mean_Variance_Estimator___Uptime_Gating +
524 1.1 brad F16(VocAlgorithm_SAMPLING_INTERVAL));
525 1.1 brad }
526 1.1 brad VocAlgorithm__mean_variance_estimator___sigmoid__set_parameters(
527 1.1 brad params, F16(1.), F16(VocAlgorithm_INIT_DURATION_MEAN),
528 1.1 brad F16(VocAlgorithm_INIT_TRANSITION_MEAN));
529 1.1 brad sigmoid_gamma_mean =
530 1.1 brad VocAlgorithm__mean_variance_estimator___sigmoid__process(
531 1.1 brad params, params->m_Mean_Variance_Estimator___Uptime_Gamma);
532 1.1 brad gamma_mean =
533 1.1 brad (params->m_Mean_Variance_Estimator___Gamma +
534 1.1 brad (fix16_mul((params->m_Mean_Variance_Estimator___Gamma_Initial_Mean -
535 1.1 brad params->m_Mean_Variance_Estimator___Gamma),
536 1.1 brad sigmoid_gamma_mean)));
537 1.1 brad gating_threshold_mean =
538 1.1 brad (F16(VocAlgorithm_GATING_THRESHOLD) +
539 1.1 brad (fix16_mul(
540 1.1 brad F16((VocAlgorithm_GATING_THRESHOLD_INITIAL -
541 1.1 brad VocAlgorithm_GATING_THRESHOLD)),
542 1.1 brad VocAlgorithm__mean_variance_estimator___sigmoid__process(
543 1.1 brad params, params->m_Mean_Variance_Estimator___Uptime_Gating))));
544 1.1 brad VocAlgorithm__mean_variance_estimator___sigmoid__set_parameters(
545 1.1 brad params, F16(1.), gating_threshold_mean,
546 1.1 brad F16(VocAlgorithm_GATING_THRESHOLD_TRANSITION));
547 1.1 brad sigmoid_gating_mean =
548 1.1 brad VocAlgorithm__mean_variance_estimator___sigmoid__process(
549 1.1 brad params, voc_index_from_prior);
550 1.1 brad params->m_Mean_Variance_Estimator__Gamma_Mean =
551 1.1 brad (fix16_mul(sigmoid_gating_mean, gamma_mean));
552 1.1 brad VocAlgorithm__mean_variance_estimator___sigmoid__set_parameters(
553 1.1 brad params, F16(1.), F16(VocAlgorithm_INIT_DURATION_VARIANCE),
554 1.1 brad F16(VocAlgorithm_INIT_TRANSITION_VARIANCE));
555 1.1 brad sigmoid_gamma_variance =
556 1.1 brad VocAlgorithm__mean_variance_estimator___sigmoid__process(
557 1.1 brad params, params->m_Mean_Variance_Estimator___Uptime_Gamma);
558 1.1 brad gamma_variance =
559 1.1 brad (params->m_Mean_Variance_Estimator___Gamma +
560 1.1 brad (fix16_mul(
561 1.1 brad (params->m_Mean_Variance_Estimator___Gamma_Initial_Variance -
562 1.1 brad params->m_Mean_Variance_Estimator___Gamma),
563 1.1 brad (sigmoid_gamma_variance - sigmoid_gamma_mean))));
564 1.1 brad gating_threshold_variance =
565 1.1 brad (F16(VocAlgorithm_GATING_THRESHOLD) +
566 1.1 brad (fix16_mul(
567 1.1 brad F16((VocAlgorithm_GATING_THRESHOLD_INITIAL -
568 1.1 brad VocAlgorithm_GATING_THRESHOLD)),
569 1.1 brad VocAlgorithm__mean_variance_estimator___sigmoid__process(
570 1.1 brad params, params->m_Mean_Variance_Estimator___Uptime_Gating))));
571 1.1 brad VocAlgorithm__mean_variance_estimator___sigmoid__set_parameters(
572 1.1 brad params, F16(1.), gating_threshold_variance,
573 1.1 brad F16(VocAlgorithm_GATING_THRESHOLD_TRANSITION));
574 1.1 brad sigmoid_gating_variance =
575 1.1 brad VocAlgorithm__mean_variance_estimator___sigmoid__process(
576 1.1 brad params, voc_index_from_prior);
577 1.1 brad params->m_Mean_Variance_Estimator__Gamma_Variance =
578 1.1 brad (fix16_mul(sigmoid_gating_variance, gamma_variance));
579 1.1 brad params->m_Mean_Variance_Estimator___Gating_Duration_Minutes =
580 1.1 brad (params->m_Mean_Variance_Estimator___Gating_Duration_Minutes +
581 1.1 brad (fix16_mul(F16((VocAlgorithm_SAMPLING_INTERVAL / 60.)),
582 1.1 brad ((fix16_mul((F16(1.) - sigmoid_gating_mean),
583 1.1 brad F16((1. + VocAlgorithm_GATING_MAX_RATIO)))) -
584 1.1 brad F16(VocAlgorithm_GATING_MAX_RATIO)))));
585 1.1 brad if ((params->m_Mean_Variance_Estimator___Gating_Duration_Minutes <
586 1.1 brad F16(0.))) {
587 1.1 brad params->m_Mean_Variance_Estimator___Gating_Duration_Minutes = F16(0.);
588 1.1 brad }
589 1.1 brad if ((params->m_Mean_Variance_Estimator___Gating_Duration_Minutes >
590 1.1 brad params->m_Mean_Variance_Estimator__Gating_Max_Duration_Minutes)) {
591 1.1 brad params->m_Mean_Variance_Estimator___Uptime_Gating = F16(0.);
592 1.1 brad }
593 1.1 brad }
594 1.1 brad
595 1.1 brad static void VocAlgorithm__mean_variance_estimator__process(
596 1.1 brad VocAlgorithmParams* params, fix16_t sraw, fix16_t voc_index_from_prior) {
597 1.1 brad
598 1.1 brad fix16_t delta_sgp;
599 1.1 brad fix16_t c;
600 1.1 brad fix16_t additional_scaling;
601 1.1 brad
602 1.1 brad if ((params->m_Mean_Variance_Estimator___Initialized == false)) {
603 1.1 brad params->m_Mean_Variance_Estimator___Initialized = true;
604 1.1 brad params->m_Mean_Variance_Estimator___Sraw_Offset = sraw;
605 1.1 brad params->m_Mean_Variance_Estimator___Mean = F16(0.);
606 1.1 brad } else {
607 1.1 brad if (((params->m_Mean_Variance_Estimator___Mean >= F16(100.)) ||
608 1.1 brad (params->m_Mean_Variance_Estimator___Mean <= F16(-100.)))) {
609 1.1 brad params->m_Mean_Variance_Estimator___Sraw_Offset =
610 1.1 brad (params->m_Mean_Variance_Estimator___Sraw_Offset +
611 1.1 brad params->m_Mean_Variance_Estimator___Mean);
612 1.1 brad params->m_Mean_Variance_Estimator___Mean = F16(0.);
613 1.1 brad }
614 1.1 brad sraw = (sraw - params->m_Mean_Variance_Estimator___Sraw_Offset);
615 1.1 brad VocAlgorithm__mean_variance_estimator___calculate_gamma(
616 1.1 brad params, voc_index_from_prior);
617 1.1 brad delta_sgp = (fix16_div(
618 1.1 brad (sraw - params->m_Mean_Variance_Estimator___Mean),
619 1.1 brad F16(VocAlgorithm_MEAN_VARIANCE_ESTIMATOR__GAMMA_SCALING)));
620 1.1 brad if ((delta_sgp < F16(0.))) {
621 1.1 brad c = (params->m_Mean_Variance_Estimator___Std - delta_sgp);
622 1.1 brad } else {
623 1.1 brad c = (params->m_Mean_Variance_Estimator___Std + delta_sgp);
624 1.1 brad }
625 1.1 brad additional_scaling = F16(1.);
626 1.1 brad if ((c > F16(1440.))) {
627 1.1 brad additional_scaling = F16(4.);
628 1.1 brad }
629 1.1 brad params->m_Mean_Variance_Estimator___Std = (fix16_mul(
630 1.1 brad fix16_sqrt((fix16_mul(
631 1.1 brad additional_scaling,
632 1.1 brad (F16(VocAlgorithm_MEAN_VARIANCE_ESTIMATOR__GAMMA_SCALING) -
633 1.1 brad params->m_Mean_Variance_Estimator__Gamma_Variance)))),
634 1.1 brad fix16_sqrt((
635 1.1 brad (fix16_mul(
636 1.1 brad params->m_Mean_Variance_Estimator___Std,
637 1.1 brad (fix16_div(
638 1.1 brad params->m_Mean_Variance_Estimator___Std,
639 1.1 brad (fix16_mul(
640 1.1 brad F16(VocAlgorithm_MEAN_VARIANCE_ESTIMATOR__GAMMA_SCALING),
641 1.1 brad additional_scaling)))))) +
642 1.1 brad (fix16_mul(
643 1.1 brad (fix16_div(
644 1.1 brad (fix16_mul(
645 1.1 brad params->m_Mean_Variance_Estimator__Gamma_Variance,
646 1.1 brad delta_sgp)),
647 1.1 brad additional_scaling)),
648 1.1 brad delta_sgp))))));
649 1.1 brad params->m_Mean_Variance_Estimator___Mean =
650 1.1 brad (params->m_Mean_Variance_Estimator___Mean +
651 1.1 brad (fix16_mul(params->m_Mean_Variance_Estimator__Gamma_Mean,
652 1.1 brad delta_sgp)));
653 1.1 brad }
654 1.1 brad }
655 1.1 brad
656 1.1 brad static void VocAlgorithm__mean_variance_estimator___sigmoid__init(
657 1.1 brad VocAlgorithmParams* params) {
658 1.1 brad
659 1.1 brad VocAlgorithm__mean_variance_estimator___sigmoid__set_parameters(
660 1.1 brad params, F16(0.), F16(0.), F16(0.));
661 1.1 brad }
662 1.1 brad
663 1.1 brad static void VocAlgorithm__mean_variance_estimator___sigmoid__set_parameters(
664 1.1 brad VocAlgorithmParams* params, fix16_t L, fix16_t X0, fix16_t K) {
665 1.1 brad
666 1.1 brad params->m_Mean_Variance_Estimator___Sigmoid__L = L;
667 1.1 brad params->m_Mean_Variance_Estimator___Sigmoid__K = K;
668 1.1 brad params->m_Mean_Variance_Estimator___Sigmoid__X0 = X0;
669 1.1 brad }
670 1.1 brad
671 1.1 brad static fix16_t VocAlgorithm__mean_variance_estimator___sigmoid__process(
672 1.1 brad VocAlgorithmParams* params, fix16_t sample) {
673 1.1 brad
674 1.1 brad fix16_t x;
675 1.1 brad
676 1.1 brad x = (fix16_mul(params->m_Mean_Variance_Estimator___Sigmoid__K,
677 1.1 brad (sample - params->m_Mean_Variance_Estimator___Sigmoid__X0)));
678 1.1 brad if ((x < F16(-50.))) {
679 1.1 brad return params->m_Mean_Variance_Estimator___Sigmoid__L;
680 1.1 brad } else if ((x > F16(50.))) {
681 1.1 brad return F16(0.);
682 1.1 brad } else {
683 1.1 brad return (fix16_div(params->m_Mean_Variance_Estimator___Sigmoid__L,
684 1.1 brad (F16(1.) + fix16_exp(x))));
685 1.1 brad }
686 1.1 brad }
687 1.1 brad
688 1.1 brad static void VocAlgorithm__mox_model__init(VocAlgorithmParams* params) {
689 1.1 brad
690 1.1 brad VocAlgorithm__mox_model__set_parameters(params, F16(1.), F16(0.));
691 1.1 brad }
692 1.1 brad
693 1.1 brad static void VocAlgorithm__mox_model__set_parameters(VocAlgorithmParams* params,
694 1.1 brad fix16_t SRAW_STD,
695 1.1 brad fix16_t SRAW_MEAN) {
696 1.1 brad
697 1.1 brad params->m_Mox_Model__Sraw_Std = SRAW_STD;
698 1.1 brad params->m_Mox_Model__Sraw_Mean = SRAW_MEAN;
699 1.1 brad }
700 1.1 brad
701 1.1 brad static fix16_t VocAlgorithm__mox_model__process(VocAlgorithmParams* params,
702 1.1 brad fix16_t sraw) {
703 1.1 brad
704 1.1 brad return (fix16_mul((fix16_div((sraw - params->m_Mox_Model__Sraw_Mean),
705 1.1 brad (-(params->m_Mox_Model__Sraw_Std +
706 1.1 brad F16(VocAlgorithm_SRAW_STD_BONUS))))),
707 1.1 brad F16(VocAlgorithm_VOC_INDEX_GAIN)));
708 1.1 brad }
709 1.1 brad
710 1.1 brad static void VocAlgorithm__sigmoid_scaled__init(VocAlgorithmParams* params) {
711 1.1 brad
712 1.1 brad VocAlgorithm__sigmoid_scaled__set_parameters(params, F16(0.));
713 1.1 brad }
714 1.1 brad
715 1.1 brad static void
716 1.1 brad VocAlgorithm__sigmoid_scaled__set_parameters(VocAlgorithmParams* params,
717 1.1 brad fix16_t offset) {
718 1.1 brad
719 1.1 brad params->m_Sigmoid_Scaled__Offset = offset;
720 1.1 brad }
721 1.1 brad
722 1.1 brad static fix16_t VocAlgorithm__sigmoid_scaled__process(VocAlgorithmParams* params,
723 1.1 brad fix16_t sample) {
724 1.1 brad
725 1.1 brad fix16_t x;
726 1.1 brad fix16_t shift;
727 1.1 brad
728 1.1 brad x = (fix16_mul(F16(VocAlgorithm_SIGMOID_K),
729 1.1 brad (sample - F16(VocAlgorithm_SIGMOID_X0))));
730 1.1 brad if ((x < F16(-50.))) {
731 1.1 brad return F16(VocAlgorithm_SIGMOID_L);
732 1.1 brad } else if ((x > F16(50.))) {
733 1.1 brad return F16(0.);
734 1.1 brad } else {
735 1.1 brad if ((sample >= F16(0.))) {
736 1.1 brad shift = (fix16_div(
737 1.1 brad (F16(VocAlgorithm_SIGMOID_L) -
738 1.1 brad (fix16_mul(F16(5.), params->m_Sigmoid_Scaled__Offset))),
739 1.1 brad F16(4.)));
740 1.1 brad return ((fix16_div((F16(VocAlgorithm_SIGMOID_L) + shift),
741 1.1 brad (F16(1.) + fix16_exp(x)))) -
742 1.1 brad shift);
743 1.1 brad } else {
744 1.1 brad return (fix16_mul(
745 1.1 brad (fix16_div(params->m_Sigmoid_Scaled__Offset,
746 1.1 brad F16(VocAlgorithm_VOC_INDEX_OFFSET_DEFAULT))),
747 1.1 brad (fix16_div(F16(VocAlgorithm_SIGMOID_L),
748 1.1 brad (F16(1.) + fix16_exp(x))))));
749 1.1 brad }
750 1.1 brad }
751 1.1 brad }
752 1.1 brad
753 1.1 brad static void VocAlgorithm__adaptive_lowpass__init(VocAlgorithmParams* params) {
754 1.1 brad
755 1.1 brad VocAlgorithm__adaptive_lowpass__set_parameters(params);
756 1.1 brad }
757 1.1 brad
758 1.1 brad static void
759 1.1 brad VocAlgorithm__adaptive_lowpass__set_parameters(VocAlgorithmParams* params) {
760 1.1 brad
761 1.1 brad params->m_Adaptive_Lowpass__A1 =
762 1.1 brad F16((VocAlgorithm_SAMPLING_INTERVAL /
763 1.1 brad (VocAlgorithm_LP_TAU_FAST + VocAlgorithm_SAMPLING_INTERVAL)));
764 1.1 brad params->m_Adaptive_Lowpass__A2 =
765 1.1 brad F16((VocAlgorithm_SAMPLING_INTERVAL /
766 1.1 brad (VocAlgorithm_LP_TAU_SLOW + VocAlgorithm_SAMPLING_INTERVAL)));
767 1.1 brad params->m_Adaptive_Lowpass___Initialized = false;
768 1.1 brad }
769 1.1 brad
770 1.1 brad static fix16_t
771 1.1 brad VocAlgorithm__adaptive_lowpass__process(VocAlgorithmParams* params,
772 1.1 brad fix16_t sample) {
773 1.1 brad
774 1.1 brad fix16_t abs_delta;
775 1.1 brad fix16_t F1;
776 1.1 brad fix16_t tau_a;
777 1.1 brad fix16_t a3;
778 1.1 brad
779 1.1 brad if ((params->m_Adaptive_Lowpass___Initialized == false)) {
780 1.1 brad params->m_Adaptive_Lowpass___X1 = sample;
781 1.1 brad params->m_Adaptive_Lowpass___X2 = sample;
782 1.1 brad params->m_Adaptive_Lowpass___X3 = sample;
783 1.1 brad params->m_Adaptive_Lowpass___Initialized = true;
784 1.1 brad }
785 1.1 brad params->m_Adaptive_Lowpass___X1 =
786 1.1 brad ((fix16_mul((F16(1.) - params->m_Adaptive_Lowpass__A1),
787 1.1 brad params->m_Adaptive_Lowpass___X1)) +
788 1.1 brad (fix16_mul(params->m_Adaptive_Lowpass__A1, sample)));
789 1.1 brad params->m_Adaptive_Lowpass___X2 =
790 1.1 brad ((fix16_mul((F16(1.) - params->m_Adaptive_Lowpass__A2),
791 1.1 brad params->m_Adaptive_Lowpass___X2)) +
792 1.1 brad (fix16_mul(params->m_Adaptive_Lowpass__A2, sample)));
793 1.1 brad abs_delta =
794 1.1 brad (params->m_Adaptive_Lowpass___X1 - params->m_Adaptive_Lowpass___X2);
795 1.1 brad if ((abs_delta < F16(0.))) {
796 1.1 brad abs_delta = (-abs_delta);
797 1.1 brad }
798 1.1 brad F1 = fix16_exp((fix16_mul(F16(VocAlgorithm_LP_ALPHA), abs_delta)));
799 1.1 brad tau_a =
800 1.1 brad ((fix16_mul(F16((VocAlgorithm_LP_TAU_SLOW - VocAlgorithm_LP_TAU_FAST)),
801 1.1 brad F1)) +
802 1.1 brad F16(VocAlgorithm_LP_TAU_FAST));
803 1.1 brad a3 = (fix16_div(F16(VocAlgorithm_SAMPLING_INTERVAL),
804 1.1 brad (F16(VocAlgorithm_SAMPLING_INTERVAL) + tau_a)));
805 1.1 brad params->m_Adaptive_Lowpass___X3 =
806 1.1 brad ((fix16_mul((F16(1.) - a3), params->m_Adaptive_Lowpass___X3)) +
807 1.1 brad (fix16_mul(a3, sample)));
808 1.1 brad return params->m_Adaptive_Lowpass___X3;
809 1.1 brad }
810