diyAudio (
-   Digital Line Level (
-   -   iDFT-based XOs (FIR) (

steph_tsf 18th August 2012 10:17 PM

iDFT-based XOs (FIR)
5 Attachment(s)
Just in case you want to experiment with FIRs in a digital XO, here are a few utilities relying on the iDFT (inverse discrete Fourier transform).

For more info about the iDFT and the DFT, please visit Steven W. Smith website Notation and Format of the Real DFT

In a nutshell, if you plan using a N-tap FIR at the heart of your digital XO, you need to define a lowpass Bode plot (gain and phase) as target, from DC to Fs/2, using N equally spaced (in linear scale) frequency bands.

Say Fs is 48,000 Hz. If you plan using a 10-tap FIR, you only have 10 equally spaced (in linear scale) frequency bands at your disposition. Each will thus be 4,800 Hz wide. Don't expect good results. Unless you want to split the audio in two bands like below 4,800 Hz (the lowpass) and above 4,800 Hz (the corresponding complementary highpass). This is something worth trying indeed.

Say Fs is 48,000 Hz. If you plan using a 100-tap FIR, you have 100 equally spaced (in linear scale) frequency bands at your disposition. Each will thus be 480 Hz wide. Of course you need some fast hardware, able to execute 100 multiply accumulate (MACC) per audio sample that's incoming. A stereo 2-way XO operating this way will thus require 48,000 x 4 x 100 MACC = 19.2 Mega MACC/s. A Microchip PIC32MX2 (two I2S ports) may be able to execute this, clocked at 40 MHz. Some ARM Cortex-M0 like NXP LPC111x (the ones equipped with two SSP) may be also be able to execute this, clocked at 50 MHz. Any decent PC running BASS, BASSASIO and ASIO (or ASIO4ALL) can execute this.

So, what's the point with the iDFT here?

Once you have defined the lowpass target Bode plot, you know everything about the system, in frequency domain.
Applying the iDFT on the corresponding data set (gain array and phase array), you get the corresponding time domain impulse response.
Such time domain impulse response can be viewed as a file, listing the required FIR coefficients.
So simple.

It's entirely up to you to define a lowpass target Bode plot that makes sense for a crossover. As lowpass target Bode plot, you may specify some Butterworth equivalent. Of any order. Even a non-integer order if you want. Or some Bessel equivalent. Of any order. Even a non-integer order if you want. Or a Brickwall. Or some asymptotic lowpass, of any order. Etc ...

Quite obligatory is to design the crossover as perfectly complementary. This means that when summing the lowpass and the highpass outputs, you get back the input signal. You thus can expect a perfect reconstruction, both in amplitude and in phase.
How to compute the complementary highpass from the lowpass FIR? That's quite simple, knowing that in time domain, the lowpass + highpass sum must equal the Dirac. As consequence, generally speaking, the highpass FIR is the lowpass FIR with a minus sign. This way, the sum is zero outside of the Dirac pulse. Which is what we want. The notable exception being the midpoint, where we must ensure that the highpass midpoint FIR coefficient equals unity less the lowpass midpoint FIR coefficient.
So simple.

The "iDFT XO" app illustrates all this.
I encourage you to play with.
The light-blue crossmarks make up the target lowpass amplutide curve.
The solid blue line shows you how the iDFT obeys the target lowpass.
The solid red line shows you the complementary highpass.
The lowpass FIR coefficients get written on your hard disk, in your "My Documents" directory.

steph_tsf 18th August 2012 10:25 PM

The "iDFT XO CGn" app zooms on a particular lowpass target family.

XO for Crossover
C for Complementary.
Gn for Gauss any order

I designed it for answering all sorts of recurrent questions about "pure Gauss" and "Gauss-derived" crossovers. It illustrates the fact that if you select a "Gauss" order that's higher than 2, yes indeed the lowpass and highpass slopes do improve, but unfortunately the particular "Gauss" quality isn't there anymore as we observe preshoot and ringing in time domain. That's exactly what Berchin says (1999 publication).
If you want a neat, clean XO exhibiting no preshoot and ringing, select the "true" Gauss (thus with an order that's equal to 2), aka "Berchin", and you are done. Just make sure your tweeter can cope with the 2nd-order highpass slope.
If your tweeter needs a steeper highpass slope, select a higher "Gauss" order, but beware preshoot and ringing in time domain.

steph_tsf 18th August 2012 10:36 PM

A few words about Windowing.

As it is always the case with FIRs, you can apply some Windowing.
Selecting "rectangle" means "no window" actually.
The window gets embedded in the FIR coefficients, at design stage. From a processing power perspective, it costs nothing to introduce a windowing function. During runtime, your PIC32, ARM Cortex-M, or x86 PC won't see any difference.

Playing with the apps, you will observe that most Windowing functions tend to smooth the amplitude curve, erasing out-of-band irregularities. The price to pay are somewhat relaxed slopes.

Playing with the apps you will observe that using some Windowing functions, you get nice amplitude curves exhibiting a good balance between selectivity, out-of-band rejection and sharpness, without relying on extra long FIRs.

steph_tsf 19th August 2012 11:24 AM

3 Attachment(s)
A few examples running iDFT XO.

Say your harware is not so powerful. You want to reduce the FIR length. Let's try with a 31-tap FIR. This means 48,000 x 4 x 31 = 6 million multiply-accumulate per second. Any Microchip PIC32, ARM Cortex-M0/3/4 or x86 PC can do this. Digital diyAudio nowadays can (and needs) to base on proletarian hardware. The real issue are the I2S interfaces. How many PIC32 and ARM Cortex-M0/3/4 do you know, equipped with one I2S acting as digital audio input plus two I2S acting as digital audio outputs? Answer : PIC32MX2, STM32F4, Infineon XMC4500, and NXP LPC4330. Of course we still have the Freescale DSP56K family (not recommended for new designs) and the ADI SigmaDSP (currently used in miniDSP). Of course we can use an x86 PC running BASS, BASSASIO and ASIO (or ASIO4ALL).

We'll use a somewhat high crossover frequency. Say 3,800 Hz as starting point. Therefore, no question of using a big woofer. The woofer shall exhibit a consistent frequency response and wide polar diagram until 6 kHz or so. Say two 5 inch midbass drivers in a 2-way d'Appolito setup supposed to reproduce 50 Hz to 20 kHz. Say one or two 4 inch midbass drivers if we are dealing with a 2-way satellite unit supposed to reproduce 160 Hz to 20 kHz. There is nothing expensive here. Being crossed at 3,800 Hz, the tweeter can be anything from a miniature 13mm dome (Visaton CP13), miniature 16mm dome (Dayton ND16) or miniature 20mm dome (Dayton ND20). Again, there is nothing expensive here.

Say you heard about Bessel filters, exhibiting no preshoot and ringing. This is figure 1. You may feel happy with such Bessel 2nd-order.

Wanting some more slope regarding the woofer? Try the Bessel 4th-order. This is figure 2. Note the tweeter slope : it hasn't changed. It's still a 2nd-order highpass.

Wanting to improve the tweeter slope? Try the Butterworth 2nd-order "double". Kind of Linkwitz-Riley. This is figure 3. Better than Linkwitz-Riley as this time, there is no phase distorsion in the reconstructed signal. Dirac in, Dirac out. What about preshoot and ringing? Looks decent. Why not trying this, after all?

All this with "rectangular" windowing, aka no windowing at all.

Amazing, isn't ?

For the same price, we can embed a driver linearization feature into each FIR.

What about 3-way systems? Do we need a 310-tap FIR for crossing at 380 Hz instead of 3,800 Hz? At the moment I would say yes. Which means 60 million multiply-accumulate per second. Are Microchip PIC32 and ARM Cortex-M0/M3 ruled out here ? Maybe not. The trick, as explained by CopperTop, is to apply a 256-tap or 512-tap FFT, execute the filter in frequency domain, then execute an inverse FFT.

steph_tsf 19th August 2012 12:25 PM

2 Attachment(s)
A few examples iDFT XO CGn.

What if trying a kind of infinite order Bessel as lowpass? This is the purpose of the "iDFT XO CGn" app.

First of all, we need to define the target Bode plot (amplitude) as a typical bell-shaped curve. Actually this is half a Gauss curve, only the right part of it, with the transmission equal to 1.0 for DC , 0.5 for the crossover frequency, and zero for the infinite frequency. You may see it as a bell-shaped curve if you extend the left part using negative frequencies.

The target Bode plot is thus generated this way, very simply:

order = 2
For i = 0 To N
- F = FS * (i / N)
- If F < Fcut Then GAIN(i) = Math.Exp(((F / Fcut) ^ order) * Math.Log(0.5))
- If F = Fcut Then GAIN(i) = 0.5
- If F > Fcut Then GAIN(i) = Math.Exp(((F / Fcut) ^ order) * Math.Log(0.5))
- PHASE(i) = 2 * Math.PI * (MID * i / N) 'take FIR delay in account for the phase

The "order = 2" instruction at the beginning is of importance. You only get a true Gauss function if specifying 2 as exponent. I suggest you pay a visit to Wikipedia about Gauss and the Normal Distribution.

Better not say a "Gauss order". Better say a "Gauss exponent". I'll change the name of the selection box app.

Thus at this stage we know that a) the Gauss idea here is not about the time-domain impulse response, b) the exponent parameter has nothing to do with a filter order or decibels per octave or decade, c) the exponent parameter is equal to 2 when applying a "true" bell-shaped (Gauss) curve as target lowpass amplitude.

What's so special about specifying a true bell-shaped (Gauss) curve as target lowpass amplitude?

See for yourself running iDFT XO CGn. Looking at the lowpass curve, it seems that we get a very high order Bessel, perhaps an infinite order Bessel. This is substantiated by the fact that the complementary highpass is a kind of 2nd-order. This is figure 1.

We thus know that for a given FIR length (here, 31), using the Gauss approach, we get a lowpass exhibiting an impressive, maximal slope. Indeed, the lowpass is more selective than when relying on the traditional "Bessel order N" approach like proposed in the "iDFT XO" app. All this without the slightest preshoot, overshoot or ringing in time domain.

The highpass remains a 2nd-order, unfortunately this is the Bessel / Gauss Achille's heel.

Now let's investigate when specifying an exponent greater than 2. This is figure 2. The exponent is now equal to 3.3. The highpass slope improves. At the expense of some time domain preshoot and ringing. Still looks very decent.

All this with "rectangular" windowing, aka no windowing at all.

Worth trying, isn't?

steph_tsf 19th August 2012 01:12 PM

1 Attachment(s)
slightly revised iDFT XO CGn app

"order" replaced by "exponent"

steph_tsf 19th August 2012 02:19 PM

3 Attachment(s)
An example running iDFT XO CSRn

XO for Crossover
C for Complementary
S for Symmetric
Rn for Ratiometric any order

"Symmetric" is the new feature.
The lowpass and highpass now exhibit the same shapes and slopes.
Don't know if this helps delivering good sound.
Anyway, it looks nice on paper.

The attached .jpg sketch illustrates the symmetry principle and the design constraints that we need to introduce when specifying the target lowpass Bode plot.
From DC to Fc, we draw a said-to-be arbitrary lowpass attenuation curve. The curve segment starts at DC with a 1.0 amplitude and end at Fc with a 0.5 amplitude. This is segment 1 in blue.
Let's now apply the lowpass-highpass symmetry. We thus know what shape the highpass will exhibit between Fc and Finfinite. This is segment 2 in red.
We also know that our crossover is complementary. This means that, knowing segment 2 in red (highpass), we know how much the lowpass must deliver for ensuring highpass + lowpass = unity between Fc and Finfinite. See dy1 and dy2 in red. We thus obtain segment 3 in dashed blue.
Let's use the same logic, starting with segment 1 (lowpass between DC and Fc), for determining how much the highpass must deliver for ensuring lowpass + highpass = unity between DC and Fc. See dy1 and dy2 in blue. We thus obtain segment 4 in dashed red.
The conclusion is that the said-to-be arbitrary lowpass attenuation segment between DC and Fc needs to be replicated using symmetry rules. On a Bode plot using linear Y axis and log X axis, this becomes evident. See the .jpg sketch. The (Fc, 0.5) points needs to act as central symmetry centre.

For designing Complementary Symmetric crossovers, we only need to scratch our heads, finding some simple and elegant mathematical function obeying such symmetry rule when graphed using linear Y axis and log X axis.

An easy one is:

order = 3
For i = 0 To N
- F = FS * (i / N)
- If F < Fcut Then GAIN(i) = 1 - (((F / Fcut) ^ order) / 2.0)
- If F = Fcut Then GAIN(i) = 0.5
- If F > Fcut Then GAIN(i) = (((Fcut / F) ^ order) / 2.0)
- PHASE(i) = 2 * Math.PI * (MID * i / N) 'take FIR delay in account for the phase

The order can be any value, including non-integer values.

This time we selected a 51-tap FIR.
Crossover frequency still 3,800 Hz.

I selected a 3rd-order for guaranteeing a solid highpass function to the tweeter. As most tweeters exhibit a natural 2nd-order acoustic highpass, a bulletproof practice is to ask for an acoustic 3rd-order highpass. This way, the tweeter will remain protected against low frequency content. The magnetic circuit won't need to endure intense low frequency content. Sweet and precise highs guaranteed, even at high listening volume, using virtually any tweeter, including most miniature neodyme ones.

Selecting a higher order like 4 will provide an even better protection to the tweeter, at the expense of more preshoot and ringing.

Such 3rd-order Complementary Symmetric XO is a simple and solid design, even using fragile tweeters.

ChrisPa 19th August 2012 11:39 PM

Thank you
A lot to digest. Very helpful at letting me understand the application of fft to dsp

steph_tsf 20th August 2012 05:01 AM


Originally Posted by ChrisPa (
Thank you. Very helpful at letting me understand the application of fft to dsp

Basically this is all about the inverse dft (iDFT), not fft. The fft is only used for graphing the resulting amplitude curves.

mixtricks 19th October 2012 08:36 PM

Bonjour Stťphane,

Many thanks for sharing this with us.

Today I succesfully loaded a set of coŽfficiŽnts into my digital loudspeaker management system, used to separate low from high at 2800Hz on my studio monitors. It runs at 96KHz and uses 121 taps.

Those monitors are using a d'Apollito config, and I'd like to try and lowpass one of the midwoofers at eg 500Hz to avoid path length differences causing comb filtering in the midrange. It'd be interesting to see if this makes an audible improvement...

Is there a way I can calculate coŽfficiŽnts for a LPF @ 500Hz and somehow "merge" them with the coŽfficiŽnts for the HPF at 2K8? Can sets of coŽfficiŽnts be combined somehow?

Thanks again, I find the new linear phase crossover to result in a much more forward sounding vocal range, compared to traditional 2nd- or 4th order Linkwitz-Riley crossover.

Best Regards,


All times are GMT. The time now is 06:45 PM.

Search Engine Optimisation provided by DragonByte SEO (Pro) - vBulletin Mods & Addons Copyright © 2018 DragonByte Technologies Ltd.
Resources saved on this page: MySQL 18.75%
vBulletin Optimisation provided by vB Optimise (Pro) - vBulletin Mods & Addons Copyright © 2018 DragonByte Technologies Ltd.
Copyright ©1999-2018 diyAudio