

An infinite impulse response (I\+IR) filter library for Linux, Mac O\+SX and Windows which implements Butterworth, R\+BJ, Chebychev filters and can easily import coefficients generated by Python (scipy).

The filter processes the data sample by sample for realtime processing.

It uses templates to allocate the required memory so that it can run without any malloc / new commands. Memory is allocated at compile time so that there is never the risk of memory leaks.\hypertarget{md_README_autotoc_md1}{}\doxysubsection{C++ code}\label{md_README_autotoc_md1}
Add the following include statement to your code\+: 
\begin{DoxyCode}{0}
\DoxyCodeLine{\#include "Iir.h"}
\end{DoxyCode}


The general coding approach is that first the filter is instantiated specifying its order, then the parameters are set with the function {\ttfamily setup} and then it\textquotesingle{}s ready to be used for sample by sample realtime filtering.\hypertarget{md_README_autotoc_md2}{}\doxysubsubsection{Setting the filter parameters}\label{md_README_autotoc_md2}
All filters are available as lowpass, highpass, bandpass and bandstop/notch filters. Butterworth / Chebyshev offer also low/high/band-\/shelves with specified passband gain and 0dB gain in the stopband.

The frequencies can either be analogue ones against the sampling rate or normalised ones between 0..1/2 where 1/2 is the Nyquist frequency. Note that normalised frequencies are simply f = F/\+Fs and are in units of 1/samples. Internally the library uses normalised frequencies and the setup commands simply divide by the sampling rate if given. Choose between\+:
\begin{DoxyEnumerate}
\item {\ttfamily setup}\+: sampling rate and the analogue cutoff frequencies
\item {\ttfamily setupN}\+: normalised frequencies in 1/samples between f = 0..1/2 where 1/2 = Nyquist.
\end{DoxyEnumerate}

See the header files in {\ttfamily \textbackslash{}iir} or the documentation for the arguments of the {\ttfamily setup} commands.

The examples below are for lowpass filters\+:


\begin{DoxyEnumerate}
\item Butterworth -- {\ttfamily \mbox{\hyperlink{Butterworth_8h_source}{Butterworth.\+h}}} Standard filter suitable for most applications. Monotonic response. 
\begin{DoxyCode}{0}
\DoxyCodeLine{const int order = 4; // 4th order (=2 biquads)}
\DoxyCodeLine{Iir::Butterworth::LowPass<order> f;}
\DoxyCodeLine{const float samplingrate = 1000; // Hz}
\DoxyCodeLine{const float cutoff\_frequency = 5; // Hz}
\DoxyCodeLine{f.setup (samplingrate, cutoff\_frequency);}
\end{DoxyCode}

\end{DoxyEnumerate}

or specify a normalised frequency between 0..1/2\+: 
\begin{DoxyCode}{0}
\DoxyCodeLine{f.setupN(norm\_cutoff\_frequency);}
\end{DoxyCode}



\begin{DoxyEnumerate}
\item Chebyshev Type I -- {\ttfamily \mbox{\hyperlink{ChebyshevI_8h_source}{Chebyshev\+I.\+h}}} With permissible passband ripple in dB. 
\begin{DoxyCode}{0}
\DoxyCodeLine{Iir::ChebyshevI::LowPass<order> f;}
\DoxyCodeLine{const float passband\_ripple\_in\_db = 5;}
\DoxyCodeLine{f.setup (samplingrate,}
\DoxyCodeLine{         cutoff\_frequency,}
\DoxyCodeLine{         passband\_ripple\_in\_dB);}
\end{DoxyCode}

\end{DoxyEnumerate}

or specify a normalised frequency between 0..1/2\+: 
\begin{DoxyCode}{0}
\DoxyCodeLine{f.setupN(norm\_cutoff\_frequency,passband\_ripple\_in\_dB);}
\end{DoxyCode}



\begin{DoxyEnumerate}
\item Chebyshev Type II -- {\ttfamily \mbox{\hyperlink{ChebyshevII_8h_source}{Chebyshev\+I\+I.\+h}}} With worst permissible stopband rejection in dB. 
\begin{DoxyCode}{0}
\DoxyCodeLine{Iir::ChebyshevII::LowPass<order> f;}
\DoxyCodeLine{double stopband\_ripple\_in\_dB = 20;}
\DoxyCodeLine{f.setup (samplingrate,}
\DoxyCodeLine{         cutoff\_frequency,}
\DoxyCodeLine{         stopband\_ripple\_in\_dB);}
\end{DoxyCode}

\end{DoxyEnumerate}

or specify a normalised frequency between 0..1/2\+: 
\begin{DoxyCode}{0}
\DoxyCodeLine{f.setupN(norm\_cutoff\_frequency,stopband\_ripple\_in\_dB);}
\end{DoxyCode}



\begin{DoxyEnumerate}
\item R\+BJ -- {\ttfamily \mbox{\hyperlink{RBJ_8h_source}{R\+B\+J.\+h}}} 2nd order filters with cutoff and Q factor. 
\begin{DoxyCode}{0}
\DoxyCodeLine{Iir::RBJ::LowPass f;}
\DoxyCodeLine{const float cutoff\_frequency = 100;}
\DoxyCodeLine{const float Q\_factor = 5;}
\DoxyCodeLine{f.setup (samplingrate, cutoff\_frequency, Q\_factor);}
\end{DoxyCode}

\end{DoxyEnumerate}

or specify a normalised frequency between 0..1/2\+: 
\begin{DoxyCode}{0}
\DoxyCodeLine{f.setupN(norm\_cutoff\_frequency, Q\_factor);}
\end{DoxyCode}



\begin{DoxyEnumerate}
\item Designing filters with Python\textquotesingle{}s scipy.\+signal -- {\ttfamily \mbox{\hyperlink{Custom_8h_source}{Custom.\+h}}} 
\begin{DoxyCode}{0}
\DoxyCodeLine{\#\#\#\#\#\#\#\#}
\DoxyCodeLine{\# Python}
\DoxyCodeLine{\# See "elliptic\_design.py" for the complete code.}
\DoxyCodeLine{from scipy import signal}
\DoxyCodeLine{order = 4}
\DoxyCodeLine{sos = signal.ellip(order, 5, 40, 0.2, 'low', output='sos')}
\DoxyCodeLine{print(sos) \# copy/paste the coefficients over \& replace [] with \{\}}
\DoxyCodeLine{}
\DoxyCodeLine{///////}
\DoxyCodeLine{// C++}
\DoxyCodeLine{// part of "iirdemo.cpp"}
\DoxyCodeLine{const double coeff[][6] = \{}
\DoxyCodeLine{                \{1.665623674062209972e-\/02,}
\DoxyCodeLine{                 -\/3.924801366970616552e-\/03,}
\DoxyCodeLine{                 1.665623674062210319e-\/02,}
\DoxyCodeLine{                 1.000000000000000000e+00,}
\DoxyCodeLine{                 -\/1.715403014004022175e+00,}
\DoxyCodeLine{                 8.100474793174089472e-\/01\},}
\DoxyCodeLine{                \{1.000000000000000000e+00,}
\DoxyCodeLine{                 -\/1.369778997100624895e+00,}
\DoxyCodeLine{                 1.000000000000000222e+00,}
\DoxyCodeLine{                 1.000000000000000000e+00,}
\DoxyCodeLine{                 -\/1.605878925999785656e+00,}
\DoxyCodeLine{                 9.538657786383895054e-\/01\}}
\DoxyCodeLine{        \};}
\DoxyCodeLine{const int nSOS = sizeof(coeff) / sizeof(coeff[0]); // here: nSOS = 2 = order / 2}
\DoxyCodeLine{Iir::Custom::SOSCascade<nSOS> cust(coeff);}
\end{DoxyCode}

\end{DoxyEnumerate}\hypertarget{md_README_autotoc_md3}{}\doxysubsubsection{Realtime filtering sample by sample}\label{md_README_autotoc_md3}
Samples are processed one by one. In the example below a sample {\ttfamily x} is processed with the {\ttfamily filter} command and then saved in {\ttfamily y}. The types of {\ttfamily x} and {\ttfamily y} can either be float or double (integer is also allowed but is still processed internally as floating point)\+: 
\begin{DoxyCode}{0}
\DoxyCodeLine{y = f.filter(x);}
\end{DoxyCode}


This is then repeated for every incoming sample in a loop or event handler.\hypertarget{md_README_autotoc_md4}{}\doxysubsubsection{Error handling}\label{md_README_autotoc_md4}
Invalid values provided to {\ttfamily setup()} will throw an exception. Parameters provided to {\ttfamily setup()} which result in coefficients being N\+AN will also throw an exception.\hypertarget{md_README_autotoc_md5}{}\doxysubsection{Linking}\label{md_README_autotoc_md5}
\hypertarget{md_README_autotoc_md6}{}\doxysubsubsection{C\+Make setup}\label{md_README_autotoc_md6}
If you use cmake as your build system then just add to your {\ttfamily C\+Make\+Lists.\+txt} the following lines for the dynamic library\+: 
\begin{DoxyCode}{0}
\DoxyCodeLine{find\_package(iir)}
\DoxyCodeLine{target\_link\_libraries(... iir::iir)}
\end{DoxyCode}


or for the static one\+: 
\begin{DoxyCode}{0}
\DoxyCodeLine{find\_package(iir)}
\DoxyCodeLine{target\_link\_libraries(... iir::iir\_static)}
\end{DoxyCode}
\hypertarget{md_README_autotoc_md7}{}\doxysubsubsection{Generic linker setup}\label{md_README_autotoc_md7}
Link it against the dynamic library (Unix/\+Mac\+: {\ttfamily -\/liir}, Windows\+: {\ttfamily iir.\+lib}) or the static library (Unix/\+Mac\+: {\ttfamily libiir\+\_\+static.\+a}, Windows\+: {\ttfamily libiir\+\_\+static.\+lib}).\hypertarget{md_README_autotoc_md8}{}\doxysubsection{Packages for Ubuntu (xenial / bionic / focal)\+:}\label{md_README_autotoc_md8}
If you have Ubuntu\textquotesingle{}s L\+TS distros xenial, bionic or focal then install it as a pre-\/compiled package\+:


\begin{DoxyCode}{0}
\DoxyCodeLine{sudo add-\/apt-\/repository ppa:berndporr/dsp}
\end{DoxyCode}


It\textquotesingle{}s available for 32,64 bit PC and 32,64 bit A\+RM (Raspberry PI etc). The documentation and the example programs are in\+: 
\begin{DoxyCode}{0}
\DoxyCodeLine{/usr/share/doc/iir1-\/dev/}
\end{DoxyCode}
\hypertarget{md_README_autotoc_md9}{}\doxysubsection{Package for Mac\+OS}\label{md_README_autotoc_md9}
Make sure you have the homebrew package manager installed\+: \href{https://brew.sh/}{\texttt{ https\+://brew.\+sh/}}

Add the homebrew tap\+:


\begin{DoxyCode}{0}
\DoxyCodeLine{brew tap berndporr/dsp}
\end{DoxyCode}


and then install the iir filter package with\+:


\begin{DoxyCode}{0}
\DoxyCodeLine{brew install iir}
\end{DoxyCode}
\hypertarget{md_README_autotoc_md10}{}\doxysubsection{Compilation from source}\label{md_README_autotoc_md10}
The build tool is {\ttfamily cmake} which generates the make-\/ or project files for the different platforms. {\ttfamily cmake} is available for Linux, Windows and Mac. It also compiles directly on a Raspberry PI.\hypertarget{md_README_autotoc_md11}{}\doxysubsubsection{Linux / Mac}\label{md_README_autotoc_md11}
Run 
\begin{DoxyCode}{0}
\DoxyCodeLine{cmake .}
\end{DoxyCode}


which generates the Makefile. Then run\+: 
\begin{DoxyCode}{0}
\DoxyCodeLine{make}
\DoxyCodeLine{sudo make install}
\end{DoxyCode}


which installs it under {\ttfamily /usr/local/lib} and {\ttfamily /usr/local/include}.

Both gcc and clang have been tested.\hypertarget{md_README_autotoc_md12}{}\doxysubsubsection{Windows}\label{md_README_autotoc_md12}

\begin{DoxyCode}{0}
\DoxyCodeLine{cmake -\/G "Visual Studio 15 2017 Win64" .}
\end{DoxyCode}


See {\ttfamily cmake} for the different build-\/options. Above is for a 64 bit build. Then start Visual C++ and open the solution. This will create the D\+LL and the L\+IB files. Under Windows it\textquotesingle{}s highly recommended to use the static library and link it into the application program.\hypertarget{md_README_autotoc_md13}{}\doxysubsubsection{Unit tests}\label{md_README_autotoc_md13}
Run unit tests by typing {\ttfamily make test} or just {\ttfamily ctest}. These test if after a delta pulse all filters relax to zero and that their outputs never become NaN.\hypertarget{md_README_autotoc_md14}{}\doxysubsection{Documentation}\label{md_README_autotoc_md14}
\hypertarget{md_README_autotoc_md15}{}\doxysubsubsection{Learn from the demos}\label{md_README_autotoc_md15}
The easiest way to learn is from the examples which are in the {\ttfamily demo} directory. A delta pulse as a test signal is sent into the different filters and saved in a file. With the Python script {\ttfamily plot\+\_\+impulse\+\_\+fresponse.\+py} you can then plot the frequency responses.

Also the directory containing the unit tests provides examples for every filter type.\hypertarget{md_README_autotoc_md16}{}\doxysubsubsection{Detailed documentation}\label{md_README_autotoc_md16}
A P\+DF of all classes, methods and in particular {\ttfamily setup} functions is in the {\ttfamily docs/pdf} directory.

The online documentation is here\+: \href{http://berndporr.github.io/iir1}{\texttt{ http\+://berndporr.\+github.\+io/iir1}}\hypertarget{md_README_autotoc_md17}{}\doxysubsection{Example filter responses}\label{md_README_autotoc_md17}
These responses have been generated by {\ttfamily iirdemo.\+cpp} in the {\ttfamily /demo/} directory and then plotted with {\ttfamily plot\+\_\+impulse\+\_\+fresponse.\+py}.

      \hypertarget{md_README_autotoc_md18}{}\doxysubsection{Credits}\label{md_README_autotoc_md18}
This library has been further developed from Vinnie Falco\textquotesingle{}s great original work which can be found here\+:

\href{https://github.com/vinniefalco/DSPFilters}{\texttt{ https\+://github.\+com/vinniefalco/\+D\+S\+P\+Filters}}

While the original library processes audio arrays this library has been adapted to do fast realtime processing sample by sample. The {\ttfamily setup} command won\textquotesingle{}t require the filter order and instead remembers it from the template argument. The class structure has been simplified and all functions documented for doxygen. Instead of having assert() statements this libary throws exceptions in case a parameter is wrong. Any filter design requiring optimisation (for example Ellipic filters) has been removed and instead a function has been added which can import easily coefficients from scipy.\hypertarget{md_README_autotoc_md19}{}\doxysubsection{Bibliography}\label{md_README_autotoc_md19}

\begin{DoxyCode}{0}
\DoxyCodeLine{"High-\/Order Digital Parametric Equalizer Design"}
\DoxyCodeLine{ Sophocles J. Orfanidis}
\DoxyCodeLine{ (Journal of the Audio Engineering Society, vol 53. pp 1026-\/1046)}
\DoxyCodeLine{}
\DoxyCodeLine{"Spectral Transformations for digital filters"}
\DoxyCodeLine{ A. G. Constantinides, B.Sc.(Eng.) Ph.D.}
\DoxyCodeLine{ (Proceedings of the IEEE, vol. 117, pp. 1585-\/1590, August 1970)}
\end{DoxyCode}


Enjoy!

Bernd Porr -- \href{http://www.berndporr.me.uk}{\texttt{ http\+://www.\+berndporr.\+me.\+uk}} 