Hide navigation sidebar
Hide table of contents sidebar
Back to top
Toggle table of contents sidebar

# AEC High Level API Functions

group aec_func

  Functions

  void aec_init(aec_state_t *main_state, aec_state_t *shadow_state, aec_shared_state_t *shared_state, uint8_t *main_mem_pool, uint8_t *shadow_mem_pool, unsigned num_y_channels, unsigned num_x_channels, unsigned num_main_filter_phases, unsigned num_shadow_filter_phases)

    Initialise AEC data structures.

    This function initializes AEC data structures for a given configuration. The configuration parameters num_y_channels, num_x_channels, num_main_filter_phases and num_shadow_filter_phases are passed in as input arguments.

    This function needs to be called at startup to first initialise the AEC and subsequently whenever the AEC configuration changes.

    `main_state`, `shadow_state` and shared_state structures must start at double word aligned addresses.

    main_mem_pool and shadow_mem_pool must point to memory buffers big enough to support main and shadow filter processing. AEC state aec_state_t and shared state aec_shared_state_t structures contain only the BFP data structures used in the AEC. The memory these BFP structures will point to needs to be provided by the user in the memory pool main and shadow filters memory pool. An example memory pool structure is present in aec_memory_pool_t and aec_shadow_filt_memory_pool_t.

    main_mem_pool and shadow_mem_pool must also start at double word aligned addresses.

    Example

          #include "aec_memory_pool.h"
          aec_state_t DWORD_ALIGNED main_state;
          aec_state_t DWORD_ALIGNED shadow_state;
          aec_shared_state_t DWORD_ALIGNED aec_shared_state;
          uint8_t DWORD_ALIGNED aec_mem[sizeof(aec_memory_pool_t)];
          uint8_t DWORD_ALIGNED aec_shadow_mem[sizeof(aec_shadow_filt_memory_pool_t)];
          unsigned y_chans = 2, x_chans = 2;
          unsigned main_phases = 10, shadow_phases = 5;
          // There is one main and one shadow filter per x-y channel pair, so for this example there will be 4 main and 4
          // shadow filters. Each main filter will have 10 phases and each shadow filter will have 5 phases.
          aec_init(&main_state, &shadow_state, &shared_state, aec_mem, aec_shadow_mem, y_chans, x_chans, main_phases, shadow_phases);

    Parameters:

      - main_state – [inout] AEC state structure for holding main filter specific state

      - shadow_state – [inout] AEC state structure for holding shadow filter specific state

      - shared_state – [inout] Shared state structure for holding state that is common to main and shadow filter

      - main_mem_pool – [inout] Memory pool containing main filter memory buffers

      - shadow_mem_pool – [inout] Memory pool containing shadow filter memory buffers

      - num_y_channels – [in] Number of mic input channels

      - num_x_channels – [in] Number of reference input channels

      - num_main_filter_phases – [in] Number of phases in the main filter

      - num_shadow_filter_phases – [in] Number of phases in the shadow filter

  void aec_frame_init(aec_state_t *main_state, aec_state_t *shadow_state, const int32_t (*y_data)[AEC_FRAME_ADVANCE], const int32_t (*x_data)[AEC_FRAME_ADVANCE])

    Initialise AEC data structures for processing a new frame.

    This is the first function that is called when a new frame is available for processing. It takes the new samples as input and combines the new samples and previous frame’s history to create a processing block on which further processing happens. It also initialises some data structures that need to be initialised at the beginning of a frame.

    Note

    y_data and x_data buffers memory is free to be reused after this function call.

    Parameters:

      - main_state – [inout] main filter state

      - shadow_state – [inout] shadow filter state

      - y_data – [in] pointer to mic input buffer

      - x_data – [in] pointer to reference input buffer

  void aec_calc_freq_domain_energy(float_s32_t *fd_energy, const bfp_complex_s32_t *input)

    Calculate energy in the spectrum.

    This function calculates the energy of frequency domain data used in the AEC. Frequency domain data in AEC is in the form of complex 32bit vectors and energy is calculated as the squared magnitude of the input vector.

    Parameters:

      - fd_energy – [out] energy of the input spectrum

      - input – [in] input spectrum BFP structure

  void aec_calc_time_domain_ema_energy(float_s32_t *ema_energy, const bfp_s32_t *input, unsigned start_offset, unsigned length, const aec_config_params_t *conf)

    Calculate exponential moving average (EMA) energy of a time domain (TD) vector.

    This function calculates the EMA energy of AEC time domain data which is in the form of real 32bit vectors.

    This function can be called to calculate the EMA energy of subsets of the input vector as well.

    Parameters:

      - ema_energy – [out] EMA energy of the input

      - input – [in] time domain input BFP structure

      - start_offset – [in] offset in the input vector from where to start calculating EMA energy

      - length – [in] length over which to calculate EMA energy

      - conf – [in] AEC configuration parameters.

  void aec_forward_fft(bfp_complex_s32_t *output, bfp_s32_t *input)

    Calculate Discrete Fourier Transform (DFT) spectrum of an input time domain vector.

    This function calculates the spectrum of a real 32bit time domain vector. It calculates an N point real DFT where N is the length of the input vector to output a complex N/2+1 length complex 32bit vector. The N/2+1 complex output values represent spectrum samples from DC up to the Nyquist frequency.

    The DFT calculation is done in place. After this function call the input and output BFP structures `data` fields point to the same memory. Since DFT is calculated in place, use of the input BFP struct is undefined after this function.

    To allow for inplace transform from N real 32bit values to N/2+1 complex 32bit values, the input vector should have 2 extra real 32bit samples worth of memory. This means that `input->data` should point to a buffer of length `input->length`+2

    After this function `input->data` and `output->data` point to the same memory address.

    Parameters:

      - output – [out] DFT output BFP structure

      - input – [in] DFT input BFP structure

  void aec_inverse_fft(bfp_s32_t *output, bfp_complex_s32_t *input)

    Calculate inverse Discrete Fourier Transform (DFT) of an input spectrum.

    This function calculates a N point inverse real DFT of a complex 32bit where N is 2*(length-1) where length is the length of the input vector. The output is a real 32bit vector of length N.

    The inverse DFT calculation is done in place. After this operation the input and the output BFP structures `data` fields point to the same memory. Since the calculation is done in place, use of input BFP struct after this function is undefined.

    After this function `input->data` and `output->data` point to the same memory address.

    Parameters:

      - output – [out] inverse DFT output BFP structure

      - input – [in] inverse DFT input BFP structure

  void aec_calc_X_fifo_energy(aec_state_t *state, unsigned ch, unsigned recalc_bin)

    Calculate total energy of the X FIFO.

    `X FIFO` is a FIFO of the most recent `X` frames, where `X` is spectrum of one frame of reference input. There’s a common X FIFO that is shared between main and shadow filters. It holds `num_main_filter_phases` most recent X frames and the shadow filter uses `num_shadow_filter_phases` most recent frames out of it.

    This function calculates the energy per X sample index summed across the X FIFO phases. This function also calculates the maximum energy across all samples indices of the output energy vector

    Note

    This function implements some speed optimisations which introduce quantisation error. To stop quantisation error build up, in every call of this function, energy for one sample index, which is specified in the `recalc_bin` argument, is recalculated without the optimisations. There are a total of AEC_FD_FRAME_LENGTH samples in the energy vector, so recalc_bin keeps cycling through indexes 0 to AEC_PROC_FRAME_LENGTH/2.

    Parameters:

      - state – [inout] AEC state. state->X_energy[ch] and state->max_X_energy[ch] are updated

      - ch – [in] channel index for which energy calculations are done

      - recalc_bin – [in] The sample index for which energy is recalculated to eliminate quantisation errors

  void aec_update_X_fifo_and_calc_sigmaXX(aec_state_t *state, unsigned ch)

    Update X FIFO with the current X frame.

    This function updates the X FIFO by removing the oldest X frame from it and adding the current X frame to it. This function also calculates sigmaXX which is the exponential moving average of the current X frame energy

    Parameters:

      - state – [inout] AEC state structure. state->shared_state->X_fifo[ch] and state->shared_state->sigma_XX[ch] are updated.

      - ch – [in] X channel index for which to update X FIFO

  void aec_calc_Error_and_Y_hat(aec_state_t *state, unsigned ch)

    Calculate error spectrum and estimated mic signal spectrum.

    This function calculates the error spectrum (`Error`) and estimated mic input spectrum (`Y_hat`) `Y_hat` is calculated as the sum of all phases of the adaptive filter multiplied by the respective phases of the reference input spectrum. Error is calculated by subtracting `Y_hat` from the mic input spectrum `Y`

    Parameters:

      - state – [inout] AEC state structure. state->Error[ch] and state->Y_hat[ch] are updated

      - ch – [in] mic channel index for which to compute Error and Y_hat

  void aec_calc_coherence(aec_state_t *state, unsigned ch)

    Calculate coherence.

    This function calculates the average coherence between mic input signal (`y`) and estimated mic signal (`y_hat`). A metric is calculated using `y` and `y_hat` and the moving average (`coh`) and a slow moving average (`coh_slow`) of that metric is calculated. The coherence values are used to distinguish between situations when filter adaption should continue or freeze and update mu accordingly.

    Parameters:

      - state – [inout] AEC state structure. `state->shared_state->coh_mu_state[ch].coh` and `state->shared_state->coh_mu_state[ch].coh_slow` are updated

      - ch – [in] mic channel index for which to calculate average coherence

  void aec_calc_output(aec_state_t *state, int32_t (*output)[AEC_FRAME_ADVANCE], unsigned ch)

    Calculate AEC filter output signal.

    This function is responsible for windowing the filter `error` signal and creating AEC filter output that can be propagated to downstream stages. `output` is calculated by overlapping and adding current frame’s windowed error signal with the previous frame windowed error. This is done to smooth discontinuities in the output as the filter adapts.

    Parameters:

      - state – [inout] AEC state structure. `state->error[ch]`

      - output – [out] pointer to the output buffer

      - ch – [in] mic channel index for which to calculate output

  void aec_calc_normalisation_spectrum(aec_state_t *state, unsigned ch, unsigned is_shadow)

    Calculate normalisation spectrum.

    This function calculates the normalisation spectrum of the reference input signal. This normalised spectrum is later used during filter adaption to scale the adaption to the size of the input signal. The normalisation spectrum is calculated as a time and frequency smoothed energy of the reference input spectrum.

    The normalisation spectrum is calculated differently for main and shadow filter, so a flag indicating whether this calculation is being done for the main or shadow filter is passed as an input to the function

    Parameters:

      - state – [inout] AEC state structure. state->inv_X_energy[ch] is updated

      - ch – [in] reference channel index for which to calculate normalisation spectrum

      - is_shadow – [in] flag indicating filter type. 0: Main filter, 1: Shadow filter

  void aec_compare_filters_and_calc_mu(aec_state_t *main_state, aec_state_t *shadow_state)

    Compare and update filters. Calculate the adaption step size mu.

    This function has 2 responsibilities. First, it compares the energies in the error spectrums of the main and shadow filter with each other and with the mic input spectrum energy, and makes an estimate of how well the filters are performing. Based on this, it optionally modifies the filters by either resetting the filter coefficients or copying one filter into another. Second, it uses the coherence values calculated in aec_calc_coherence as well as information from filter comparison done in step 1 to calculate the adaption step size mu.

    Parameters:

      - main_state – [inout] AEC state structure for the main filter

      - shadow_state – [inout] AEC state structure for the shadow filter

  void aec_calc_T(aec_state_t *state, unsigned y_ch, unsigned x_ch)

    Calculate the parameter `T`

    This function calculates a parameter referred to as `T` that is later used to scale the reference input spectrum in the filter update step. `T` is a function of the adaption step size `mu`, normalisation spectrum `inv_X_energy` and the filter error spectrum `Error`.

    Parameters:

      - state – [inout] AEC state structure. `state->T[x_ch]` is updated

      - y_ch – [in] mic channel index

      - x_ch – [in] reference channel index

  void aec_filter_adapt(aec_state_t *state, unsigned y_ch)

    Update filter.

    This function updates the adaptive filter spectrum (H_hat). It calculates the delta update that is applied to the filter by scaling the X FIFO with the T values computed in `aec_compute_T()` and applies the delta update to `H_hat`. A gradient constraint FFT is then applied to constrain the length of each phase of the filter to avoid wrapping when calculating `y_hat`

    Parameters:

      - state – [inout] AEC state structure. `state->H_hat[y_ch]` is updated

      - y_ch – [in] mic channel index

  void aec_update_X_fifo_1d(aec_state_t *state)

    Update the X FIFO alternate BFP structure.

    The X FIFO BFP structure is maintained in 2 forms - as a 2 dimensional [x_channels][num_phases] and as a [x_channels * num_phases] 1 dimensional array. This is done in order to optimally access the X FIFO as needed in different functions. After the X FIFO is updated with the current X frame, this function is called in order to copy the 2 dimensional BFP structure into it’s 1 dimensional counterpart.

    Parameters:

      - state – [inout] AEC state structure. `state->X_fifo_1d` is updated

  float_s32_t aec_calc_corr_factor(aec_state_t *state, unsigned ch)

    Calculate a correlation metric between the microphone input and estimated microphone signal.

    This function calculates a metric of resemblance between the mic input and the estimated mic signal. The correlation metric, along with reference signal energy is used to infer presence of near and far end signals in the AEC mic input.

    Parameters:

      - state – [in] AEC state structure. `state->y` and `state->y_hat` are used to calculate the correlation metric

      - ch – [in] mic channel index for which to calculate the metric

    Returns:

      correlation metric in float_s32_t format

  float_s32_t aec_calc_max_input_energy(const int32_t (*input_data)[AEC_FRAME_ADVANCE], int num_channels)

    Calculate the energy of the input signal.

    This function calculates the sum of the energy across all samples of the time domain input channel and returns the maximum energy across all channels.

    Parameters:

      - input_data – [in] Pointer to the input data buffer. The input is assumed to be in Q1.31 fixed point format.

      - num_channels – [in] Number of input channels.

    Returns:

      Maximum energy in float_s32_t format.

  void aec_reset_state(aec_state_t *main_state, aec_state_t *shadow_state)

    Reset parts of aec state structure.

    This function resets parts of AEC state so that the echo canceller starts adapting from a zero filter.

    Parameters:

      - pointer – [in] to AEC main filter state structure.

      - pointer – [in] to AEC shadow filter state structure

  uint32_t aec_detect_input_activity(const int32_t (*input_data)[AEC_FRAME_ADVANCE], float_s32_t active_threshold, int32_t num_channels)

    Detect activity on input channels.

    This function implements a quick check for detecting activity on the input channels. It detects signal presence by checking if the maximum sample in the time domain input frame is above a given threshold.

    Parameters:

      - input_data – [in] Pointer to input data frame. Input is assumed to be in Q1.31 fixed point format.

      - active_threshold – [in] Threshold for detecting signal activity

      - num_channels – [in] Number of input data channels

    Returns:

      0 if no signal activity on the input channels, 1 if activity detected on the input channels