Skip to content

Window-method FIR design

Cut the ideal low-pass to length, taper it with a window, size it with Kaiser's formulas, and build high-pass, band-pass and band-stop filters from it.

Before this15.1 · 15.2 · 18.1 · 5 more
Chapter 19 · Lesson 1 of 4

First, the picture

Start from the perfect low-pass and keep only its middle taps. Below, the cut keeps 21, then 41, then 81 taps. Watch the bracket at the edge shrink, and the dotted level at the top stay where it is.

Cut the ideal, and the edge ripples

12.4's ideal low-pass, Ω_c = 0.25π, moved to its centre and cut to N_h taps.

21 taps: the gain overshoots to 1.073 next to the edge and ripples on both sides.

taps N_h
21
highest
1.073
edge width
0.081π rad/sample
0.00 / 13.00 s
Describe this picture

Two stacked panels for 12.4’s ideal low-pass, Ωc=0.25π\Omega_c=0.25\pi, moved to its centre and cut to NhN_h taps. The taps panel plots h[n]h[n] against n−αn-\alpha, the samples from the centre: the kept taps are stems with dot heads, and the ideal’s further values are faint open circles labelled “cut off”. The gain panel plots Hzp(Ω)H_\text{zp}(\Omega) against Ω\Omega in rad/sample. The ideal is a thin dashed box, and the design is a solid curve. A dotted level sits at the design’s highest value and is labelled with it, and a bracket labelled “edge” spans the edge from the 0.9 crossing to the 0.1 crossing. The readouts are the taps NhN_h, the highest value and the edge width.

The clip lasts 13 s, with a blank caption while the taps change. At 21 taps the gain overshoots to 1.073 next to the edge and ripples on both sides; the edge width is 0.081π0.081\pi rad/sample. The taps grow at both ends to 41, held at 5.25 s: the edge is twice as steep, 0.045π0.045\pi, but the overshoot is still there, 1.099. Last the taps grow to 81: steeper again, 0.022π0.022\pi, and the overshoot stays near 1.09, the 9 % of 7.3. The end caption adds that keeping NhN_h taps is multiplying by a rectangular window. After the clip a slider named “Taps N_h” takes the odd values from 11 to 101: the arrow keys move it by 2, Page Up and Page Down by 10, and Home and End jump to 11 and 101. The choice is kept in the link, as cut.N.

Cut the ideal, and the edge ripples

In Filter specifications (18.1) we wrote down how close to ideal a low-pass has to be. Now I want to build one. The plan is the simplest I know: start from the perfect filter and keep the part of it that matters.

On the page Frequency response of discrete-time systems (12.4), the ideal low-pass with cutoff Ωc\Omega_c had this impulse response. I call it the desired response, hdes[n]h_\text{des}[n]:

hdes[n]=sin⁡(Ωcn)πn,hdes[0]=Ωcπ.h_\text{des}[n]=\frac{\sin(\Omega_cn)}{\pi n},\qquad h_\text{des}[0]=\frac{\Omega_c}{\pi}.

It never ends in either direction, which is why it cannot be built. But its values shrink as nn moves away from 0, so the part near the peak carries most of it.

So let’s keep only that part. Shift hdesh_\text{des} to the right by α\alpha samples, so that the kept part starts at n=0n=0, and keep Nh=2α+1N_h=2\alpha+1 taps:

h[n]=hdes[n−α],0≤n≤Nh−1.h[n]=h_\text{des}[n-\alpha],\qquad 0\le n\le N_h-1.

The taps are symmetric about α\alpha. By Linear-phase systems (17.3), the filter is then linear phase with a delay of α\alpha samples, and its gain is the real zero-phase response Hzp(Ω)H_\text{zp}(\Omega).

The picture at the top of the page uses 12.4’s own example, Ωc=0.25π\Omega_c=0.25\pi, whose centre tap is hdes[0]=0.25π/π=0.25h_\text{des}[0]=0.25\pi/\pi=0.25. It cuts it to 21, 41 and then 81 taps. To compare the cuts I measure an edge width. It is the distance in Ω\Omega from the last point before the cutoff where the gain is 0.9 to the first point after it where it is 0.1.

Watch what moves and what stays. The edge width roughly halves each time the taps double: it is about 1.8π/Nh1.8\pi/N_h. The highest value hardly moves. It stays near 1.09, an overshoot of about 9 % of the jump from 1 to 0, which is the bump of Convergence and the Gibbs phenomenon (7.3).

After the clip, set the number of taps yourself with the slider. At 61 taps the highest value is 1.084 and the edge width 0.029π. Try 101: the edge narrows to 0.017π, and the highest value is still 1.086. Then try 11. The edge is now so wide, 0.179π, that the highest value, 1.078, is at Ω=0\Omega=0 and not next to the edge.

Why does the ripple stay? Keeping NhN_h taps multiplies hdes[n−α]h_\text{des}[n-\alpha] by a rectangular window: 1 on the kept taps and 0 everywhere else. By Properties of the DTFT (12.3), multiplying in time convolves the spectra. So the gain is the ideal box smeared by the rectangular window’s spectrum.

As NhN_h grows, that spectrum’s main lobe narrows, so the edge gets steeper. Its side lobes narrow too, but they keep their height relative to the main lobe. They are what makes the ripple, so the ripple keeps its height as well.

A smoother window has smaller side lobes (Window functions compared, 15.2). So let’s multiply by one of those instead. Windows for filters are the symmetric kind: w[n]w[n] for n=0n=0 to Nh−1N_h-1 is symmetric about α\alpha. In SciPy that is get_window(name, N_h, fftbins=False), and NumPy’s np.hanning is symmetric already.

15.2 used periodic windows, which are made for spectra. A symmetric window keeps the product symmetric, so the filter stays linear phase. That gives the window design:

h[n]=w[n] hdes[n−α],α=Nh−12,0≤n≤Nh−1.\begin{aligned} h[n]&=w[n]\,h_\text{des}[n-\alpha],\\ \alpha&=\frac{N_h-1}{2},\qquad 0\le n\le N_h-1. \end{aligned}

The maths behind it · orthogonal projections

Keeping the first terms of an expansion in orthogonal functions is an orthogonal projection, and 7.3 showed it gives the smallest squared error. So the plain cut is the least-squares best NhN_h-tap filter for the ideal box over the whole band. A window gives that up to shrink the worst error instead. Optimal FIR design (19.3) makes both choices exact.

A window trades a wider edge for less ripple

The instrument below keeps the 41 taps and changes only the window: rectangular, which is the plain cut, then Hann, Hamming and Blackman. It is like sanding a sawn edge. The splinters go, and the edge gets rounder.

I write δ\delta for a design’s ripple: the largest distance of its gain from 1 in the pass band, or from 0 in the stop band. For a window design the ripples in the two bands come out nearly equal, so one δ\delta describes both. The instrument gives the stop band’s ripple in dB, 20log⁡10δ20\log_{10}\delta.

Its transition is measured with that δ\delta. It runs from the last Ω\Omega below the cutoff where the gain is within δ\delta of 1 to the first Ω\Omega above it where the gain is within δ\delta of 0. It is not the edge width of the first instrument, which used the fixed levels 0.9 and 0.1.

A window trades a wider edge for less ripple

The same 41 taps of the ideal low-pass (Ω_c = 0.25π), multiplied by four windows.

Rectangular, the plain cut: ripple up to −21.7 dB, and the narrowest transition, 0.047π.

window
rectangular
stop band
−21.7 dB
transition
0.047π rad/sample
Window
0.00 / 17.00 s
Describe this picture

Two stacked panels for the same 41 taps of the ideal low-pass (Ωc=0.25π\Omega_c=0.25\pi), multiplied by four windows. The taps panel draws h[n]h[n] against the sample nn as stems with dot heads, with the window, scaled to the panel, as a dashed curve labelled with its name. The gain panel plots the gain from −100 to 5 dB against Ω\Omega in rad/sample as a solid curve. A dotted level sits at the stop band’s highest peak and is labelled with it, and a bracket labelled “transition” spans the transition. The readouts are the window, the stop band and the transition.

The clip lasts 17 s and cross-fades from window to window, with a blank caption during each cross-fade. Rectangular, the plain cut, has ripple up to −21.7 dB and the narrowest transition, 0.047π. At 5.45 s comes Hann: the taps taper to 0 at the ends, the ripple falls to −44.0 dB, and the transition widens to 0.156π. At 9.65 s Hamming reaches −52.3 dB with a transition of 0.165π. At the end Blackman reaches −75.6 dB, but with a transition of 0.294π, six times the plain cut’s. After the clip the four windows are buttons in a group named “Window”; the arrow keys move between them, and Home and End jump to the first and the last. Each choice shows that window’s caption from the clip, and it is kept in the link, as trade.w.

After the clip, press each window’s button to compare them yourself. Notice that Blackman’s stop band is 54 dB below the plain cut’s, while its transition is six times as wide.

A window’s side lobe is not the filter’s ripple

Hann’s highest side lobe is −31.5 dB (15.2), yet the Hann filter reaches −44 dB. Why the difference? The convolution adds up the window’s spectrum WW over a stretch as wide as the box. As Ω\Omega crosses the edge, that stretch slides off WW, so the gain there is a running area under WW.

A running area is set by how much area the side lobes hold, not by how tall the tallest one is. Side lobes that alternate in sign and shrink quickly add up to very little. So each window reaches more as a filter than its side lobe suggests.

The transition shrinks like 1/(Nh−1)1/(N_h-1), so I give it as a multiple of π/(Nh−1)\pi/(N_h-1). The table puts the textbook values (Oppenheim and Schafer, table 7.2) beside my own measurements at 201 taps, with each window’s highest side lobe from 15.2.

WindowHighest side lobeStop band (textbook)Stop band (201 taps)Transition × (Nh−1)(N_h-1) (textbook)Transition × (Nh−1)(N_h-1) (201 taps)
rectangular−13.3 dB−21 dB−21.2 dB1.8π1.8\pi1.88π1.88\pi
Hann−31.5 dB−44 dB−43.9 dB6.2π6.2\pi6.25π6.25\pi
Hamming−42.7 dB−53 dB−53.7 dB6.6π6.6\pi6.69π6.69\pi
Blackman−58.1 dB−74 dB−75.3 dB11π11\pi11.17π11.17\pi

Now let’s size a Hann design for the running spec of 18.1. It needs 40 dB, and Hann reaches 44. The transition is ΔΩ=0.125π\Delta\Omega=0.125\pi, so 6.2π/(Nh−1)≤0.125π6.2\pi/(N_h-1)\le0.125\pi, which gives Nh−1≥49.6N_h-1\ge49.6 and Nh≥51N_h\ge51. The shortest Hann design that really passes has 50 taps: the table is a guide, not a guarantee.

From the spec to the taps

The table makes you pick from four windows with fixed ripples. The Kaiser window of 15.2 has a knob, β\beta, and Kaiser found two formulas that turn a spec straight into β\beta and a length (Oppenheim and Schafer, §7.6). A window design has one ripple δ\delta in both bands, so take the smaller of δpass\delta_\text{pass} and δstop\delta_\text{stop}, and Astop=−20log⁡10δA_\text{stop}=-20\log_{10}\delta.

For AstopA_\text{stop} from 21 to 50 dB, which covers the running spec, the first formula is

β=0.5842 (Astop−21)0.4+0.07886 (Astop−21).\begin{aligned} \beta&=0.5842\,(A_\text{stop}-21)^{0.4}\\ &\quad+0.07886\,(A_\text{stop}-21). \end{aligned}

Above 50 dB it is β=0.1102 (Astop−8.7)\beta=0.1102\,(A_\text{stop}-8.7). Below 21 dB it is β=0\beta=0, the rectangular window, which reaches 21 dB by itself. The second formula gives the length:

Nh−1≥Astop−7.952.285 ΔΩ.N_h-1\ge\frac{A_\text{stop}-7.95}{2.285\,\Delta\Omega}.

These are not 15.2’s side-lobe rule. There β\beta was chosen for a window’s side lobe; here it is chosen for a filter’s ripple. Place the cutoff in the middle of the transition, Ωc=(Ωpass+Ωstop)/2\Omega_c=(\Omega_\text{pass}+\Omega_\text{stop})/2. In SciPy, kaiserord gives both numbers and firwin gives the taps.

One difference from the first two instruments: firwin scales the taps so that the gain at Ω=0\Omega=0 is exactly 1. The plain product w[n] hdes[n−α]w[n]\,h_\text{des}[n-\alpha] does not. Think of the formulas as a recipe’s baking time. It is a good start, but you still check the cake. Below, the formulas size a design for the running spec, and the zones check it.

From the spec to the taps

The running spec of 18.1. Kaiser's formulas choose β and N_h; the design is checked against the zones.

β
not yet
taps N_h
not yet
stop band, worst
not yet
0.00 / 13.00 s
Describe this picture

Two stacked panels for the running spec of 18.1, where Kaiser’s formulas choose β\beta and NhN_h and the design is checked against the zones. The taps panel draws h[n]h[n] against the sample nn as stems with dot heads; its range grows with the design. The gain panel is the spec drawing of 18.1: the gain from −80 to 5 dB against frequency from 0 to 4000 Hz, with the running spec’s forbidden zones hatched and “−40 dB” at the stop edge. The design is a solid curve, and a cross marks its worst stop-band point when it fails. The readouts are β\beta, the taps NhN_h and the worst stop-band level with a word, such as “−39.8 dB, fails”. Each reads “not yet” until its number exists: β\beta once the zones are in, the length when the taps start to grow, and the worst level when the curve is complete.

The clip lasts 13 s. First the zones fade in. The stricter ripple is the stop band’s, 0.01, so Astop=40A_\text{stop}=40 dB, and the transition is 500 Hz, 0.125π0.125\pi; Kaiser’s first formula gives β=3.40\beta=3.40. Then the second formula gives the length, 37 taps, which grow from the centre outwards while the curve draws. At 7 s the gain at 1500 Hz is −39.8 dB, 0.2 dB short of the spec: the formula is an estimate. Then the design morphs to 38 taps: −41.7 dB, with the pass band within 0.012 of 1. It passes, with a delay of 18.5 samples, 2.3 ms. After the clip the stop edge is a handle named “Stop edge”, from 1100 to 2500 Hz in steps of 25 Hz, with a value like “1500 Hz: 38 taps”; the pass edge stays at 1000 Hz. The arrow keys move the edge by 25 Hz, Page Up and Page Down by 100 Hz, and Home and End jump to 1100 and 2500 Hz. The position is kept in the link, as kaiser.fstop.

The formula was 0.2 dB short, and one more tap fixed it. Notice that 38 is even, so the centre α=18.5\alpha=18.5 falls between two taps. By 17.3 an even-length symmetric filter has a zero forced at z=−1z=-1, but a low-pass does not mind a zero at Ω=π\Omega=\pi.

After the clip, drag the stop edge yourself, or use the arrow keys; the pass edge stays at 1000 Hz. The widget takes Kaiser’s length and adds one tap at a time until the design passes. β\beta stays 3.40, because AstopA_\text{stop} stays 40 dB. At 1250 Hz Kaiser’s estimate is 73 taps, and 74 pass. At 2000 Hz, 19 taps pass, as estimated.

Halve the transition and the length doubles: 37 taps at 500 Hz, 73 at 250 Hz. The estimate is right or one tap short across the whole range.

One low-pass, four filters

The other three shapes can be built from low-passes. Start with a high-pass. Subtract the low-pass from a pure delay:

hhp[n]=δ[n−α]−h[n].h_\text{hp}[n]=\delta[n-\alpha]-h[n].

The delay δ[n−α]\delta[n-\alpha] passes every frequency with gain 1 and the same delay α\alpha, so the high-pass’s zero-phase response is 1−Hzp(Ω)1-H_\text{zp}(\Omega). Where the low-pass passes, the high-pass stops, and the other way round.

This needs an odd NhN_h, so that α\alpha is a whole number of samples. There is a second reason. An even-length symmetric filter has a zero forced at z=−1z=-1 (17.3), so it cannot pass Ω=π\Omega=\pi, and SciPy’s firwin refuses an even-length high-pass.

Subtracting from 1 turns the low-pass’s pass-band ripple into the high-pass’s stop-band ripple. So design the low-pass to the stricter δ\delta. A different route also works: by 12.3, multiplying by (−1)n(-1)^n slides the response by π\pi, so (−1)nh[n](-1)^nh[n] is a high-pass with cutoff π−Ωc\pi-\Omega_c.

A band-pass from Ω1\Omega_1 to Ω2\Omega_2 is a low-pass with cutoff Ω2\Omega_2 minus a low-pass with cutoff Ω1\Omega_1, both with the same NhN_h and window: hbp=hlp,Ω2−hlp,Ω1h_\text{bp}=h_{\text{lp},\Omega_2}-h_{\text{lp},\Omega_1}. A band-stop is δ[n−α]\delta[n-\alpha] minus a band-pass. The figure builds all four from one 39-tap Kaiser design.

low-pass, cutoff 1250 Hz01gainhigh-pass: δ[n − 19] − h[n]01gainband-pass: low-pass at 2750 Hz minus the low-pass01gainband-stop: δ[n − 19] minus the band-pass01gain01000200030004000frequency (Hz)
Fig. One 39-tap Kaiser low-pass (β = 3.40) and three filters built from it. Each has gain 0.50 at its cutoffs. The high-pass’s stop band reaches −37.3 dB: inverting turned the low-pass’s pass-band ripple, 0.0136, into stop-band ripple.

Worked example

Let’s redo the page’s numbers by hand where we can, and with SciPy where we can’t.

1. The ideal, cut. With Ωc=0.25π\Omega_c=0.25\pi and 41 taps, α=20\alpha=20 and the centre tap is h[20]=0.25h[20]=0.25. Every fourth tap from the centre is 0, because sin⁡(0.25π⋅4k)=sin⁡(kπ)=0\sin(0.25\pi\cdot4k)=\sin(k\pi)=0. The gain peaks at 1.099, dips to −0.082 and has an edge width of 0.045π.

That dip, 0.0825 below zero, is the rectangular window’s ripple in the second instrument: 20log⁡100.0825=−21.720\log_{10}0.0825=-21.7 dB.

2. Kaiser for the running spec. The stop band’s 0.01 is stricter than the pass band’s 0.05, so Astop=40A_\text{stop}=40 dB. Then β=0.5842⋅190.4+0.07886⋅19=1.8970+1.4983=3.3953\beta=0.5842\cdot19^{0.4}+0.07886\cdot19=1.8970+1.4983=3.3953. The transition is ΔΩ=2π⋅500/8000=0.125π=0.3927\Delta\Omega=2\pi\cdot500/8000=0.125\pi=0.3927 rad/sample.

The length formula gives Nh−1≥(40−7.95)/(2.285⋅0.3927)=35.72N_h-1\ge(40-7.95)/(2.285\cdot0.3927)=35.72, so Nh−1=36N_h-1=36 and Nh=37N_h=37. The cutoff goes in the middle of the transition, (1000+1500)/2=1250(1000+1500)/2=1250 Hz. There 37 taps fail by a little, −39.80 dB at 1500 Hz. 38 taps pass, at −41.68 dB.

The 38 taps have their centre between h[18]h[18] and h[19]h[19], which both equal 0.3009. The ideal there, half a sample from its centre, is sin⁡(0.3125π⋅0.5)/(0.5π)=0.3001\sin(0.3125\pi\cdot0.5)/(0.5\pi)=0.3001, so the window and the scaling barely touch the middle. The end taps are −0.0016.

3. Other windows on the running spec. I tried firwin with each window and growing NhN_h until the design passed. The table gives the shortest length that passes, and the shortest odd one. Kaiser’s tuned β\beta saves 12 taps over Hann.

WindowShortest NhN_h that passesShortest odd NhN_h
Hann5051
Hamming5051
Blackman6667
Kaiser, β=3.40\beta=3.403839

4. A high-pass from the 39-tap low-pass. The low-pass’s centre tap is 0.3139, so the high-pass’s centre tap is 1−0.3139=0.68611-0.3139=0.6861. All the other taps just change sign. The low-pass has pass-band deviation 0.0136 and stop band −40.57 dB. The high-pass swaps them: pass-band deviation 0.0094, and stop band 20log⁡100.0136=−37.3020\log_{10}0.0136=-37.30 dB.

The band-pass’s centre tap is 0.6869−0.3139=0.37300.6869-0.3139=0.3730, and the band-stop’s is 1−0.3730=0.62701-0.3730=0.6270. Every cutoff gain is 0.50 to two decimals.

5. The window table at 201 taps. I used firwin(201, 0.25, window=name) and the rules of the second instrument: the ripple beyond the first null after the cutoff, and the transition between the points within that ripple of 1 and of 0. That gave stop bands of −21.2, −43.9, −53.7 and −75.3 dB, and transitions of 1.88π1.88\pi, 6.25π6.25\pi, 6.69π6.69\pi and 11.17π11.17\pi over 200.

Where you’ll meet this

The window method is the default FIR design in SciPy (firwin) and MATLAB (fir1). It makes anti-alias and decimation filters (Downsampling and decimation, 22.1), audio crossovers and biomedical filters. Reach for it wherever a quick, reliable linear-phase design is enough.

When every tap counts, Optimal FIR design (19.3) meets the same spec with fewer. Frequency-sampling design (19.2) designs from samples of the gain instead. Whether an FIR is the right choice at all is Choosing FIR or IIR (20.6), and long FIRs run fast with Fast convolution (14.3).

The maths behind it · kernel smoothing

In kernel smoothing, a hard-edged box kernel makes a fitted curve ring next to jumps. A smooth kernel, such as the Epanechnikov or the Gaussian, trades that ringing for blur. A window on hdesh_\text{des} is the same trade, with the transition width as the blur.

Reference card

QuantityFormulaNotes
Window designh[n]=w[n] hdes[n−α]h[n]=w[n]\,h_\text{des}[n-\alpha], α=(Nh−1)/2\alpha=(N_h-1)/2symmetric ww: linear phase
Ideal low-passhdes[n]=sin⁡(Ωcn)πnh_\text{des}[n]=\dfrac{\sin(\Omega_cn)}{\pi n}, hdes[0]=Ωc/πh_\text{des}[0]=\Omega_c/\piΩc\Omega_c mid-transition
Plain cutripple about 9 % at any NhN_h7.3’s Gibbs bump
Window as filterstop band: rectangular −21, Hann −44, Hamming −53, Blackman −74 dBtransition 1.8π1.8\pi, 6.2π6.2\pi, 6.6π6.6\pi, 11π11\pi over Nh−1N_h-1
Kaiser β\beta0.5842(Astop−21)0.4+0.07886(Astop−21)0.5842(A_\text{stop}-21)^{0.4}+0.07886(A_\text{stop}-21) for 21 to 50 dB; 0.1102(Astop−8.7)0.1102(A_\text{stop}-8.7) aboveAstop=−20log⁡10δA_\text{stop}=-20\log_{10}\delta
Kaiser lengthNh−1≥(Astop−7.95)/(2.285 ΔΩ)N_h-1\ge(A_\text{stop}-7.95)/(2.285\,\Delta\Omega)an estimate: check, add a tap
High-passδ[n−α]−h[n]\delta[n-\alpha]-h[n], NhN_h oddripples swap bands
Band-passhlp,Ω2−hlp,Ω1h_{\text{lp},\Omega_2}-h_{\text{lp},\Omega_1}band-stop: δ[n−α]−hbp\delta[n-\alpha]-h_\text{bp}

End of lesson 19.1

Where to go next.

Phasorium
LibraryEvery lesson, in order

Parts

About Phasorium
Look