LCOV - code coverage report
Current view: top level - lib_lc3plus - plc_phecu_spec_ana.c (source / functions) Hit Total Coverage
Test: Coverage on main -- short test vectors @ 6c9ddc4024a9c0e1ecb8f643f114a84a0e26ec6b Lines: 0 220 0.0 %
Date: 2025-05-23 08:37:30 Functions: 0 3 0.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             : *                        ETSI TS 103 634 V1.5.1                               *
       3             : *              Low Complexity Communication Codec Plus (LC3plus)              *
       4             : *                                                                             *
       5             : * Copyright licence is solely granted through ETSI Intellectual Property      *
       6             : * Rights Policy, 3rd April 2019. No patent licence is granted by implication, *
       7             : * estoppel or otherwise.                                                      *
       8             : ******************************************************************************/
       9             : 
      10             : #include "options.h"
      11             : #include "wmc_auto.h"
      12             : #include "defines.h"
      13             : #include "functions.h"
      14             : 
      15             : #define PEAK_LOCATOR_RES_FX    1  /*  fixed point resolution minimum value  */
      16             : 
      17             : static LC3_INT16  plc_phEcu_find_ind_fx(                        /* o  : output maximum  indx 0.. len-1    */
      18             :     const LC3_INT16 *inp,      /* i  : vector     */
      19             :     const LC3_INT16  len,      /* i  : length     */
      20             :     const LC3_INT16  val   /* i  : value to find     */
      21             : );
      22             : 
      23             : static void plc_phEcu_peak_locator_fxlike(const LC3_INT16 *inp, /* i: vector with values >=0   ,Qx      */
      24             :     const LC3_INT16  inp_len,              /* i: length of inp                                 */
      25             :     LC3_INT16 *      int_plocs,            /* o:  array of filtered integer plocs           Q0 */
      26             :     LC3_INT16 *      n_fsc,                /* o:  total_ number of filtered located highs   Q0 */
      27             :     const LC3_INT16  sens,                 /* i  sensitivity,   Qx */
      28             :     const LC3_INT16  inp_high,             /* i  global high ,  Qx */
      29             :     const LC3_INT16  inp_low               /* i:  global low,  Qx */
      30             : );
      31             : 
      32             : 
      33           0 : void plc_phEcu_spec_ana(LC3_FLOAT* xfp, 
      34             :    LC3_INT32 xfp_len, 
      35             :    const LC3_FLOAT* whr, 
      36             :    LC3_FLOAT *pfind_sensPtr, 
      37             :    LC3_INT32* plocs, 
      38             :    LC3_INT32* n_plocs, 
      39             :    LC3_FLOAT* f0est, 
      40             :    Complex* x, 
      41             :    LC3_INT32* x_len, 
      42             :    LC3_FLOAT * f0hzLtpBinPtr, 
      43             :    LC3_FLOAT * f0gainLtpPtr, 
      44             :    LC3_INT32 bw_idx,
      45             :    Fft* PhEcu_fft
      46             : ) 
      47             : {
      48             : 
      49             : 
      50             :    LC3_INT32 i, peak_range_1, curr;
      51             :    LC3_FLOAT xfp_w[MAX_PLC_LPROT];
      52             :  
      53           0 :    LC3_FLOAT Xabs[MAX_LEN] = {0};
      54             :    LC3_FLOAT inp_high, inp_low, sens;
      55             :    LC3_FLOAT interPos;
      56             :    Complex   Xana_p[3];
      57             :    LC3_INT32   P_in_plocs;
      58             :    LC3_INT32   nSubs;
      59             :    LC3_INT32   n_plocs_in;
      60             :    LC3_FLOAT phEcu_c_jacob[1];
      61             : 
      62             :     LC3_FLOAT fx_fft_scale;
      63             :     LC3_FLOAT fft_fs_scale;
      64             : 
      65             :     LC3_FLOAT max_xfp_abs;
      66             :     LC3_FLOAT PLC2_Q_flt;
      67             :     LC3_FLOAT Q_scale_flt;
      68             : 
      69             :     LC3_INT16    Xabs_fx[MAX_LEN];
      70             :     LC3_INT16    plocs_fx[MAX_LEN];
      71             : 
      72             :     LC3_INT16    sens_fx;
      73             :     LC3_INT16    inp_high_fx;
      74             :     LC3_INT16    inp_low_fx;
      75             :     LC3_INT16    n_plocs_fx;
      76             : 
      77             :     LC3_FLOAT pfind_sens  ;
      78             :     LC3_FLOAT f0hzLtpBin  ; 
      79             :     LC3_FLOAT f0gainLtp   ; 
      80             :  
      81           0 :    pfind_sens = *pfind_sensPtr;
      82           0 :    f0hzLtpBin = *f0hzLtpBinPtr;
      83           0 :    f0gainLtp = *f0gainLtpPtr;
      84             : 
      85           0 :     for (i = 0; i < xfp_len; i++)
      86             :     {
      87           0 :        xfp_w[i] = xfp[i] * whr[i]; /* whr windowing may be split into three segments ,  two loops,  and possibly inplace */
      88             :     }
      89           0 :     real_fft_apply(PhEcu_fft, xfp_w,  (LC3_FLOAT *)x); 
      90             : 
      91           0 :     x[xfp_len/2].r = x[0].i;  /* move  the real Fs/2 value to end  */
      92           0 :     x[xfp_len/2].i = 0;       /* safety clear imaginary   Fs/2 value at  end */
      93           0 :     x[0].i = 0.0;             /* safety, make DC  value only real  */
      94             : 
      95             :     
      96           0 :     *x_len = xfp_len/2 + 1;
      97             :     
      98           0 :    i =(LC3_INT32) LC3_FLOOR(20000.0/PHECU_FRES)+1;
      99           0 :    zero_cmplx( &(x[i]),  *x_len - i);
     100             :     
     101           0 :     peak_range_1 = (LC3_INT32) MIN(*x_len, (40000.0 / 100 * 1.6) / 2 + 1);
     102             :     
     103           0 :    plc_phEcu_fft_spec2_sqrt_approx(x, peak_range_1, Xabs);
     104             : 
     105           0 :    zero_float(&(Xabs[peak_range_1]), *x_len - peak_range_1);
     106             :     
     107           0 :     inp_high = Xabs[0];
     108           0 :     inp_low = Xabs[0];
     109             :     
     110           0 :     for (i = 1; i < peak_range_1; i++) {
     111           0 :         inp_high = MAX(inp_high, Xabs[i]);
     112           0 :         inp_low = MIN(inp_low, Xabs[i]);
     113             :     }
     114             :     
     115           0 :     sens = (inp_high-inp_low)*(1-pfind_sens);
     116             : 
     117           0 :    if (inp_high >  ((LC3_FLOAT) PEAK_LOCATOR_RES_FX)/2.0)
     118             :     { 
     119             :        {
     120             :           /* from ROM constants.c */
     121           0 :           LC3_FLOAT fx_fft_scales[5] = { 6, 7, 7, 8, 8 };           /*NB,WB, sSWB, SWB, FB*/
     122           0 :           fx_fft_scale = LC3_POW(2.0, fx_fft_scales[bw_idx]);  /*% scaling due to up / dn pre shifts in fx FFT */
     123             :        }
     124             :        {   /* from  ROM constants.c */
     125           0 :           LC3_FLOAT fx_fs_scales[5] = { 1.0, 1.0, 1.5, 1.0, 1.5 };           /*NB,WB, sSWB, SWB, FB*/
     126           0 :           fft_fs_scale = fx_fs_scales[bw_idx];
     127             :        }
     128             : 
     129             : 
     130           0 :         max_xfp_abs = (LC3_FLOAT) LC3_FABS(xfp[0]);
     131           0 :         for (i = 1; i < xfp_len; i++) {
     132           0 :             max_xfp_abs = (LC3_FLOAT) MAX(max_xfp_abs, LC3_FABS(xfp[i]));
     133             :         } 
     134             :         
     135           0 :         if (max_xfp_abs >= 0.5)
     136             :         {  
     137           0 :            PLC2_Q_flt = (LC3_FLOAT)LC3_FLOOR(LC3_LOGTWO(32768 / 2 / 2 / max_xfp_abs));
     138           0 :            Q_scale_flt = LC3_POW(2.0, PLC2_Q_flt) / fx_fft_scale / fft_fs_scale; /* basop way using xfp scale */
     139             : 
     140             :            /*   C-Float additional safety limit/verification of  the integer xfp based scaling using the available  C-float Xabs max value inp_high as well */
     141             :            {
     142             :               LC3_FLOAT tmp_scale;
     143           0 :               tmp_scale = LC3_POW(2.0, LC3_FLOOR(LC3_LOGTWO(32768 / 2 / 2 / inp_high)));
     144           0 :               if (Q_scale_flt > tmp_scale) {
     145           0 :                  Q_scale_flt = tmp_scale;              
     146             :               }
     147             :            }
     148             :            /* Round sens, inp_high, inp_low according to BASOP fix-point scaling */
     149             : 
     150           0 :            for (i = 0; i < peak_range_1; i++) {
     151           0 :               Xabs_fx[i] = (LC3_INT16)   LC3_ROUND(Xabs[i]  * Q_scale_flt) ;
     152             :            }
     153           0 :            sens_fx       = (LC3_INT16)   LC3_ROUND(sens      * Q_scale_flt) ;    
     154           0 :            inp_high_fx   = (LC3_INT16)   LC3_ROUND(inp_high  * Q_scale_flt) ;
     155           0 :            inp_low_fx    = (LC3_INT16)   LC3_ROUND(inp_low   * Q_scale_flt) ;
     156           0 :            plc_phEcu_peak_locator_fxlike(Xabs_fx, peak_range_1, plocs_fx, &n_plocs_fx, sens_fx, inp_high_fx, inp_low_fx);
     157             :            
     158           0 :            *n_plocs = (LC3_INT32)n_plocs_fx;
     159           0 :            for (i = 0; i < *n_plocs; i++) {
     160           0 :               plocs[i] = (LC3_INT32)plocs_fx[i]; /* short Word16  values now stored/saved  as Word32 */
     161             :            }
     162             :         }      
     163             :         else 
     164             :         {
     165           0 :                 *n_plocs = 0;   /* time domain xfp level near zero */
     166             :         }
     167             :     }
     168             :     else
     169             :     {
     170           0 :         *n_plocs = 0; /* Freq domain  Xabs  max level near zero */
     171             :     }
     172             :     
     173           0 :     for (i = 0; i < *n_plocs; i++) {
     174           0 :       curr = plocs[i];
     175           0 :         if (curr == 0) {
     176           0 :             interPos = plc_phEcu_interp_max(Xabs, 3);  /* returns 0.0 ... 2.0  */
     177           0 :             if (interPos == 2) {
     178             :             /* integer peak was at DC, restrict to one of coeffs at [DC or   DC+1] */ 
     179           0 :                 interPos = plc_phEcu_interp_max(Xabs, 2); /* returns 0.0 or 1.0 */
     180             :             }
     181           0 :             interPos += plocs[i];
     182           0 :         } else if (curr == 1) {
     183           0 :             interPos = plc_phEcu_interp_max(Xabs, 3);
     184           0 :             interPos += plocs[i] - 1;
     185           0 :         } else if (curr == *x_len - 2) {
     186           0 :             interPos = plc_phEcu_interp_max(&Xabs[*x_len - 3], 3);
     187           0 :             interPos += plocs[i] - 1;
     188           0 :         } else if (curr == *x_len - 1) {
     189             :          /* integer curr at Fs/2, a real coeff  */
     190           0 :             interPos = plc_phEcu_interp_max(&Xabs[*x_len - 3], 3); /* returns 0.0 ... 2.0  */
     191           0 :          interPos += plocs[i] - 2;    /*  valid for range   ]... 1.0 ... 2.0]  , where 1 is fs/2-1 and 2.0 is Fs/2    */
     192           0 :             if (interPos == 0) {
     193             :             /* restrict to one of coeffs at [fs/2-1,  fs/2 ] */
     194           0 :             interPos = plc_phEcu_interp_max(&Xabs[*x_len - 2], 2);    /* returns 0.0 or 1.0 */
     195           0 :                 interPos += plocs[i] - 1;
     196             :             } 
     197             : 
     198           0 :             if (interPos > (*x_len - 1) ) { /* interPos only defined  up to  Fs/2  */
     199           0 :                 interPos = (LC3_FLOAT)(*x_len - 1);
     200             :             }
     201             :       } else {
     202           0 :             Xana_p[0] = x[plocs[i]-1];
     203           0 :             Xana_p[1] = x[plocs[i]];
     204           0 :             Xana_p[2] = x[plocs[i]+1];
     205           0 :          phEcu_c_jacob[0] = (LC3_FLOAT)PHECU_C_JACOB;
     206           0 :             interPos = plc_phEcu_imax2_jacobsen_mag(Xana_p, phEcu_c_jacob );
     207           0 :             interPos += (LC3_FLOAT) plocs[i];
     208             :         }    
     209           0 :         f0est[i] = interPos;
     210             :     }
     211             :     
     212           0 :     if (*n_plocs >= 2 &&   plocs[0] == 0 &&
     213           0 :       f0est[0] > f0est[1] && plocs[1] <= 2 && Xabs[0] < Xabs[plocs[1]+1]) 
     214             :    {
     215           0 :         f0est[0] = f0est[1];
     216             :     }
     217             :     
     218           0 :     P_in_plocs = plc_phEcu_pitch_in_plocs(plocs, *n_plocs);
     219             :     
     220           0 :     if (f0hzLtpBin > 0.0 && P_in_plocs > 0) {
     221           0 :         nSubs = 2;
     222           0 :         n_plocs_in = *n_plocs;
     223           0 :         plc_phEcu_LF_peak_analysis(plocs, n_plocs, f0est, Xabs, &f0hzLtpBin, &f0gainLtp, nSubs);
     224             :         
     225           0 :         if (n_plocs_in == *n_plocs) {
     226           0 :             nSubs = 3;
     227           0 :             plc_phEcu_F0_refine_first(plocs, *n_plocs, f0est, *x_len, &f0hzLtpBin, &f0gainLtp, nSubs);
     228             :         }
     229             :     }
     230             :     
     231           0 :     if (f0gainLtp > 0.0 && f0gainLtp < 0.5 && *n_plocs > 14) {
     232           0 :         if (P_in_plocs > 0) {
     233           0 :             *n_plocs = 0;
     234             :         }
     235             :     }
     236             : 
     237           0 :    return;
     238             : }
     239             : 
     240             : 
     241             : #define sub(a,b) (a - b)
     242             : #define add(a,b) (a + b)
     243             : #define s_xor(a,b) (a ^ b)
     244             : 
     245             : /* in case a  value (e.g max or min)  is already known , find the first corresponding array  index */
     246           0 : static LC3_INT16 plc_phEcu_find_ind_fx(                        /* o  : output maximum  indx 0.. len-1    */
     247             :     const LC3_INT16 *inp,      /* i  : vector     */
     248             :     const LC3_INT16  len,      /* i  : length     */
     249             :     const LC3_INT16 val   /* i  : value to find     */
     250             : )
     251             : {
     252             :     LC3_INT16  val_ind;
     253             :     LC3_INT16 pos;
     254             : 
     255           0 :     val_ind = -1;  
     256             : 
     257           0 :     for(pos = 0; pos < len; pos++)
     258             :     {
     259           0 :         if (sub(inp[pos], val) == 0)
     260             :         {
     261           0 :             val_ind = pos;
     262             :         }
     263             :     }
     264             : 
     265           0 :     return   val_ind;
     266             : }
     267             : 
     268             : 
     269             : 
     270             : /* BASOP  function adapted to compile in float/integer  environment */
     271             : /*-----------------------------------------------------------------------------
     272             :  * plc_phEcu_peak_locator_fxlike()
     273             :  *----------------------------------------------------------------------------*/
     274           0 : static void plc_phEcu_peak_locator_fxlike(const LC3_INT16 *inp, /* i: vector with values >=0   ,Qx      */
     275             :     const LC3_INT16  inp_len,              /* i: length of inp                                 */
     276             :     LC3_INT16 *      int_plocs,            /* o:  array of filtered integer plocs           Q0 */
     277             :     LC3_INT16 *      n_fsc,                /* o:  total_ number of filtered located highs   Q0 */
     278             :     const LC3_INT16  sens,                 /* i  sensitivity,   Qx */
     279             :     const LC3_INT16  inp_high,             /* i  global high ,  Qx */
     280             :     const LC3_INT16  inp_low               /* i:  global low,  Qx */
     281             : )
     282             : {
     283             : 
     284             :    LC3_INT16        j, k, n, idx_high, idx_low;
     285             :    LC3_INT16       inp_len_minus1;
     286             :    LC3_INT16       pairs_start, pairs_end;
     287             :    LC3_INT16       *p_tmp;
     288             :    LC3_INT16       prev_delta, curr_delta;
     289             :    LC3_INT16       delta_predc, delta_fin;
     290             :    LC3_INT16       add_dc_flag, add_fin_flag;
     291             :    LC3_INT16       low_val_cand_pairs, val_range;
     292             :    LC3_INT16       num_pairs, n_tail_values;
     293             :    LC3_INT16       cand_phase_start, cand_idx, prev_low_plus_sens, tmp;
     294             :    LC3_INT16       cand_high, prev_low;
     295             :    LC3_INT16       *cand_pairs;  /*  actually  [DC ] + pairs + [FS/2]   */
     296             : 
     297             :    LC3_INT16       sc_idx[1 + 368 + 1];
     298             :    LC3_INT16       cand_pairs_buf[1 + 1 + 368 + 1];
     299             :    LC3_INT16       fsc_idx[1 + 368 / 2 + 1];
     300             : 
     301             :    
     302           0 :     inp_len_minus1 = sub(inp_len, 1);  /* size of delta=derivative array ,and last index in inp */
     303             : 
     304           0 :     cand_pairs = &cand_pairs_buf[1];  /* ptr init , make space for storing a lowest  amplitude value in location  -1    */
     305           0 :     pairs_start = 1;                 /* adjusted to zero or 1 or 2 when/if,  DC is injected  as sc_idx[0], or initial plateau skipped */
     306             : 
     307           0 :     p_tmp = &(sc_idx[pairs_start]); /* ptr init */
     308             : 
     309             : 
     310             :     /*  xor high/low pairs of delta_inp and save sign changes */
     311           0 :     prev_delta = sub(inp[1], inp[0]);  /*  precompute very first delta */
     312             : 
     313           0 :     for(n = 1;  n < inp_len_minus1; n++)
     314             :     {   /* sign change analysis */
     315           0 :         curr_delta = sub(inp[n + 1], inp[n]);    /*  n+1 ,n ,   are loop ptrs   */
     316           0 :         if (s_xor(prev_delta, curr_delta) < 0)   /* a "0" delta  treated as a  positive sign */
     317             :         {
     318           0 :             *p_tmp++ = n;               /* store sign change bin locations , location n in the inp[] signal */
     319             :         }
     320           0 :         prev_delta = curr_delta; 
     321             :     }
     322             : 
     323           0 :     k = (LC3_INT16)(p_tmp - &(sc_idx[pairs_start]));
     324             : 
     325             :     /* copy sign change location values to a pairs array */
     326             :     /* leave one initial sc_idx location open for a potential initial DC value */
     327             : 
     328           0 :     for(j = 0; j < k; j++){
     329           0 :         cand_pairs[j + pairs_start] = inp[sc_idx[j + pairs_start]];     
     330             :     }
     331             : 
     332             :     /* filter away a potential  single initial/trailing  plateau
     333             :       to enable correct analysis for adding DC or  fs/2 bins */
     334             : 
     335             :     
     336           0 :     if((sub(k, 2) >= 0) &&
     337           0 :         (sub(cand_pairs[pairs_start], cand_pairs[pairs_start + 1]) == 0)){
     338           0 :         pairs_start = add(pairs_start, 1);
     339           0 :         k = sub(k, 1);
     340             :     }
     341             : 
     342             :     /* filter away potential single trailing plateu */
     343           0 :     pairs_end = sub(add(pairs_start, k), 1);  /* point  to last established  sign change element  */
     344             :     
     345           0 :     if ((sub(k, 2) >= 0) &&
     346           0 :         (sub(cand_pairs[sub(pairs_end, 1)], cand_pairs[pairs_end]) == 0)){
     347           0 :         k = sub(k, 1);
     348             :     }
     349           0 :     pairs_end = sub(add(pairs_start, k), 1);  /*  recalc  ptr to last element  */
     350             : 
     351             : 
     352             :     /* conditionally add high/lows  on both sides of input (pre_dc or fin) as  candidates  */
     353           0 :     add_dc_flag = 0; 
     354           0 :     add_fin_flag = 0; 
     355             : 
     356             : 
     357           0 :     if(sub(k, 1) == 0) /*  one single sign change found special case */
     358             :     {
     359           0 :         if (sub(inp[0], cand_pairs[pairs_start]) != 0)
     360             :         {
     361           0 :             add_dc_flag = 1;    /* not plateau    */
     362             :         }
     363             : 
     364           0 :         if (sub(cand_pairs[pairs_end], inp[inp_len_minus1]) != 0)
     365             :         {
     366           0 :             add_fin_flag = 1;     /* not plateau    */
     367             :         }
     368             :     }
     369             : 
     370           0 :     if(sub(k, 2) >= 0)
     371             :     {
     372           0 :         delta_predc = sub(cand_pairs[pairs_start + 1], cand_pairs[pairs_start]);
     373           0 :         delta_fin = sub(cand_pairs[pairs_end], cand_pairs[pairs_end - 1]);
     374             : 
     375             :         /* plateaus are allowed to be detected by xor sign change,
     376             :            but still not allowed at the start nor  at the end */
     377             : 
     378           0 :         add_dc_flag = 1;   
     379           0 :         if (sub(inp[0], cand_pairs[pairs_start]) == 0)
     380             :         {
     381           0 :             add_dc_flag = 0;      /* plateau down or , plateaus up., --> do not add DC  */
     382             :         }
     383             : 
     384             :         
     385           0 :         if ((sub(inp[0], cand_pairs[pairs_start]) < 0) && (delta_predc > 0))
     386             :         {
     387           0 :             add_dc_flag = -1;    /*UP - up    ... replace */
     388             :         }
     389             :         
     390           0 :         if ((sub(inp[0], cand_pairs[pairs_start]) > 0) && (delta_predc < 0))
     391             :         {
     392           0 :             add_dc_flag = -1;      /* DOWN - down ... % replace */
     393             :         }
     394             : 
     395           0 :         add_fin_flag = 1;   
     396           0 :         if (sub(cand_pairs[pairs_end], inp[inp_len_minus1]) == 0)
     397             :         {
     398           0 :             add_fin_flag = 0;      /* up - plateau ... */
     399             :         }
     400             :         
     401           0 :         if ((delta_fin > 0) && (sub(cand_pairs[pairs_end], inp[inp_len_minus1]) < 0))
     402             :         {
     403           0 :             add_fin_flag = -1;      /* up - UP ...    % replace , hard to hit  */
     404             :         }
     405             :         
     406           0 :         if ((delta_fin < 0) && (sub(cand_pairs[pairs_end], inp[inp_len_minus1]) > 0))
     407             :         {
     408           0 :             add_fin_flag = -1;    /*down - DOWN ... % replace */
     409             :         }
     410             : 
     411             :     }
     412             : 
     413           0 :     if(add_dc_flag > 0)
     414             :     {  /* add DC */
     415           0 :         pairs_start = sub(pairs_start, 1);
     416           0 :         cand_pairs[pairs_start] = inp[0]; 
     417           0 :         sc_idx[pairs_start] = 0; 
     418           0 :         k = add(k, 1);
     419             :     }
     420           0 :     if(add_dc_flag < 0)
     421             :     { /*   -1 -->  replace with DC*/
     422           0 :         cand_pairs[pairs_start] = inp[0]; 
     423           0 :         sc_idx[pairs_start] = 0; 
     424             :     }
     425             : 
     426           0 :     if(add_fin_flag > 0)
     427             :     {  /* add FS/2  */
     428           0 :         pairs_end = add(pairs_end, 1);
     429           0 :         cand_pairs[pairs_end] = inp[inp_len_minus1]; 
     430           0 :         sc_idx[pairs_end] = inp_len_minus1; 
     431           0 :         k = add(k, 1);
     432             :     }
     433           0 :     if(add_fin_flag < 0)
     434             :     {  /*    -1, replace tail with FS/2*/
     435           0 :         cand_pairs[pairs_end] = inp[inp_len_minus1]; 
     436           0 :         sc_idx[pairs_end]     = inp_len_minus1; 
     437             :     }
     438             :     /* preliminary cand_pairs now only have  highs , lows , no initial/trailing plateaus */
     439             : 
     440             : 
     441             :     /*  we allow the  DC/FsBy2 lows to be used as the candidatelLow  */
     442           0 :     low_val_cand_pairs = inp_low;   
     443           0 :     val_range = sub(inp_high, low_val_cand_pairs); /* used to determine if search is useful at all */
     444             : 
     445             :     
     446           0 :     if ((sub(val_range, PEAK_LOCATOR_RES_FX) < 0) ||
     447           0 :         (sub(inp_high, sens) < 0))
     448             :     {
     449           0 :         k = 0;   
     450             :     }
     451             : 
     452             :     
     453           0 :     if ((k == 0) && (sub(val_range, sens) >= 0))
     454             :     {
     455           0 :         k = 1;  
     456             :     }
     457             : 
     458             : 
     459           0 :     if(sub(k, 2) > 0)
     460             :     {
     461             :         /*  low, high, low, ... or
     462             :             high, low, high, ...*/
     463             : 
     464           0 :         cand_phase_start = pairs_start;       /*assume first candidate   is a high */
     465           0 :         if (sub(cand_pairs[pairs_start], cand_pairs[pairs_start + 1]) < 0)
     466             :         {
     467           0 :             cand_phase_start = add(pairs_start, 1);     /* first is a low, --> skip to next higher cand  */
     468             :         }
     469             : 
     470             :         /*  high, low, high, ... */
     471           0 :         tmp = k;   
     472           0 :         if (sub(cand_phase_start, pairs_start) != 0)
     473             :         {
     474           0 :             tmp = sub(tmp, 1);
     475             :         }
     476           0 :         num_pairs = tmp / 2; // shr(tmp, 1);
     477           0 :         n_tail_values = sub(tmp, num_pairs * 2); // shl(num_pairs, 1));
     478             : 
     479             :         /* filter  preliminary  sign changes into sensitivity filtered sign changes */
     480             : 
     481           0 :         *n_fsc = 0;                        /*   counter of  filtered fsc_idx */
     482           0 :         cand_high = low_val_cand_pairs;      
     483           0 :         cand_idx = -1;                       /*  sentinel location for no high cand found yet. */
     484           0 :         cand_pairs[-1] = low_val_cand_pairs; 
     485             : 
     486           0 :         prev_low = low_val_cand_pairs;    
     487           0 :         prev_low_plus_sens = add(prev_low, sens);
     488             : 
     489             :         /* filter loop for   high - low sign change pairs */
     490             :         /* idx_high, idx_low are raw pointers into the  cand_pairs and sc_idx arrays */
     491             : 
     492           0 :         for(idx_high = cand_phase_start;  idx_high < (cand_phase_start + 2 * num_pairs); idx_high += 2)
     493             :         {
     494           0 :             idx_low = idx_high + 1;  /* loop ptr increase */
     495             : 
     496             :             /* new high candidate  larger than previous candidate  and   */
     497             :             /* sensitivity still larger  than the the previous low */
     498           0 :             tmp = MAX(cand_high, prev_low_plus_sens);
     499           0 :             if (sub(cand_pairs[idx_high], tmp) > 0)
     500             :             {
     501           0 :                 cand_idx = idx_high;                 /*   enable or shift candidate position fwd */
     502             :             }
     503           0 :             cand_high = cand_pairs[cand_idx];    /* NB, cand_pairs[-1] , has the low_val_cand_pairs value  stored */
     504             : 
     505             :             /* now check the fwd  idx_low  of the current  {high,low} pair  */
     506           0 :             prev_low = MIN(cand_pairs[idx_low], prev_low);
     507             : 
     508           0 :             tmp = sub(cand_high, sens);
     509           0 :             if(sub(tmp, cand_pairs[idx_low]) > 0)
     510             :             {
     511             :                 /*  this low  point is now low enough to fix a previous high candidate */
     512             : 
     513           0 :                 fsc_idx[*n_fsc] = cand_idx;    /*%  add cand high idx  -> output idx list*/
     514           0 :                 *n_fsc = add(*n_fsc, 1);
     515             : 
     516           0 :                 prev_low = cand_pairs[idx_low];     /*  use this value  as new low estimate */
     517           0 :                 cand_idx = -1;                     /*   no  candidate until next pair or tail  bin, and pt to lowVal */
     518           0 :                 cand_high = low_val_cand_pairs;    /*  enable next candidate to be selected immediately  */
     519             :             }
     520           0 :             prev_low_plus_sens = add(prev_low, sens);
     521             :         } /* { high, low} for loop */
     522             : 
     523             :         
     524           0 :         if((n_tail_values == 0) && (cand_idx >= 0))
     525             :         {
     526             :             /*  no tail  low or high value  to analyze
     527             :                 still may need to lock a non-locked but qualified candidate */
     528           0 :             fsc_idx[*n_fsc] = cand_idx;  
     529           0 :             *n_fsc = add(*n_fsc, 1);
     530             :         }
     531             : 
     532             : 
     533             :         /* cand_pairs vector may have a last orphan value */
     534           0 :         if(n_tail_values > 0)
     535             :         {
     536             :             /*   cand_pairs vector may have a last orphan tail value */
     537             :             /*
     538             :              logic boils down to   if (nTailValues > 0) && (cand_pairs(n_end) > tmp)
     539             :               there is a last  one  trailing high to process
     540             : 
     541             :              a) the last high, may be a new high Peak if we have not yet
     542             :                 locked  the current candidate
     543             :              b) if we have locked the last candidate, the last high may also be
     544             :                 a highpeak if it is high enough from the(newly set previous) valley floor.
     545             : 
     546             :                tmp=a||b
     547             :             */
     548             : 
     549           0 :             tmp = MAX(cand_high, prev_low_plus_sens);
     550           0 :             tmp = sub(cand_pairs[pairs_end], tmp);
     551           0 :             if(tmp > 0)
     552             :             {
     553           0 :                 fsc_idx[*n_fsc] = pairs_end;            
     554           0 :                 *n_fsc = add(*n_fsc, 1);
     555             :             }
     556             :             else
     557             :             {
     558           0 :                if(cand_idx >= 0)
     559             :                { /* we have a previously established high candidate */
     560           0 :                   fsc_idx[*n_fsc] = cand_idx;   
     561           0 :                   *n_fsc = add(*n_fsc, 1);
     562             :                }
     563             : 
     564             :             }
     565             :         }
     566             : 
     567             :         /* move high locations info from  fsc_idx , to output  */
     568           0 :         for(j = 0; j < *n_fsc; j++)
     569             :         { 
     570           0 :            int_plocs[j] = sc_idx[fsc_idx[j]];    
     571             :              
     572             :         }
     573             : 
     574             :     } /* end of  pairs + [tail] section filtering  */
     575             :     else
     576             :     {
     577             :         /* constant/single  rise or constant decay or very low overall values,   cases */
     578           0 :         *n_fsc = 0;  
     579             :         
     580           0 :         tmp = sub(inp_high, sens);
     581           0 :         if((k != 0) && (sub(tmp, low_val_cand_pairs) > 0))
     582             :         {
     583             :             /*      low,high */
     584             :             /*      high,low */
     585           0 :             tmp = plc_phEcu_find_ind_fx(inp, inp_len, inp_high);  
     586           0 :             int_plocs[0] = tmp;    /*  simply  locate the   high peak*/
     587           0 :             *n_fsc = 1;     
     588           0 :             if (tmp < 0)
     589             :             {  /*safety in case max value index was not found */
     590           0 :                *n_fsc = 0; 
     591             :             }
     592             :          }
     593             :     }
     594             : 
     595           0 :     return;
     596             : }
     597             : 

Generated by: LCOV version 1.14