The Open Master Hearing Aid (openMHA)  openMHA
Open community platform for hearing aid algorithm research
MHAFilter::polyphase_resampling_t Class Reference

A class that performs polyphase resampling. More...

Public Member Functions

 polyphase_resampling_t (unsigned n_up, unsigned n_down, mha_real_t nyquist_ratio, unsigned n_irs, unsigned n_ringbuffer, unsigned n_channels, unsigned n_prefill)
 Construct a polyphase resampler instance. More...
 
void write (mha_wave_t &signal)
 Write signal to the ringbuffer. More...
 
void read (mha_wave_t &signal)
 Read resampled signal. More...
 
unsigned readable_frames () const
 Number of frames at target sampling rate that can be produced. More...
 

Private Attributes

unsigned upsampling_factor
 Integer upsampling factor. More...
 
unsigned downsampling_factor
 Integer downsampling factor. More...
 
unsigned now_index
 Index of "now" in the interpolated sampling rate. More...
 
bool underflow
 Set to true when an underflow has occurred. More...
 
MHAWindow::hanning_t impulse_response
 Contains the impulse response of the lowpass filter needed for anti-aliasing. More...
 
MHASignal::ringbuffer_t ringbuffer
 Storage of input signal. More...
 

Detailed Description

A class that performs polyphase resampling.

Background information: When resampling from one sampling rate to another, it helps when one sampling rate is a multiple of the other sampling rate: In the case of upsampling, the samples at the original rate are copied to the upsampled signal spread out with a constant number of zero samples between the originally adjacent samples. The signal is then low-pass filtered to avoid frequency aliasing and to fill the zero-samples with interpolated values. In the case of down-sampling, the signal is first low-pass filtered for anti-aliasing, and only every nth sample of the filtered output is used for the signal at the new sample rate. Of course, for finite-impulse-response (FIR) filters this means that only every nth sample needs to be computed.

When resampling from one sampling rate to another where neither is a multiple of the other, the signal first needs to be upsampled to a sampling rate that is a multiple of both (source and target) sampling rates, and then downsampled again to the target sampling rate. Instead of applying two separate lowpass filters directly after each other (one filter for upsampling and another for downsampling), it is sufficient to apply only one low-pass filter, when producing the output at the final target rate, with a cut-off frequency equal to the lower cut-off-frequency of the replaced two low-pass filters. Not filtering to produce a filtered signal already at the common multiple sampling rate has the side effect that this intermediate signal at the common multiple sampling rate keeps its filler zero samples unaltered. These zero samples can be taken advantage of when filtering to produce the output at the target rate: The zeros do not need to be multiplied with their corresponding filter coefficients, because the result is known to be zero again, and this zero product has no effect on the summation operation to compute a target sample at the target rate. To summarize, the following optimization techniques are available:

  • The signal does not need to be stored in memory at the interpolation rate. It is sufficient to have the signal available at the source rate and to know where the zeros would be.
  • The signal needs to be low-pass-filtered only once.
  • The FIR low-pass filtering can take advantage of
    • computing only filter outputs for the required samples at the target rate,
    • skipping over zero-samples at the interpolation rate.

The procedure that takes advantage of these optimization possibilites is known as polyphase resampling.

This class implements polyphase resampling in this way for a source sampling rate and a target sampling rate that have common multiple, the interpolation sampling rate. Non-rational and drifting sample rates are outside the scope of this resampler.

Constructor & Destructor Documentation

◆ polyphase_resampling_t()

MHAFilter::polyphase_resampling_t::polyphase_resampling_t ( unsigned  n_up,
unsigned  n_down,
mha_real_t  nyquist_ratio,
unsigned  n_irs,
unsigned  n_ringbuffer,
unsigned  n_channels,
unsigned  n_prefill 
)

Construct a polyphase resampler instance.

Allocates a ringbuffer with the given capacity n_ringbuffer. Client that triggers the constructor must ensure that the capacity n_ringbuffer and the delay n_prefill are sufficient, i.e. enough old and new samples are always available to compute sufficient samples in using an impulse response of length n_irs. Audio block sizes at both sides of the resampler have to be taken into account. Class MHASignal::blockprocessing_polyphase_resampling_t takes care of this, and it is recommended to use this class for block-based processing.

Based on n_up, n_down, n_irs and nyquist_ratio, a suitable sinc impulse response is computed and windowed with a hanning window to limit its extent.

The actual source sampling rate, target sampling rate, and interpolation sampling rate are not parameters to this constructors, because only their ratios matter.

Parameters
n_upupsampling factor, ratio between interpolation rate and source rate.
n_downdownsampling factor, ratio between interpolation rate and target rate.
nyquist_ratiolow pass filter cutoff frequency relative to the nyquist frequency of the smaller of the two sampling rates. Example values: E.g. 0.8, 0.9
n_irslength of impulse response (in samples at interpolation rate)
n_ringbufferlength of ringbuffer, in samples at source sampling rate
n_channelsaudio channels count
n_prefillPrefill the ringbuffer with this many zero frames in samples at source sampling rate

Member Function Documentation

◆ write()

void MHAFilter::polyphase_resampling_t::write ( mha_wave_t signal)

Write signal to the ringbuffer.

Signal contained in signal is appended to the audio frames already present in the ringbuffer.

Parameters
signalinput signal in original sampling rate
Exceptions
MHA_ErrorRaises exception if there is not enough room or if the number of channels does not match.

◆ read()

void MHAFilter::polyphase_resampling_t::read ( mha_wave_t signal)

Read resampled signal.

Will perform the resampling and remove no longer needed samples from the input buffer.

Parameters
signalbuffer to write the resampled signal to.
Exceptions
MHA_ErrorRaises exception if there is not enough input signal or if the number of channels is too high.

◆ readable_frames()

unsigned MHAFilter::polyphase_resampling_t::readable_frames ( ) const
inline

Number of frames at target sampling rate that can be produced.

This method only checks for enough future samples present, therefore, this number can be positive and a read operation can still fail if there are not enough past samples present to perform the filtering for the first output sample. This could only happen if the constructor parameters n_ringbuffer or n_prefill have been chosen too small, because otherwise the method read ensures that enough past samples are present to compute the next target sample.

Member Data Documentation

◆ upsampling_factor

unsigned MHAFilter::polyphase_resampling_t::upsampling_factor
private

Integer upsampling factor.

Interpolation rate divided by source rate.

◆ downsampling_factor

unsigned MHAFilter::polyphase_resampling_t::downsampling_factor
private

Integer downsampling factor.

Interpolation rate divided by target rate.

◆ now_index

unsigned MHAFilter::polyphase_resampling_t::now_index
private

Index of "now" in the interpolated sampling rate.

◆ underflow

bool MHAFilter::polyphase_resampling_t::underflow
private

Set to true when an underflow has occurred.

When this is true, then the object can no longer be used. Underflows have to be avoided by clients, e.g. by checking that enough readable_frames are present before calling read

◆ impulse_response

MHAWindow::hanning_t MHAFilter::polyphase_resampling_t::impulse_response
private

Contains the impulse response of the lowpass filter needed for anti-aliasing.

The impulse response is stored at the interpolation sampling rate. We use an instance of MHAWindow::hanning_t here because we are limiting the sinc impulse response with a Hanning window (otherwise the impulse response would extend indefinitely into past and future). And the samples inside an MHAWindow::hanning_t can be altered with *=, which our constructor does.

◆ ringbuffer

MHASignal::ringbuffer_t MHAFilter::polyphase_resampling_t::ringbuffer
private

Storage of input signal.

Part of the polyphase resampling optimization is that apart from the FIR impulse response, nothing is stored at the interpolation rate, saving memory and computation cycles.


The documentation for this class was generated from the following files: