digitalfilter.lua

NAME

digitalfilter.lua - Butterworth, Chebyschev and Bessel digital filters

SYNOPSIS

 local DF = require 'digitalfilter'
 local my_filter = DF.new_digitalfilter ({   -- returns a closure
    filtertype  = 'butterworth',
    order       = 3,
    shape       = 'lowpass',
    freq        = 2756,
    samplerate  = 44100,
 })
 for i = 1,160 do
    local u = math.floor((i%16)/8 + 0.01)*2 - 1   -- square wave
    local x = my_filter(u)
    if i >= 144 then print('my_filter('..u..') \t=', x) end
 end

DESCRIPTION

This module provides some Digital Filters - Butterworth, Chebyschev and Bessel, in lowpass and highpass. Primitive bandpass and bandstop filters are provided, and hopefully, Inverse Chebyschev and Elliptic filters will follow.

It was the subject of a talk given at Taslug in October 2017

TABLE OF OPTIONS

The main function, new_digitalfilter(options), needs an argument to set the parameters; This argument is a table, with keys 'filtertype', 'order', 'shape', 'freq' and 'samplerate', and for basspass and bandstop also 'Q'

The 'filtertype' can be 'butterworth', 'bessel', or 'chebyschev'. In the case of 'chebyschev' there is an additional option 'ripple' which specifies in decibels the desired ripple in the passband, defaulting to 1dB.

The 'order' can currently be from 1 to 7 for all types, and this range will probably be extended.

The 'shape' can be 'highpass', 'lowpass', 'bandpass' or 'bandstop', though currently 'highpass' or 'lowpass' are only implemented for 'order' = 2.

The 'freq' is the desired cutoff-frequency for 'lowpass' and 'highpass' filters, and the centre-frequency for 'bandpass' and 'bandstop', It must be given in the same units as the 'samplerate'. A 'freq' greater than half the 'samplerate' is a mistake, but is implemented as setting the gain to zero for 'lowpass' or 'bandpass', or 1 for 'highpass' or 'bandstop'.
For Butterworth and Bessel lowpass designs, the corner frequency is the frequency at which the magnitude of the response is -3 dB. For Chebyshev lowpass designs, the corner frequency is the highest frequency at which the magnitude of the response is equal to the specified ripple.

The 'samplerate' is the sampling-frequency. For example in audio use 'samplerate' will often be 44100 or 48000.

The 'Q' is only necessary for 'bandpass' and 'bandstop' shapes, and specifies the quality of the pole. High 'Q' gives the filter a narrower resonance.

FILTER TYPES

butterworth
The Butterworth filter is designed to have as flat a frequency response as possible in the passband. It is also referred to as a maximally flat magnitude filter. It is very much used in audio work.   See: en.wikipedia.org/wiki/Butterworth_filter
chebyschev
Chebyshev filters have a much steeper roll-off than Butterworth filters. but have ripples in the frequency-response in the passband.   See: en.wikipedia.org/wiki/Chebyshev_filter
bessel
The Bessel filter is a type of linear filter with a maximally flat group/phase delay (maximally linear phase response), which preserves the wave shape of filtered signals in the passband. Bessel filters are often used in audio crossover systems.   See: en.wikipedia.org/wiki/Bessel_filter
Currently, the Bessel filters are implemented with the bilinear transform, which preserves the amplitude response, but alas not the phase response; preferably, they should be implemented using the Thiran filter.   See: en.wikipedia.org/wiki/Bessel_filter#Digital

FUNCTIONS

my_filter = new_digitalfilter(options)

new_digitalfilter returns a closure - a function that lies within a context of local variables which implement the filter. You can then call this closure with your input-signal-value as argument, and it will return the filtered-signal-value.

The argument options is a table, with keys 'filtertype', 'order', 'shape', 'freq' and 'samplerate'.   See the Table of Options

If an error is detected, new_digitalfilter returns nil and an error message, so it can be used with assert.

It is hoped that some future version of new_digitalfilter will return also a second closure, allowing the 'freq' parameter to be varied during use.

CONSTANTS

Version
The digitalfilter.lua version
VersionDate
The release-date of this digitalfilter.lua version

BACKGROUND

To quote en.wikipedia.org/wiki/Digital_filter ; "The design of digital filters is a deceptively complex topic. Although filters are easily understood and calculated, the practical challenges of their design and implementation are significant and are the subject of much advanced research."

In the literature I have, the notation is often confusing. For example, in Temes/Mitra p.152 the general z^-1 transfer-function is given with parameters A_2 in the numerator equal to zero. Constantinides sometimes uses u and v to mean the real and imaginary parts of the frequency omega, and sometimes to mean the input and output signals of a digital filter; Rorabaugh, however, (p.156) uses X(z) and Y(z) to mean the input and output signals of a digital filter. Rorabaugh sometimes uses q to mean the quality of filter-section, sometimes to mean the location of a zero in the z^-1 plane. Constantinides sometimes uses a and b to mean the coefficients of the transfer function in the frequency-domain, and alpha and beta to mean the coefficients of the transfer function in the z^-1-domain, but he often uses a and b to mean the coefficients of the transfer function in the z^-1-domain. Or, comparing Constantinides p.36 with Rorabaugh p.156, the meanings of a and b have been swapped, as have the meanings of G(z) and H(z). In the sox biquad b0 b1 b2 a0 a1 a2 option, b* is numerator and a* is denominator, agreeing with Rorabaugh, so I will, sometime, change my code over to use that "standard".

This version of digitalfilter.lua uses the procedure given in Rorabaugh's "Digital Filter Designer's Handbook", pp.287-291. Overall, while writing this module, I have found Rorabaugh's book to be the most helpful.

DOWNLOAD

This module is available as a LuaRock in luarocks.org/modules/peterbillam so you should be able to install it with the command:

 $ su
 Password:
 # luarocks install digitalfilter
or:
 # luarocks install http://www.pjb.com.au/comp/lua/digitalfilter-2.1-0.rockspec
The test script used during development is   www.pjb.com.au/comp/lua/test_digitalfilter.lua

You can see the source-code in:
  https://pjb.com.au/comp/lua/digitalfilter-2.1.tar.gz

AUTHOR

Peter J Billam,   www.pjb.com.au/comp/contact.html

CHANGES

 20170803 2.1 the 'type' option changed to 'filtertype'
 20170802 2.0 chebyschev even orders start at the bottom of their ripple
 20170731 1.4 chebyschev filters added, but not the right shape
 20170730 1.3 finally fix the bessel freq-resp bug
 20170729 1.2 the same bad bessel freq-resp, using Rorabaugh's book
 20170722 1.1 bad bessel freq-resp, using Constantinides' book
 20170719 1.0 place-holder; not working yet

SEE ALSO

 "Digital Filter Designer's Handbook", C. Bitton Rorabaugh,
    TAB Books (McGraw-Hill) 
 cdn.preterhuman.net/texts/engineering/Dsp/
 www.pjb.com.au/comp/free/digital_filter_designers_handbook_1.pdf

 www.pjb.com.au/comp/lua/digitalfilter.html
 www.pjb.com.au/comp/lua/digitalfilter_talk/index.html
 www.pjb.com.au/comp/index.html#electronics

 "Modern Filter Theory and Design",
   Gabor C. Temes and Sanjit K. Mitra, Wiley, 1973
 "Approximation Methods for Electronic Filter Design",
   Richard W. Daniels, McGraw-Hill, 1974
 "Introduction to Digital Filtering",
   R.E.Bogner and A.G.Constantinides, Wiley 1975
 "Active Filter Design Handbook",
   G.S. Moschytz and Petr Horn, Wiley, 1981

 en.wikipedia.org/wiki/Fourier_transform
 en.wikipedia.org/wiki/Laplace_transform
 en.wikipedia.org/wiki/Digital_filter
 en.wikipedia.org/wiki/Butterworth_filter
 en.wikipedia.org/wiki/Chebyshev_filter
 en.wikipedia.org/wiki/Bessel_function
 en.wikipedia.org/wiki/Bessel_polynomials
 en.wikipedia.org/wiki/Bessel_filter
 en.wikipedia.org/wiki/Bessel_filter#Digital
 www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html
 www-users.cs.york.ac.uk/~fisher/mkfilter/mzt.html
 www.dsprelated.com
 www.pjb.com.au