digitalfilter.lua - Butterworth, Chebyschev and Bessel digital filters
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
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
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.
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.
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.
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 digitalfilteror:
# luarocks install http://www.pjb.com.au/comp/lua/digitalfilter-2.1-0.rockspecThe 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
Peter J Billam, www.pjb.com.au/comp/contact.html
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
"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