Skip to content
Back to top

# Finite Impulse Response Filters

Finite impulse response (FIR) filters allow the use of arbitrary filters with a finite number of taps. This library does not provide FIR filter design tools, but allows for coefficients to be imported from other design tools, such as SciPy/filter_design.

## FIR Direct

The direct FIR implements the filter as a convolution in the time domain. This library uses FIR `filter_fir_s32` implementation from `lib_xcore_math` to run on xcore. More information on implementation can be found in XCORE Math Library documentation.

class audio_dsp.dsp.fir.fir_direct(fs: float, n_chans: int, coeffs_path: Path, Q_sig: int = 27)

  An FIR filter, implemented in direct form in the time domain.

  When the filter coefficients are converted to fixed point, if there will be leading zeros, a left shift is applied to the coefficients in order to use the full dynamic range of the VPU. A subsequent right shift is applied to the accumulator after the convolution to return to the same gain.

  Parameters:
    fs int

      Sampling frequency in Hz.

    n_chans int

      Number of channels the block runs on.

    coeffs_path Path

      Path to a file containing the coefficients, in a format supported by np.loadtxt.

    Q_sig: int, optional

      Q format of the signal, number of bits after the decimal point. Defaults to Q4.27.

  Attributes:
    fs int

      Sampling frequency in Hz.

    n_chans int

      Number of channels the block runs on.

    Q_sig: int

      Q format of the signal, number of bits after the decimal point.

    coeffs np.ndarray

      Array of the FIR coefficients in floating point format.

    coeffs_int list

      Array of the FIR coefficients in fixed point int32 format.

    shift int

      Right shift to be applied to the fixed point convolution result. This compensates for any left shift applied to the coefficients.

    n_taps int

      Number of taps in the filter.

    buffer np.ndarray

      Buffer of previous inputs for the convolution in floating point format.

    buffer_int list

      Buffer of previous inputs for the convolution in fixed point format.

    buffer_idx list

      List of the floating point buffer head for each channel.

    buffer_idx_int list

      List of the fixed point point buffer head for each channel.

  process(sample: float, channel: int = 0) → float

    Update the buffer with the current sample and convolve with the filter coefficients, using floating point math.

    Parameters:
      sample float

        The input sample to be processed.

      channel int

        The channel index to process the sample on.

    Returns:
      float

        The processed output sample.

  reset_state() → None

    Reset all the delay line values to zero.

  check_coeff_scaling()

    Check the coefficient scaling is optimal.

    If there will be leading zeros, calculate a shift to use the full dynamic range of the VPU

## Block Time Domain FIR

The block time domain FIR implements the filter as a convolution in the time domain, but with a block size optimized for execution on the vector-unit of xcore.ai. The advantage with this one is it is over twice the efficiency of the lib_xcore_math implementation. This block will generate C code for the block time domain FIR filter. More information on implementation can be found in AN02027: Efficient computation of FIR filters on the XCORE.

Note

The block time domain FIR filter is not currently implemented as a DSP Stage, so cannot be used with the DSP pipeline tool yet.

Autogenerator

Autogenerator

audio_dsp.dsp.td_block_fir.generate_td_fir(

  td_coefs: ndarray,
  filter_name: str,
  output_path: Path,
  frame_advance=8,
  gain_db=0.0,
  verbose=False,

)

  Convert the input filter coefficients array into a header with block time domain structures to be included in a C project.

  Parameters:
    td_coefs np.ndarray

      This is a 1D numpy float array of the coefficients of the filter.

    filter_name str

      For use in identification of the filter from within the C code. All structs and defines that pertain to this filter will contain this identifier.

    output_path str

      Where to output the resulting header file.

    frame_advance int, optional

      The size in samples of a frame, measured in time domain samples, by default 8. Only multiples of 8 are supported.

    gain_db float, optional

      A gain applied to the filter’s output, by default 0.0

    verbose bool, optional

      Enable verbose printing, by default False

  Raises:
    ValueError: Bad config - Must be fixed

C API

void td_block_fir_data_init(

  td_block_fir_data_t *fir_data,
  int32_t *data,
  uint32_t data_buffer_elements,

)

  Initialise a time domain block FIR data structure.

  This manages the input data, rather than the coefficients, for a time domain block convolution. The python filter generator should be run first resulting in a header that defines the parameters for this function.

  For example, running the generator with `--name={NAME}` would generate defines prepended with `{NAME}`, i.e. `{NAME}_DATA_BUFFER_ELEMENTS`, `{NAME}_TD_BLOCK_LENGTH`, etc. This function should then be called with:

      td_block_fir_data_t {NAME}_fir_data;
      int32_t {NAME}_data[{NAME}_DATA_BUFFER_ELEMENTS];
      td_block_fir_data_init(&{NAME}_fir_data, {NAME}_data, {NAME}_DATA_BUFFER_ELEMENTS);

  Parameters:

    - fir_data – Pointer to struct of type td_block_fir_data_t

    - data – Pointer to an amount of memory to be used by the struct in order to hold a history of the samples. The define `{NAME}_DATA_BUFFER_ELEMENTS` specifies exactly the number of int32_t elements to allocate for the filter `{NAME}` to correctly function.

    - data_buffer_elements – The number of words contained in the data array, this should be `{NAME}_DATA_BUFFER_ELEMENTS`.

void td_block_fir_add_data(

  int32_t samples_in[TD_BLOCK_FIR_LENGTH],
  td_block_fir_data_t *fir_data,

)

  Function to add samples to the FIR data structure.

  Parameters:

    - samples_in – Array of int32_t samples of length TD_BLOCK_FIR_LENGTH.

    - fir_data – Pointer to struct of type td_block_fir_data_t to which the samples will be added.

void td_block_fir_compute(

  int32_t samples_out[TD_BLOCK_FIR_LENGTH],
  td_block_fir_data_t *fir_data,
  td_block_fir_filter_t *fir_filter,

)

  Function to compute the convolution between fir_data and fir_filter.

  Parameters:

    - samples_out – Array of length TD_BLOCK_FIR_LENGTH(8), which will be used to return the processed samples.

    - fir_data – Pointer to struct of type td_block_fir_data_t from which the data samples will be obtained.

    - fir_filter – Pointer to struct of type td_block_fir_filter_t from which the coefficients will be obtained.

Python API

class audio_dsp.dsp.td_block_fir.fir_block_td(

  fs: float,
  n_chans: int,
  coeffs_path: Path,
  filter_name: str,
  output_path: Path,
  frame_advance=8,
  gain_db=0.0,
  Q_sig: int = 27,

)

  An FIR filter, implemented in block form in the time domain.

  This will also autogenerate a .c and .h file containing the optimised block filter structures, designed for use in C.

  Parameters:
    fs int

      Sampling frequency in Hz.

    n_chans int

      Number of channels the block runs on.

    coeffs_path Path

      Path to a file containing the coefficients, in a format supported by np.loadtxt.

    filter_name str

      Name of the filter, used for the autogen struct name

    output_path Path

      Output path for the autogenerated .c and .h files

    frame_advance int, optional

      Number of samples processed by the filter at once. This should be set to the same as the DSP pipeline frame size, and must be a multiple of 8.

    gain_db float, optional

      Additional gain applied by the filter

    Q_sig: int, optional

      Q format of the signal, number of bits after the decimal point. Defaults to Q4.27.

  Attributes:
    fs int

      Sampling frequency in Hz.

    n_chans int

      Number of channels the block runs on.

    Q_sig: int

      Q format of the signal, number of bits after the decimal point.

    coeffs np.ndarray

      Time domain coefficients

    n_taps int

      Length of time domain filter

    frame_advance int

      The number of new samples between subsequent frames.

    buffer np.ndarray

      Buffer of previous inputs for the convolution in floating point format.

    buffer_int list

      Buffer of previous inputs for the convolution in fixed point format.

  process_frame(frame: list)

    Update the buffer with the current samples and convolve with the filter coefficients, using floating point math.

    Parameters:
      frame list[float]

        The input samples to be processed.

    Returns:
      float

        The processed output sample.

  reset_state() → None

    Reset all the delay line values to zero.

## Block Frequency Domain FIR

This implementation is a frequency-domain implementation resulting in a lower algorithmic complexity than the time-domain versions. This will achieve the highest taps per second possible with the xcore. The main cost to using this implementation is the memory requirements double compared to the previous two time-domain versions. This block will generate C code for the block frequency domain FIR filter. More information on implementation can be found in AN02027: Efficient computation of FIR filters on the XCORE.

Note

The block time domain FIR filter is not currently implemented as a DSP Stage, so cannot be used with the DSP pipeline tool yet.

Autogenerator

Autogenerator

audio_dsp.dsp.fd_block_fir.generate_fd_fir(

  td_coefs: ndarray,
  filter_name: str,
  output_path: Path,
  frame_advance: int,
  frame_overlap: int = 0,
  nfft: int | None = None,
  gain_db: float = 0.0,
  verbose=False,

)

  Convert the input filter coefficients array into a header with block frequency domain structures to be included in a C project.

  Parameters:
    td_coefs np.ndarray

      This is a 1D numpy float array of the coefficients of the filter.

    filter_name str

      For use in identification of the filter from within the C code. All structs and defines that pertain to this filter will contain this identifier.

    output_path str

      Where to output the resulting header file.

    frame_advance int

      The number of new samples between subsequent frames.

    frame_overlap int, optional

      The number of additional samples to output per frame. This allows windowing between frames to occur. By default no overlap occurs.

    nfft int, optional

      The FFT size in samples of a frame, measured in time domain samples. If this is not set, the FFT size is set automatically. An initial attempt of `nfft = 2**(ceil(log2(frame_advance)) + 1)` is made, but may need to be increased for longer overlaps. If it is set, it must be a power of 2.

    gain_db float, optional

      A gain applied to the filters output, by default 0.0

    verbose bool, optional

      Enable verbose printing, by default False

  Raises:
    ValueError: Bad config - Must be fixed

C API

void fd_block_fir_data_init(

  fd_fir_data_t *fir_data,
  int32_t *data,
  uint32_t frame_advance,
  uint32_t block_length,
  uint32_t block_count,

)

  Initialise a frequency domain block FIR data structure.

  This manages the input data, rather than the coefficients, for a frequency domain block convolution. The python filter generator should be run first resulting in a header that defines the parameters for this function.

  For example, running the generator with `--name={NAME}` would generate defines prepended with `{NAME}`, i.e. `{NAME}_DATA_BUFFER_ELEMENTS`, `{NAME}_TD_BLOCK_LENGTH`, etc. This function should then be called with:

      fd_fir_data_t {NAME}_fir_data;
      int32_t {NAME}_data[{NAME}_DATA_BUFFER_ELEMENTS];
      fd_block_fir_data_init(&{NAME}_fir_data, {NAME}_data,
          {NAME}_FRAME_ADVANCE,
          {NAME}_TD_BLOCK_LENGTH,
          {NAME}_BLOCK_COUNT);

  Parameters:

    - fir_data – Pointer to struct of type fd_fir_data_t.

    - data – An area of memory to be used by the struct in order to hold a history of the samples. The define {NAME}_DATA_BUFFER_ELEMENTS specifies exactly the number of int32_t elements to allocate for the filter {NAME} to correctly function.

    - frame_advance – The number of samples contained in each frame, i.e. the samples count between updates. This should be initialised to {NAME}_FRAME_ADVANCE.

    - block_length – The length of the processing block, independent to the frame_advance. Must be a power of two. This should be initialised to {NAME}_TD_BLOCK_LENGTH.

    - block_count – The count of blocks required to implement the filter. This should be initialised to {NAME}_BLOCK_COUNT.

void fd_block_fir_add_data(int32_t *samples_in, fd_fir_data_t *fir_data)

  Function to add samples to the FIR data structure.

  Parameters:

    - samples_in – Array of int32_t samples of length expected to be fir_data->frame_advance.

    - fir_data – Pointer to struct of type fd_fir_data_t to which the samples will be added.

void fd_block_fir_compute(

  int32_t *samples_out,
  fd_fir_data_t *fir_data,
  fd_fir_filter_t *fir_filter,

)

  Function to compute the convolution between fir_data and fir_filter.

  Parameters:

    - samples_out – Array of length fir_data->td_block_length, which will be used to return the processed samples. The samples will be returned from element 0 for `(fir_data-td_block_length + 1 - fir_filter->taps_per_block)` elements. The remaining samples of the array are used as scratch for the processing to be in-place.

    - fir_data – Pointer to struct of type fd_fir_data_t from which the data samples will be obtained.

    - fir_filter – Pointer to struct of type fd_fir_filter_t from which the coefficients will be obtained.

Python API

class audio_dsp.dsp.fd_block_fir.fir_block_fd(

  fs: float,
  n_chans: int,
  coeffs_path: Path,
  filter_name: str,
  output_path: Path,
  frame_advance: int,
  frame_overlap: int = 0,
  nfft: int | None = None,
  gain_db: float = 0.0,
  Q_sig: int = 27,

)

  An FIR filter, implemented in block form in the frequency domain.

  This will also autogenerate a .c and .h file containing the optimised block filter structures, designed for use in C.

  Parameters:
    fs int

      Sampling frequency in Hz.

    n_chans int

      Number of channels the block runs on.

    coeffs_path Path

      Path to a file containing the coefficients, in a format supported by np.loadtxt.

    filter_name str

      For use in identification of the filter from within the C code. All structs and defines that pertain to this filter will contain this identifier.

    output_path str

      Where to output the resulting header file.

    frame_advance int

      The number of new samples between subsequent frames.

    frame_overlap int, optional

      The number of additional samples to output per frame. This allows windowing between frames to occur. By default no overlap occurs.

    nfft int, optional

      The FFT size in samples of a frame, measured in time domain samples. If this is not set, the FFT size is set automatically. An initial attempt of `nfft = 2**(ceil(log2(frame_advance)) + 1)` is made, but may need to be increased for longer overlaps. If it is set, it must be a power of 2.

    gain_db float, optional

      A gain applied to the filters output, by default 0.0

    Q_sig: int, optional

      Q format of the signal, number of bits after the decimal point. Defaults to Q4.27.

  Attributes:
    fs int

      Sampling frequency in Hz.

    n_chans int

      Number of channels the block runs on.

    Q_sig: int

      Q format of the signal, number of bits after the decimal point.

    coeffs np.ndarray

      Time domain coefficients

    n_taps int

      Length of time domain filter

    frame_advance int

      The number of new samples between subsequent frames.

    frame_overlap int

      The number of additional samples to output per frame.

    nfft int, optional

      The FFT size in samples of a frame.

    coeffs_fs np.ndarray

      The frequency domain coefficients.

    n_fd_buffers int

      The number of frames of frequency domain coefficients, set the number of buffers that need to be saved.

    td_buffer np.ndarray

      Buffer of last nfft time domain inputs in floating point format

    td_buffer_int list

      Buffer of last nfft time domain inputs in fixed point format

    fd_buffer np.ndarray

      Buffer of last n_fd_buffers of the spectrums of previous td_buffers.

  process_frame(frame: list)

    Update the buffer with the current samples and convolve with the filter coefficients, using floating point math.

    Parameters:
      frame list[float]

        The input samples to be processed.

    Returns:
      float

        The processed output sample.

  reset_state() → None

    Reset all the delay line values to zero.