Finite Impulse Response Hilbert Transform (firhilb)

The firhilbf object in liquid implements a finite impulse response Hilbert transform which converts between real and complex time series. The interpolator takes a complex time series and produces real-valued samples at twice the sample rate. The decimator reverses the process by halving the sample rate of a real-valued time series to a complex-valued one.

Typical trade-offs between filter length, side-lobe suppression, and transition bandwidth apply. The firhilbf object uses a half-band filter to implement the transform as efficiently as possible. While any filter length can be accepted, the firhilbf object internally forces the length to be of the form \(n=4m+1\) to reduce the computational load. A half-band filter of this length has \(2m\) zeros and \(2m+1\) non-zero coefficients. Of these non-zero coefficients, the center is exactly \(1\) while the other \(2m\) are even symmetric, and therefore only \(m\) computations are needed.

Figure [fig-filter-firhilb]. firhilbf (Hilbert transform) decimator demonstration. The small signal at \(f=0.13\) is due to aliasing as a result of imperfect image rejection.

filter_firhilb_decim_crcf_time.png

Time

filter_firhilb_decim_crcf_freq.png

PSD

A graphical example of the Hilbert decimator can be seen in [fig-filter-firhilb] where a real-valued input sinusoid is converted into a complex sinusoid with half the number of samples. An example code listing is given below. Although firhilbf is a placeholder for both decimation (real to complex) and interpolation (complex to real), separate objects should be used for each task.


#include <liquid/liquid.h>

int main() {
    unsigned int m=5;           // filter semi-length
    float slsl=60.0f;           // filter sidelobe suppression level

    // create Hilbert transform objects
    firhilbf q0 = firhilbf_create(m,slsl);
    firhilbf q1 = firhilbf_create(m,slsl);

    float complex x;    // interpolator input
    float y[2];         // interpolator output
    float complex z;    // decimator output

    // ...

    // execute transforms
    firhilbf_interp_execute(q0, x, y);   // interpolator
    firhilbf_decim_execute(q1, y, &z);   // decimator

    // clean up allocated memory
    firhilbf_destroy(q0);
    firhilbf_destroy(q1);
}

Listed below is the full interface to the firhilbf family of objects.

  • firhilbf_create(m,As) creates a firhilbf object with a filter semi-length of \(m\) samples (equal to the delay) and a stop-band attenuation of \(A_s\) dB. The value of \(m\) must be at least 2. The internal filter has a length \(4m+1\) coefficients and is designed using the firdes_kaiser_window() method (see [section-filter-firdes-window] on FIR filter design using windowing functions).
  • firhilbf_destroy(q) destroys the Hilbert transform object, freeing all internally-allocated memory.
  • firhilbf_print(q) prints the internal properties of the object to the standard output.
  • firhilbf_clear(q) clears the internal transform buffers.
  • firhilbf_r2c_execute(q,x,*y) executes the real-to-complex transform as a half-band filter, rejecting the negative frequency band. The input \(x\) is a real sample; the output \(y\) is complex.
  • firhilbf_c2r_execute(q,x,*y) executes the complex-to-real conversion as \(y = \Re\{x\}\) .
  • firhilbf_decim_execute(q,*x,*y) executes the transform as a decimator, converting a 2-sample input array \(\vec{x}\) of real values into a single complex output value \(y\) .
  • firhilbf_interp_execute(q,x,*y) executes the transform as a decimator, converting a single complex input sample \(x\) into a two real-valued samples stored in the output array \(\vec{y}\) .

For more detailed examples on Hilbert transforms in liquid, refer to the files examples/firhilb_decim_example.c and examples/firhilb_interp_example.c located within the main liquid project directory. See also: resamp2 ( [section-filter-resamp2] ), FIR filter design ( [section-filter-firdes] ).