Digital Filters

The digital filters are embedded in Spectrum Lab's test circuit. There is one filter for each of the two possible channels, but both channels can be combined into one long processing chain. A filter can be used for many purposes. This chapter describes the basic operation of the filter.
Overview of contents:

See also: Spectrum Lab's main index ,  circuit window , comb filter .


FFT filter

The FFT-based filters are basically FIR filters, but the filtering is not done in the time domain. The input signal is transformed from the time- into the frequency domain (using the FFT), the spectrum multiplied with the filter's frequency response, and the result is transformed back into the time domain (using the inverse FFT). Though this sounds more complicated than the classic FIR implementation in a DSP, it's actually much faster if the filter has a high order (=a large number of coefficients). And it offers some special options -see the list of operations below- which are otherwise difficult to achieve.

With an FFT-based FIR filter, you can realize increadibly steep transitions, extreme stopband attenuation, and a linear phase - which is almost impossible with a simple FIR- or IIR filter. Since 2006, the filter can additionally move frequencies up or down, and turn USB into LSB (upper / lower sideband). The following list shows the sequence of the operations performed inside the filter:

  1. Transform a block of samples from the time- to the frequency-domain (FFT)
  2. If loaded and configured as the "first step": Pass the transformed data to the FFT-filter plugin
  3. Move frequencies down (option, one of the first steps in the frequency domain when converting "down")
  4. frequency-selective limiter (optionally)
  5. automatic multi-notch filter (to remove "steady carriers", optionally)
  6. denoiser (option.. using spectral subtraction)
  7. FILTER (always active, may be bandpass, lowpass, highpass, bandgap, or custom-type).
    In the frequency domain, this is just a multiplication of the samples with the filter's frequency response.
  8. Move frequencies up (option, last step in the frequency domain when converting "up")
  9. If loaded and configured as the "last step": Pass the transformed data to the FFT-filter plugin
  10. Transform back from frequency- to time domain (inverse FFT)

There is an extra tabsheet for the two FFT filters in the filter control window. If you want to use the FFT filter as a simple lowpass, highpass, bandpass or bandgap, select the filter type from the combo box, enter the center- or cutoff frequency and -possibly- the bandwidth in the edit fields (advanced users can also set these parameters through interpreter commands instead of defining them on the panel shown below). One example for controlling the FFT-filter through the interpreter is the "SAQ VLF Receiver" (software defined radio for the VLF band, 3 to 24 kHz).


(screenshot "FFT filter control panel")

Controls for the FFT filter in the filter control window:

On the "Graph" tab of the FFT-filter control panel, the most important parameters are displayed in graphical form and can be modified with the mouse (by clicking into the graph). Some of the graphic elements can be turned on and off on the "options" tab (next paragraph). Controls on this tabsheet are:

The black graph shows the filter response in the baseband, the gray graph is the same but shifted up or down, depending on the frequency-shift settings. Together with the option 'show input spectrum', this feature can be used like the VFO in a software-defined radio.

Less often used controls are on the "options" tab:

Notes:

Function of the FFT-based frequency conversion ("pitch shift")

<ToDo: a lot..> (works, but still subject to change)

Note that unlike a classic frequency converter, the FFT-based filter can only shift frequencies by multiples of an FFT bin width. The longer the FFT, the finer the stepwidth for this kind of frequency conversion.

If frequencies shall be moved DOWN, the conversion takes place as the first processing step. If frequencies shall be moved UP, it happens as last processing step. Why ? Because this way, the filter response, frequency inversion range, etc always remain at 'baseband' - regardless of the shift value. This simplifies switching from receive (=move frequency DOWN) and transmit (=move frequency UP), if the FFT-based filter is used as the core for a software-defined radio.

For convenience, the frequency shift can be connected to one of the frequency markers ("diamonds") on the main frequency scale, so you can move the marker with the mouse for tuning like in a software-defined radio. More details on this are in the chapter 'Interpreter commands for the digital filters'.

Function of the FFT-based USB / LSB conversion ("frequency inversion")

<ToDo> (works, but subject to change)

Function of the FFT-based autonotch

The autonotch in the FFT-based filter basically works as follows ("special options" explained later) :

  1. Convert a block of samples from the time domain into the frequency domain, using the FFT. Let's call the result "FFT bins".
  2. Calculate the powers from all FFT bins.
  3. From the powers of current FFT bins, calculate "slowly average". The autonotch speed parameter is used in this step.
  4. Compare the power of each (averaged) FFT bin with its neighbours. If the bin exceeds the average power of its neighbours (say 10 bins to the left and the right), set this bin in the complex spectrum (and a few bins to the left and the right, depending on the configuration) to zero.
  5. Multiply the complex spectrum with the filter coefficients (like in normal mode without autonotch, for bandpass / lowpass / highpass function).
  6. Convert the complex spectrum back into the time domain, using another ("inverse") FFT.

The sample blocks use a 50 percent overlap (from the previous block), and a cos^2 window, to avoid aliasing effects which would cause an ugly low-pitched clicking sound. If you have the C++ sourcefiles, you can find more details about the windowing function in the file FftFilter.cpp (available on request). 

Options for the FFT-based automatic notch filter

These options can be configured on the "Option"-tab of the filter control panel (not a surprise..). Due to the limited space on that panel, some parameters are not properly labelled there, so here's what those cryptic abbreviations mean:

AFL: Autonotch Frequency Limit (in Hertz)
Allows to limit the frequency range for the automatic notches. Set this range to "0 ... 0 Hz" to let it operate in the entire frequency range. If, for example, you only want to remove constant "carriers" between 45 and 5000 Hz, enter that range here.
auto NW: Automatic Notch WIDTH (checkmark)
If this (experimental) option is enabled, the automatic notch filter will choose the width of each notch automatically. Otherwise, the notch width is defined by the "ANW" field in Hz - see below.
ANS : Automatic  Notch Speed.
This dimensionless parameter defines the relative speed" of the adaption of the automatic notches to match the received signal. In other words, it defines "how fast" new signals with an almost constant frequency and amplitude will be removed, and how fast notches on "clear" frequencies will disappear. The usable range is zero to one, a typical setting is 0.1 .
ANW : Width of a single notch for the automatic notch filter in Hertz.
Only has an effect if the option "auto NW" is *not* checked.
ATW : Autonotch Transition Width (unit: number of FFT frequency bins)
This parameter can be used to make the transition between stopband and passband (for each notch) smoother. In some cases -for example if a *very* strong signal is notched away- a smooth transition can reduce the amout of "filter ringing", even though the FFT-based filter is an FIR filter (not an IIR filter) by design.
ANR : Autonotch Region width (unit: Hz)
To decide where to place a notch, the algorithm compares each bin power with the average of its neighbours. This parameter defines the "number of neighbours", but as a width in Hz, not as a number of frequency bins. However the algorithm look at a minimum number of 3 neighbours (on each side), so this parameter may be ignored if the FFT size is too low. Note that the FFT bin width (in Hz) is displayed near the lower left corner of the filter control panel.
As a rule of thumb, make the region small enough so the 'wanted' signals don't get wiped out. If, for example, a wanted signal has a bandwidth of 100 Hz (due to its modulation), a region width of 20 Hz ensures that the signal does *not* get wiped out.
On the other hand, make the region wide enough so 'unwanted' signals will be removed. For example, the AC mains frequency (and its harmonics), or the QRM emitted by a switching mode power supply may be "drifting", effectively widening the bandwidth to a few Hz. If the region is too small, and the unwanted signal too "wide" (spectrally), the ratio between the bin power and average of its (few) neighbours will be too small to reach the autonotch threshold value (ANT, see below).
ANT : Autonotch Threshold (unit: dB between bin power and the mean power within the 'region width' (ANR).
Only signals exceeding this value will be notched out.
BRej : Burst Reject Threshold (unit: dB between momentary total power and average total power)
This parameter is used to avoid "irritation" of the algorithm from short, strong bursts of noise (like Sferics in the VLF spectrum).
An explanation by Paul Nicholson (who suggested this algorithm - thanks Paul):
To avoid upsetting the filter settings every time a loud sferic or lightning crash comes in, we only revise the notch settings when the total signal power in this frame compared with the average total power in recent frames is below a threshold.
The 'Burst Reject Threshold' parameter was originally a power ratio of two, i.e. 3 dB difference between momentary and average power (over the entire input spectrum).

back to top

I/Q processing with the FFT-filter

The FFT-based filter can operate in I/Q-mode. I/Q means "Inphase" and "Quadrature" channel. Search the web on "I/Q signal processing", or just "quadrature signals" in the context of digital signal processing. A few notes on how to use the spectrum analyser in I/Q mode is here. Some applications of the FFT-filter in I/Q-mode are described in the chapter about image-cancelling direct conversion receivers.
Basically, the filter processes complex values in this mode. In fact, it's complex but not complicated !

The following combinations can be selected on the Options tab of the FFT filter control panel:

FFT Filter Plugins

For special applications, a plugin (in the form of a special DLL) can be loaded into the FFT filter. To do this, open the filter control panel, switch to the "FFT Filter", and open the "FFT Filter Plugin" tab. Enter the name of the plugin DLL under "Name of the FFT Filter Plugin", or click on the "Load" button to open a file selector box for the DLL plugins.


FFT Filter Plugin

Depending on the loaded filter plugin, some additional parameters may have to be set in table (as in the example above).

To develop your own FFT filter plugin, you need a C compiler (recommended : DevCpp, which is free, and based on GNU C / MinGW). As a starting point, download the "FFT Filter Plugins" package from the author's website. It contains a simple example project written in DevCpp, and a more detailed README file explaining how to write your own filter plugin.

The filter plugin parameters can be accessed through the interpreter if necessary, using the command (or function) filter.param .


Filter Implementation

The filter algorithm in Spectrum Lab runs in real time, the input can be fed from the soundcard's ADC while the output goes to the DAC.

The implementation of a "sharp" filter on a PC under Windows makes some problems, because Windows is not a real-time operating system.

A major problem is that the CPU (Pentium etc) spends a lot of time for executing other tasks and threads. The filter algorithm described above is calculated by the main CPU (not the so-called "DSP" on the soundcard which is no real DSP at all).

Because besides calculating the filter, the CPU will do "something else" for a few hundred milliseconds. To avoid interrupted audio, a sufficiently large filter holds some thousand audio samples ready for output. The soundcard driver reads data from this buffer whenever it needs to. The following diagram show the flow of information when the audio filter is active.

Sound Input
>>>
Analog to digital converter
>>>
Audio sample input buffer #1
(hard- and software)
>>>
Windows driver routine(s)
>>>
Audio sample input buffer #2
(software)
>>>
Filter algorithm
(software)
>>>
Audio sample output buffer #1
(software)
>>>
Even more windows driver(s)
>>>
Audio sample output buffer #2
(hard- and software)
>>>
Digital to analog converter
>>>
Sound Output

Without buffering, the filter will miss a lot of samples which results in audible "thumps" etc. Sometimes the filter routine even crashes completely, creating a horrible noise in the output. The result of too much sound buffering is an annoying delay between the filter input and output (you will notice it when tuning a receiver "by ear"). See the notes on testing the filter on your PC.

back to top


Starting and stopping the filter

After configuring the filter, you are ready to start it. But before starting the filter, you should start sampling the input (from the main window, "Start Analysis"). However, you may let the filter algorithm run without the sound input but that doesn't make much sense.

Start the filter by clicking the "Start"-Button in the filter control window. You should see an indication of the time required for a filter calculation in that window, as long as the filter is running.

To stop the filter, click the "Stop"-Button. Remember this when an IIR filter starts to oscillate and produce annoying sounds...

You may also change the filter coefficients while the filter remains running (no need to turn the filter off to change it). Just click the "Apply"-Button of the filter control window after typing new coefficients into the grid table.

If you find the new filter behaves worse than the "old" (before clicking "Apply"), click on the "Undo"-button. This will toggle between the "old" and the "new" filter settings.

back to top


Testing the filter on your PC

To find out if the filter runs properly on your PC, try the following:

  1. Select a filter which lets everything pass (for example, a low pass filter with an upper edge frequency above 16 kHz ), or switch the digital filter in SL's component window into "bypass" mode.
  2. Feed a clean sine wave of about 1kHz to the soundcards input. Watch the amplitude of the input signal with a monitor scope. Listen to the soundcard output with a headphone. If the output is "clean", you may be lucky. If you hear "thumps", clicking or cracking sounds, the CPU may be too slow or some other application occupies the CPU for too long intervals. Try another sampling rate on SpecLab's Audio Settings panel.
    If you don't hear anything, check the mixer settings of the soundcard.
  3. Now modify the filter so nothing should pass (for example, low-pass with upper edge frequency of zero). This will generate silence at the filters (software-) output. If you can still hear the sine wave, try to adjust the mixer settings of the soundcard until it disappears. There is some about this in this document.

If you also use Creative Lab's Audigy 2 or similar soundcards, and have the "audio bypass" problem, also read this info.

back to top


DSP Literature

If you want to learn more about digital signal processing, there is a large amount of literature about this fascinating subject. Here are just some of my favorites..

back to top


Interpreter commands for the digital filters

Up to now, there is just a small list of interpreter commands to control the digital filters. The first keyword is always "filter", followed by an index for the channel (like "filter[0]" for the left and "filter[1]" for the right channel). After this, there is at least one separator followed by another keyword defining what shall happen, etc :

Note: In the current release of Spectrum Lab, there are only two filters, one for the left and one for the right audio channel. So N may only be 0(zero) or 1(one).
(Why 0..1 and not 1..2 ? Because the author always uses array indices running from "zero" to "count of elements minus one", like in the 'C' programming language). But you may let the audio from a monophone source pass through both filters by chaining both processing branches as explained in the chapter about the test circuit.

back to top