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

Sampling frequency in Hz.

n_chansint

Number of channels the block runs on.

coeffs_pathPath

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

Sampling frequency in Hz.

n_chansint

Number of channels the block runs on.

Q_sig: int

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

coeffsnp.ndarray

Array of the FIR coefficients in floating point format.

coeffs_intlist

Array of the FIR coefficients in fixed point int32 format.

shiftint

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

n_tapsint

Number of taps in the filter.

buffernp.ndarray

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

buffer_intlist

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

buffer_idxlist

List of the floating point buffer head for each channel.

buffer_idx_intlist

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

The input sample to be processed.

channelint

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

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_coefsnp.ndarray

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

filter_namestr

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_pathstr

Where to output the resulting header file.

frame_advanceint, optional

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

gain_dbfloat, optional

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

verbosebool, optional

Enable verbose printing, by default False

Raises:
ValueError: Bad config - Must be fixed
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.

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

Sampling frequency in Hz.

n_chansint

Number of channels the block runs on.

coeffs_pathPath

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

filter_namestr

Name of the filter, used for the autogen struct name

output_pathPath

Output path for the autogenerated .c and .h files

frame_advanceint, 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_dbfloat, 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:
fsint

Sampling frequency in Hz.

n_chansint

Number of channels the block runs on.

Q_sig: int

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

coeffsnp.ndarray

Time domain coefficients

n_tapsint

Length of time domain filter

frame_advanceint

The number of new samples between subsequent frames.

buffernp.ndarray

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

buffer_intlist

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

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: Optional[int] = 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_coefsnp.ndarray

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

filter_namestr

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_pathstr

Where to output the resulting header file.

frame_advanceint

The number of new samples between subsequent frames.

frame_overlapint, optional

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

nfftint, 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_dbfloat, optional

A gain applied to the filters output, by default 0.0

verbosebool, optional

Enable verbose printing, by default False

Raises:
ValueError: Bad config - Must be fixed
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.

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: Optional[int] = 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:
fsint

Sampling frequency in Hz.

n_chansint

Number of channels the block runs on.

coeffs_pathPath

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

filter_namestr

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_pathstr

Where to output the resulting header file.

frame_advanceint

The number of new samples between subsequent frames.

frame_overlapint, optional

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

nfftint, 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_dbfloat, 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:
fsint

Sampling frequency in Hz.

n_chansint

Number of channels the block runs on.

Q_sig: int

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

coeffsnp.ndarray

Time domain coefficients

n_tapsint

Length of time domain filter

frame_advanceint

The number of new samples between subsequent frames.

frame_overlapint

The number of additional samples to output per frame.

nfftint, optional

The FFT size in samples of a frame.

coeffs_fsnp.ndarray

The frequency domain coefficients.

n_fd_buffersint

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

td_buffernp.ndarray

Buffer of last nfft time domain inputs in floating point format

td_buffer_intlist

Buffer of last nfft time domain inputs in fixed point format

fd_buffernp.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:
framelist[float]

The input samples to be processed.

Returns:
float

The processed output sample.

reset_state() None

Reset all the delay line values to zero.