Home | History | Annotate | Line # | Download | only in i2c
      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