Lines Matching +full:scaled +full:- +full:output +full:- +full:hz
1 // SPDX-License-Identifier: GPL-2.0-only
3 * SpanDSP - a series of DSP components for telephony
5 * echo.c - A line echo canceller. This code is being developed
30 especially for double talk - there were always cases where my DTD
50 on 4 real-world samples.
54 on the real-world samples. I have no idea why, perhaps a scaling
59 dot product) compared to the current sample-by-sample update.
66 Path Models", IEEE Transactions on communications, COM-25,
87 Thanks to Steve Underwood, Jean-Marc Valin, and Ramakrishnan
118 factor = clean >> -shift; in lms_adapt_bg()
122 offset2 = ec->curr_pos; in lms_adapt_bg()
123 offset1 = ec->taps - offset2; in lms_adapt_bg()
125 for (i = ec->taps - 1; i >= offset1; i--) { in lms_adapt_bg()
126 exp = (ec->fir_state_bg.history[i - offset1] * factor); in lms_adapt_bg()
127 ec->fir_taps16[1][i] += (int16_t) ((exp + (1 << 14)) >> 15); in lms_adapt_bg()
129 for (; i >= 0; i--) { in lms_adapt_bg()
130 exp = (ec->fir_state_bg.history[i + offset2] * factor); in lms_adapt_bg()
131 ec->fir_taps16[1][i] += (int16_t) ((exp + (1 << 14)) >> 15); in lms_adapt_bg()
138 return -1; in top_bit()
140 return (int)fls((int32_t) bits) - 1; in top_bit()
153 ec->taps = len; in oslec_create()
154 ec->log2taps = top_bit(len); in oslec_create()
155 ec->curr_pos = ec->taps - 1; in oslec_create()
157 ec->fir_taps16[0] = in oslec_create()
158 kcalloc(ec->taps, sizeof(int16_t), GFP_KERNEL); in oslec_create()
159 if (!ec->fir_taps16[0]) in oslec_create()
162 ec->fir_taps16[1] = in oslec_create()
163 kcalloc(ec->taps, sizeof(int16_t), GFP_KERNEL); in oslec_create()
164 if (!ec->fir_taps16[1]) in oslec_create()
167 history = fir16_create(&ec->fir_state, ec->fir_taps16[0], ec->taps); in oslec_create()
170 history = fir16_create(&ec->fir_state_bg, ec->fir_taps16[1], ec->taps); in oslec_create()
175 ec->xvtx[i] = ec->yvtx[i] = ec->xvrx[i] = ec->yvrx[i] = 0; in oslec_create()
177 ec->cng_level = 1000; in oslec_create()
180 ec->snapshot = kcalloc(ec->taps, sizeof(int16_t), GFP_KERNEL); in oslec_create()
181 if (!ec->snapshot) in oslec_create()
184 ec->cond_met = 0; in oslec_create()
185 ec->pstates = 0; in oslec_create()
186 ec->ltxacc = ec->lrxacc = ec->lcleanacc = ec->lclean_bgacc = 0; in oslec_create()
187 ec->ltx = ec->lrx = ec->lclean = ec->lclean_bg = 0; in oslec_create()
188 ec->tx_1 = ec->tx_2 = ec->rx_1 = ec->rx_2 = 0; in oslec_create()
189 ec->lbgn = ec->lbgn_acc = 0; in oslec_create()
190 ec->lbgn_upper = 200; in oslec_create()
191 ec->lbgn_upper_acc = ec->lbgn_upper << 13; in oslec_create()
196 fir16_free(&ec->fir_state_bg); in oslec_create()
198 fir16_free(&ec->fir_state); in oslec_create()
200 kfree(ec->fir_taps16[1]); in oslec_create()
202 kfree(ec->fir_taps16[0]); in oslec_create()
213 fir16_free(&ec->fir_state); in oslec_free()
214 fir16_free(&ec->fir_state_bg); in oslec_free()
216 kfree(ec->fir_taps16[i]); in oslec_free()
217 kfree(ec->snapshot); in oslec_free()
224 ec->adaption_mode = adaption_mode; in oslec_adaption_mode()
232 ec->ltxacc = ec->lrxacc = ec->lcleanacc = ec->lclean_bgacc = 0; in oslec_flush()
233 ec->ltx = ec->lrx = ec->lclean = ec->lclean_bg = 0; in oslec_flush()
234 ec->tx_1 = ec->tx_2 = ec->rx_1 = ec->rx_2 = 0; in oslec_flush()
236 ec->lbgn = ec->lbgn_acc = 0; in oslec_flush()
237 ec->lbgn_upper = 200; in oslec_flush()
238 ec->lbgn_upper_acc = ec->lbgn_upper << 13; in oslec_flush()
240 ec->nonupdate_dwell = 0; in oslec_flush()
242 fir16_flush(&ec->fir_state); in oslec_flush()
243 fir16_flush(&ec->fir_state_bg); in oslec_flush()
244 ec->fir_state.curr_pos = ec->taps - 1; in oslec_flush()
245 ec->fir_state_bg.curr_pos = ec->taps - 1; in oslec_flush()
247 memset(ec->fir_taps16[i], 0, ec->taps * sizeof(int16_t)); in oslec_flush()
249 ec->curr_pos = ec->taps - 1; in oslec_flush()
250 ec->pstates = 0; in oslec_flush()
256 memcpy(ec->snapshot, ec->fir_taps16[0], ec->taps * sizeof(int16_t)); in oslec_snapshot()
275 ec->tx = tx; in oslec_update()
276 ec->rx = rx; in oslec_update()
281 * Filter DC, 3dB point is 160Hz (I think), note 32 bit precision in oslec_update()
283 * at (1-Beta) on real axis. Some chip sets (like Si labs) don't in oslec_update()
292 * = 2^(-3) = 0.125, 3dB freq is 0.125 rads = 159Hz. in oslec_update()
295 if (ec->adaption_mode & ECHO_CAN_USE_RX_HPF) { in oslec_update()
306 tmp -= (tmp >> 4); in oslec_update()
308 ec->rx_1 += -(ec->rx_1 >> DC_LOG2BETA) + tmp - ec->rx_2; in oslec_update()
312 * stage rx should be limited to +/- 16383 due to right shift in oslec_update()
315 tmp1 = ec->rx_1 >> 15; in oslec_update()
318 if (tmp1 < -16383) in oslec_update()
319 tmp1 = -16383; in oslec_update()
321 ec->rx_2 = tmp; in oslec_update()
334 old = (int)ec->fir_state.history[ec->fir_state.curr_pos] * in oslec_update()
335 (int)ec->fir_state.history[ec->fir_state.curr_pos]; in oslec_update()
336 ec->pstates += in oslec_update()
337 ((new - old) + (1 << (ec->log2taps - 1))) >> ec->log2taps; in oslec_update()
338 if (ec->pstates < 0) in oslec_update()
339 ec->pstates = 0; in oslec_update()
344 ec->ltxacc += abs(tx) - ec->ltx; in oslec_update()
345 ec->ltx = (ec->ltxacc + (1 << 4)) >> 5; in oslec_update()
346 ec->lrxacc += abs(rx) - ec->lrx; in oslec_update()
347 ec->lrx = (ec->lrxacc + (1 << 4)) >> 5; in oslec_update()
351 ec->fir_state.coeffs = ec->fir_taps16[0]; in oslec_update()
352 echo_value = fir16(&ec->fir_state, tx); in oslec_update()
353 ec->clean = rx - echo_value; in oslec_update()
354 ec->lcleanacc += abs(ec->clean) - ec->lclean; in oslec_update()
355 ec->lclean = (ec->lcleanacc + (1 << 4)) >> 5; in oslec_update()
359 echo_value = fir16(&ec->fir_state_bg, tx); in oslec_update()
360 clean_bg = rx - echo_value; in oslec_update()
361 ec->lclean_bgacc += abs(clean_bg) - ec->lclean_bg; in oslec_update()
362 ec->lclean_bg = (ec->lclean_bgacc + (1 << 4)) >> 5; in oslec_update()
370 ec->factor = 0; in oslec_update()
371 ec->shift = 0; in oslec_update()
372 if (!ec->nonupdate_dwell) { in oslec_update()
377 f = Beta * clean_bg_rx/P ------ (1) in oslec_update()
386 therefore the scaled version of (1) is: in oslec_update()
389 factor = (2^30) * Beta * clean_bg_rx/P ----- (2) in oslec_update()
393 factor = (2^30) * (2^-2) * clean_bg_rx/P in oslec_update()
395 (30 - 2 - log2(P)) in oslec_update()
396 factor = clean_bg_rx 2 ----- (3) in oslec_update()
399 which returns the position of the highest non-zero bit in in oslec_update()
408 p = MIN_TX_POWER_FOR_ADAPTION + ec->pstates; in oslec_update()
409 logp = top_bit(p) + ec->log2taps; in oslec_update()
410 shift = 30 - 2 - logp; in oslec_update()
411 ec->shift = shift; in oslec_update()
419 ec->adapt = 0; in oslec_update()
420 if ((ec->lrx > MIN_RX_POWER_FOR_ADAPTION) && (ec->lrx > ec->ltx)) in oslec_update()
421 ec->nonupdate_dwell = DTD_HANGOVER; in oslec_update()
422 if (ec->nonupdate_dwell) in oslec_update()
423 ec->nonupdate_dwell--; in oslec_update()
430 if ((ec->adaption_mode & ECHO_CAN_USE_ADAPTION) && in oslec_update()
431 (ec->nonupdate_dwell == 0) && in oslec_update()
432 /* (ec->Lclean_bg < 0.875*ec->Lclean) */ in oslec_update()
433 (8 * ec->lclean_bg < 7 * ec->lclean) && in oslec_update()
434 /* (ec->Lclean_bg < 0.125*ec->Ltx) */ in oslec_update()
435 (8 * ec->lclean_bg < ec->ltx)) { in oslec_update()
436 if (ec->cond_met == 6) { in oslec_update()
441 ec->adapt = 1; in oslec_update()
442 memcpy(ec->fir_taps16[0], ec->fir_taps16[1], in oslec_update()
443 ec->taps * sizeof(int16_t)); in oslec_update()
445 ec->cond_met++; in oslec_update()
447 ec->cond_met = 0; in oslec_update()
449 /* Non-Linear Processing */ in oslec_update()
451 ec->clean_nlp = ec->clean; in oslec_update()
452 if (ec->adaption_mode & ECHO_CAN_USE_NLP) { in oslec_update()
454 * Non-linear processor - a fancy way to say "zap small in oslec_update()
456 * non-linearity in the channel.". in oslec_update()
459 if ((16 * ec->lclean < ec->ltx)) { in oslec_update()
465 if (ec->adaption_mode & ECHO_CAN_USE_CNG) { in oslec_update()
466 ec->cng_level = ec->lbgn; in oslec_update()
471 * Hoth-like. DR: This noise doesn't sound in oslec_update()
472 * quite right to me - I suspect there are some in oslec_update()
479 ec->cng_rndnum = in oslec_update()
480 1664525U * ec->cng_rndnum + 1013904223U; in oslec_update()
481 ec->cng_filter = in oslec_update()
482 ((ec->cng_rndnum & 0xFFFF) - 32768 + in oslec_update()
483 5 * ec->cng_filter) >> 3; in oslec_update()
484 ec->clean_nlp = in oslec_update()
485 (ec->cng_filter * ec->cng_level * 8) >> 14; in oslec_update()
487 } else if (ec->adaption_mode & ECHO_CAN_USE_CLIP) { in oslec_update()
489 if (ec->clean_nlp > ec->lbgn) in oslec_update()
490 ec->clean_nlp = ec->lbgn; in oslec_update()
491 if (ec->clean_nlp < -ec->lbgn) in oslec_update()
492 ec->clean_nlp = -ec->lbgn; in oslec_update()
498 ec->clean_nlp = 0; in oslec_update()
511 if (ec->lclean < 40) { in oslec_update()
512 ec->lbgn_acc += abs(ec->clean) - ec->lbgn; in oslec_update()
513 ec->lbgn = (ec->lbgn_acc + (1 << 11)) >> 12; in oslec_update()
519 if (ec->curr_pos <= 0) in oslec_update()
520 ec->curr_pos = ec->taps; in oslec_update()
521 ec->curr_pos--; in oslec_update()
523 if (ec->adaption_mode & ECHO_CAN_DISABLE) in oslec_update()
524 ec->clean_nlp = rx; in oslec_update()
526 /* Output scaled back up again to match input scaling */ in oslec_update()
528 return (int16_t) ec->clean_nlp << 1; in oslec_update()
537 energy, e.g. down to 20Hz. This can make the hybrid non-linear
559 if (ec->adaption_mode & ECHO_CAN_USE_TX_HPF) { in oslec_hpf_tx()
570 tmp -= (tmp >> 4); in oslec_hpf_tx()
572 ec->tx_1 += -(ec->tx_1 >> DC_LOG2BETA) + tmp - ec->tx_2; in oslec_hpf_tx()
573 tmp1 = ec->tx_1 >> 15; in oslec_hpf_tx()
576 if (tmp1 < -32767) in oslec_hpf_tx()
577 tmp1 = -32767; in oslec_hpf_tx()
579 ec->tx_2 = tmp; in oslec_hpf_tx()