A filter widget prototype

This is a little prototype I made in order to see if it would be intuitive to specify filters as the poles and zeros of a transfer function by dragging points around the complex plane with the mouse.

The particular form of transfer function shown in the demo is $$ H(z) = c \frac{h_{11}(z) h_{12}(z)}{h_{21}(z) h_{22}(z)}$$ where $ h_{ij}(z) = (z - a_{ij})(z - \overline{a_{ij}})$ and $c$ is chosen such that $|H(-1)| = 1$, which is a convenient choice for making a high-pass filter.

Code snapshot for this article (tagged filter_input_widget_prototype-2016-10-16): .zip, .tar.gz. For latest version, go to the github page.

A bit more explanation

The dots

The black dots are poles and the white dots are zeros. In other words, the four white dots are the $a_{1,j}$ and their complex conjugates. The four black dots are the $a_{2,j}$ and their complex conjuagates.

The disks on the left

There are two copies of the complex plane shown, but it displays the same configuration of points. The upper one shows a plot of the magnitude (i.e. $z \to |H(z)|$), and the lower one shows a plot of the phase ($z \to \arg(H(z))$). In both cases I have quantized the colors to only a few levels. It's easier to get a sense of the shapes that way than with a smooth gradient.

The phase is displayed by mapping it to a color wheel. This kind of plot is called a domain coloring of $H$.

The graphs on the right

Now for the diagrams on the right-hand side. The top plot shows $f \to |H(e^{-i \pi f})|$, and the bottom plot shows $f \to \arg\left(H\left(e^{-i \pi f}\right)\right)$. So they are the magnitude and phase we measure if we walk along the top semicircles of the upper and lower disks shown on the left hand side, respectively. These diagrams are known as the Bode plots of a filter.

The y-axes of both plots have, besides numbers, also the colors that the numerical ranges correspond to in the color-disks.

Implementation

This is a D3D11 program written in C++ for Windows. The disks are drawn using special-purpose shaders. There is no supersampling in those shaders yet (just a single sample per pixel), which causes the level-curves to look a bit aliased.

The grid is also drawn using a special shader, and the numbers in the plots are drawn in a bitmap font I made by hand. As such, it is unfortunately constrained to whole-pixel coordinates, which sometimes makes slow movement a little wobbly-looking.