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