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