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 :
|