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