Optimize digital filters with differential evolution
Project description
This project originated when I was learning digital filter design from the book “Digital Signal Processing” [1] recommended to me by a colleague.
The main idea here is the optimization of digital filters (with additional constraints on group delay variation) with Differential Evolution (DE) inspired by an early paper on the subject by Rainer Storn [2], [3].
It also includes various Jupyter notebooks where I was experimenting with what I’d learned. These include:
IIR_Filter.ipynb: Various filter examples I could get my hands on to test my implementations of pole-zero plots, frequency response and group delay. It also includes the outcome of my attempts at optimizing filters with Differential Evolution (DE) inspired by an early paper on the subject by Rainer Storn [2] (the paper is behind a paywall, you may want to read the technical report [3] which has all information in the paper and is available online from ICSI, unfortunately as of this writing it seems the report is no longer available)
Experiments.ipynb: Here I tried conversion of analog filters to their digital counterparts. In addition I was experimenting with a method for minimizing group delay variance.
RIAA.ipynb: This has experiments with various digital filters for the RIAA equalization used in vinyl players. The digital filter can never fully match the analog filter (although I’m sure nobody my age can ever hope to hear the difference). This analyzes RIAA implementations from various sources.
Example call
The optimizer takes options for upper and lower bounds on the filter magnitude by frequency (in dB) as well as on the group delay (in samples). The options for the filter magnitude are -u and -l for upper and lower bound, respectively. The options for the group delay are (capital) -U and -L for upper and lower bound, respectively. These take four mandatory parameters: The minimum and maximum X-value, the minimum and maximum Y-value. In addition the number of points can be specified and another optional parameter if a raised cosine transform should be applied (this makes the points tighter at the bounds).
Experiment without pre-filter, this is from the Storn paper [3]:
mpirun --machinefile ~/.mpi-openmpi-cat --np 8 \ python3 -m filter_optimizer.filter_optimizer \ -u 0,0.04938,0.01,0.025,9 -u 0.04938,0.2716,0.025,0.025,73 \ -u 0.2716,0.3334,0.05,0.05,151 -u 0.3334,0.395,-12,-12,43 \ -u 0.395,0.5,-40,-40,37 \ -l 0.0,0.04938,-0.01,-0.025,9 -l 0.04938,0.2716,-0.025,-0.025,43 \ -l 0.2716,0.284,-0.05,-0.05 \ -U 0.0,0.284,0.10125,0.30375,17 -L 0.0,0.284,-0.10125,-0.30375,50 \ -R2 >! by2.out
The result in by2.out can be plotted with the command:
filter-show-from-log by5-prefilter.out
resulting in the magnitude graph in the following figure. Note that this program is interactive and we can zoom into the graph – which unfortunately is not possible here.
The green lines indicate the specified magnitude bounds while the blue line is the filter magnitude. The X-axis is the frequency in units of the sampling rate. The passband cannot be seen clearly so this is magnified in the following graph
The group delay is shown in the next figure
Again the green lines show the bounds while the blue line reflects the delay in samples. Note that the delay specification to the algorithm is not in absolute samples but relative to the middle of the delay.
The pole zero plot for this filter can be seen in the next figure
The same experiment can be run with a pre-filter, in the paper [3] an existing filter is asumed (the magnitude response of the pre-filter is shown in the IIR-Filter jupyter notebook) and the goal is to design a second filter so that both filter together fulfill the requirements. We see that we get a completely different filter (e.g. when looking at the pole-zero plot) but it still fulfills the requirements:
mpirun --machinefile ~/.mpi-openmpi-cat --np 8 \ python3 -m filter_optimizer.filter_optimizer --use-prefilter \ -u 0,0.04938,0.01,0.025,9 -u 0.04938,0.2716,0.025,0.025,73 \ -u 0.2716,0.3334,0.05,0.05,151 -u 0.3334,0.395,-12,-12,43 \ -u 0.395,0.5,-40,-40,37 \ -l 0.0,0.04938,-0.01,-0.025,9 -l 0.04938,0.2716,-0.025,-0.025,43 \ -l 0.2716,0.284,-0.05,-0.05 \ -U 0.0,0.284,0.10125,0.30375,17 -L 0.0,0.284,-0.10125,-0.30375,50 \ -R5 >! by5-prefilter.out
The next two are solutions to the specification of a high pass filter also with some group delay constraints also from a paper that optimizes filters with Differential Evolution [4] but using it for optimizing analog filters. I’ve added an upper limit of 2.5 dB for the transition band ripple. I leave it to the reader to plot the results:
mpirun --machinefile ~/.mpi-openmpi-cat --np 8 filter-optimizer \ -P 7 -Z 7 -u 0,1,-70,-70,100 -u 1,1.5,2.5,2.5,100 \ -l1.5,3.14159265,-0.075,-0.075,31,1 \ -u 1.5,3.14159265,0.075,0.075,31,1 -L 1.5,3.14159265,-1.25,-1.25,100 \ -U 1.5,3.14159265,1.25,1.25,100 --dont-scale-by-pi -R6 >! 06vond.out
mpirun --machinefile ~/.mpi-openmpi-cat --np 8 filter-optimizer \ -P 7 -Z 7 -u 0,1,-70,-70,100,0,0.9542 -u 1,1.5,2.5,2.5,100 \ -l1.5,3.14159265,-0.075,-0.075,31,1 \ -u 1.5,3.14159265,0.075,0.075,31,1 -L 1.5,3.14159265,-1.25,-1.25,100 \ -U 1.5,3.14159265,1.25,1.25,100 --dont-scale-by-pi -R6 >! 06vond+1x.out
Finally we have another example of a high-pass filter with tighter constraints in the transition band:
mpirun --machinefile ~/.mpi-openmpi-cat --np 8 filter-optimizer \ -P 7 -Z 7 -u 0,1,-70,-70,100 -u 1,1.5,0.075,0.075,100,0,1.174 \ -l1.5,3.14159265,-0.075,-0.075,31,1 \ -u 1.5,3.14159265,0.075,0.075,31,1 -L 1.5,3.14159265,-1.25,-1.25,100 \ -U 1.5,3.14159265,1.25,1.25,100 --dont-scale-by-pi \ -R8 >! hi-constraint-8+1.out
When we zoom in we find that the constraints seem to be violated at certain positions, we see two peaks overflowing the upper green line and also the lower green line seems to be violated.
To see what is going on we can use the --scatter option when plotting. Instead of a line we only show the individual positions where we actually test the bounds. We see that due to the raised cosine distribution of points we actually have huge gaps in the points where we test the boundaries.
And even the seemingly high violation happens to pass between two test points. So when setting up the bounds you should check that the number of test points is high enough and verify that no violations occur.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file filter_optimizer-0.2.tar.gz.
File metadata
- Download URL: filter_optimizer-0.2.tar.gz
- Upload date:
- Size: 23.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.11.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4ae6f92bbff7d5b46a76f4e038587899bc016a81aa6389a8194a216dede7b221
|
|
| MD5 |
ca8b0ad4be1538417484c6af1834f8f5
|
|
| BLAKE2b-256 |
a8d1feffc2ee0040d5e4435b1ea90b6237eeffcf29c918d83be1596fe9de0d46
|
File details
Details for the file filter_optimizer-0.2-py3-none-any.whl.
File metadata
- Download URL: filter_optimizer-0.2-py3-none-any.whl
- Upload date:
- Size: 21.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.11.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0d3348bfa7ed17aa4d82dd0271a41022a2e99456ca105f799a40f07f13810bc6
|
|
| MD5 |
47918fa7dc03ccde1eb4df042cda0a71
|
|
| BLAKE2b-256 |
1e2d9faecd1ffadd5b8f3ae6039f6ae3ece0b0e1433fe7a00888f395559cc1e9
|