Lines Matching +full:dc +full:- +full:dc +full:- +full:freq +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
102 #define DC_LOG2BETA 3 /* log2() of DC filter Beta */
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()
282 * required otherwise values do not track down to 0. Zero at DC, Pole in oslec_update()
283 * at (1-Beta) on real axis. Some chip sets (like Si labs) don't in oslec_update()
284 * need this, but something like a $10 X100P card does. Any DC really 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()
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()
528 return (int16_t) ec->clean_nlp << 1; in oslec_update()
533 as part of the tx process. See rx HP (DC blocking) filter above, it's
537 energy, e.g. down to 20Hz. This can make the hybrid non-linear
542 It can also help by removing and DC in the tx signal. DC is bad
545 This is one of the classic DC removal filters, adjusted to provide
551 giving very clean DC removal.
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()