Tag Archives: dsp

FIR filtering on the Raspberry Pi

hbdigi-proto-raspberry

A HiFiBerry user asked, if it would be possible to use BruteFIR for room equalization with the DAC. I was pretty sure that BruteFIR only runs on Intel CPUs. Looks like I was wrong. It seems, that BruteFIR also runs on the Raspberry Pi. Alternatively JConvolver also implements FIR filtering on the Raspberry. One commenter noted, that he has a setup running BruteFIR with 32k taps and 50% CPU load on the Raspberry. Wow! This is something we have to look into. Using the HiFiBerry Digi with an additional SPDIF input would allow to use the Raspberry Pi as a flexible room-equalization module.

Has anybody implemented a setup like this already? Let us know!

Comparisson IIR and FIR filters

There are lots of discussion in the DIY loudspeaker community, if digital loudspeaker crossover filters should be designed using IIR (infinite impulse response) or FIR (finite impulse response) filters. As IIR-capable DSPs are usually cheaper, many people use them.

This short article should give some information about advantages and disadvantages of both filter types.

Comparison of IIR and FIR filters

IIR FIR
 Feedback  yes  no
 Latency  low  high
 Processing complexity  low  high
 Comparable to analog circuits  yes  no
 Linear phase filtering  no  yes

One argument often used pro FIR and contra IIR filters is the phase response. It is possible, to design FIR filters, that change the frequency response, but not the phase response – so-called linear phase filters. However, have a look at real circuits and even a loudspeaker. No real circuit with capacitors or inductors used for filtering is a linear-phase system. Also a loudspeaker chassis changes its phase response depending on the frequency. Even in high-end speakers, passive LC-crossovers introduce phase shifts. It seems, that a changing phase response is not the worst thing in the world.

There are two major disadvantages of FIR filters: the need a lot of processing power and they introduce a longer delay than IIR filters. Depending on the hardware used, the first issue might not be a disadvantage. But the delay can be a problem in many use cases.



Are FIR filters bad? No, but you should understand the differences of IIR and FIR filters and then decide what kind of filtering you need. For loudspeaker crossovers, IIR filters often work well – as the old school passive filters did before.

References

HiFiBerry DSP – processing power

Raspberry Pi and HiFiBerry DSP Light

While we’re working on the DSP software, we had a closer look at the performance of the used ADAU1701. At 48kHz Sample rate, this DSP can process 1024 command per sample. With a normal CPU, that would not be a lot. But what about this DSP? Let’s have a look: a single-precision biquad filter needs 6 commands, a double-precision filter 10 commands. That means with single precision filters we would be able to use more than 150 biquad filters and even with double-precision filters there are about 100 filters possible. For a simple loudspeaker crossover, that’s a lot.

But what about FIR filtering? FIR filters are quite resource-intense. Their computing complexity is linearly dependent on the number of filter taps. The ADAU1701 can process one tap per command. That means you could process FIR filters up to about 1000 taps length on this DSP. This might not be enough for FIR based room correction, but enough for a FIR-based crossover for a normal 2 way speaker. We will see, if we can implement this.

Mixing two signals in SigmaStudio

If you use SigmaStudio to create filter networks, you might look for a simple mixer to add two signals. The NxM mixer seems to be the tool for this. However, if you set all parameters directly at the DSP, there is a way that’s even less resource-intense: the switch. Have a look at the following configuration:

sigmastudio_mixers

There is a mono switch and a mono mixer. Isn’t the switch designed to only switch between inputs and not to mix them? You could think so. But internally, it is easier to implement a switch as a mixer than as a real switch. Let’s check the parameter definitions of these blocks:

/* Module mx3 - Mono Switch Nx1*/
#define MOD_MX3_COUNT 2
#define MOD_MX3_DEVICE "IC1"
#define MOD_MX3_ALG0_STAGE0_MONOSWITCHNOSLEW_ADDR 4
#define MOD_MX3_ALG0_STAGE0_MONOSWITCHNOSLEW_FIXPT 0x00000000
#define MOD_MX3_ALG0_STAGE0_MONOSWITCHNOSLEW_VALUE SIGMASTUDIOTYPE_FIXPOINT_CONVERT(0)
#define MOD_MX3_ALG0_STAGE0_MONOSWITCHNOSLEW_TYPE SIGMASTUDIOTYPE_FIXPOINT
#define MOD_MX3_ALG0_STAGE1_MONOSWITCHNOSLEW_ADDR 5
#define MOD_MX3_ALG0_STAGE1_MONOSWITCHNOSLEW_FIXPT 0x00800000
#define MOD_MX3_ALG0_STAGE1_MONOSWITCHNOSLEW_VALUE SIGMASTUDIOTYPE_FIXPOINT_CONVERT(1)
#define MOD_MX3_ALG0_STAGE1_MONOSWITCHNOSLEW_TYPE SIGMASTUDIOTYPE_FIXPOINT

/* Module mx4 - NxM Mixer*/
#define MOD_MX4_COUNT 4
#define MOD_MX4_DEVICE "IC1"
#define MOD_MX4_ALG0_NXNMIXER1940ALG100_ADDR 6
#define MOD_MX4_ALG0_NXNMIXER1940ALG100_FIXPT 0x00800000
#define MOD_MX4_ALG0_NXNMIXER1940ALG100_VALUE SIGMASTUDIOTYPE_FIXPOINT_CONVERT(1)
#define MOD_MX4_ALG0_NXNMIXER1940ALG100_TYPE SIGMASTUDIOTYPE_FIXPOINT
#define MOD_MX4_ALG0_NXNMIXER1940ALG100_ADDR 6
#define MOD_MX4_ALG0_NXNMIXER1940ALG100_FIXPT 0x00800000
#define MOD_MX4_ALG0_NXNMIXER1940ALG100_VALUE SIGMASTUDIOTYPE_FIXPOINT_CONVERT(1)
#define MOD_MX4_ALG0_NXNMIXER1940ALG100_TYPE SIGMASTUDIOTYPE_FIXPOINT
#define MOD_MX4_ALG0_NXNMIXER1940ALG101_ADDR 7
#define MOD_MX4_ALG0_NXNMIXER1940ALG101_FIXPT 0x00000000
#define MOD_MX4_ALG0_NXNMIXER1940ALG101_VALUE SIGMASTUDIOTYPE_FIXPOINT_CONVERT(1E-10)
#define MOD_MX4_ALG0_NXNMIXER1940ALG101_TYPE SIGMASTUDIOTYPE_FIXPOINT
#define MOD_MX4_ALG0_NXNMIXER1940ALG101_ADDR 7
#define MOD_MX4_ALG0_NXNMIXER1940ALG101_FIXPT 0x00000000
#define MOD_MX4_ALG0_NXNMIXER1940ALG101_VALUE SIGMASTUDIOTYPE_FIXPOINT_CONVERT(1E-10)
#define MOD_MX4_ALG0_NXNMIXER1940ALG101_TYPE SIGMASTUDIOTYPE_FIXPOINT

The Mono switch has two fixpoint parameters. Why does it need a fixpoint parameter? The easiest implementation for a switch would be a parameter that holds the active input. But on a DSP that’s not the most effective way to implement a switch. Therefore Analog Devices has decided to implement a switch as

output = input1 x param1 + input2 x param2

The way as SigmaStudio used this switch, one parameter is 1 and the other is 0. But they do not have to be 0 or 1. They can use any value between -16 and 16.  Negative numbers? Yes, even negative parameters are possible. Using a negative value will invert the signal. This gives us nice possibilities to mix two signals in-phase and even out-of-phase.

Another interesting fact: The implementation of he switch is less resource-intense than the mixer. The switch needs only 2 addresses in the parameter RAM instead of the 4 that the mixer needs. Also the code is one instruction shorter. That’s not much, but if your program is using almost all resources of the DSP, it might help to free up some instructions.

P.S. The trick using negative numbers to invert a signal works with many DSP blocks created by SigmaStudio.

A simple XML model for filter networks

For the HiFiBerry DSP project we need a compact, but flexible configuration of a network of filters. Therefore I created an XML configuration that models the different parts of the filter network.

<network samplerate="48000">
<input name="input1"/>
<biquad name="bq1" input="input1" type="allpass" frequency="200" q="1" />
<biquad name="bq2" input="bq1" type="lowpass" frequency="1000" q="0.7" />
<biquad name="bq3" input="bq2" type="highpass" frequency="100" q="0.7" />
<biquad name="bq4" input="bq3" type="notch" frequency="400" q=".1" />
<biquad name="bq5" input="bq4" type="peaking_eq" frequency="700" q="4" dbgain="3" />
<output name="out1" input="bq5" />
</network>

Here you see a simple DSP configuration with one input and one output and 5 biquad filters processing the data. Today, no other filters are supported, but I will add other types soon. I plan to also support FIR filters.

Using our software you can now calculate the frequency response of this filter chain:

out1
  Freq       Mag   Phase
    10  -40.27db  151.26°
    15  -33.54db  137.31°
    20  -28.95db  123.77°
    30  -22.92db   98.07°
    40  -19.11db   73.96°
    50  -16.52db   51.02°
    75  -13.06db   -3.32°
   100  -12.19db  -54.31°
   150  -13.86db -148.08°
   200  -16.87db -232.90°
   300  -24.77db -340.74°
   400 -298.86db -480.46°
   500  -26.91db -242.30°
   750  -16.50db -310.78°
  1000  -16.52db -346.21°
  1500  -17.48db -391.49°
  2000  -19.60db  -58.47°
  3000  -23.71db  -89.23°
  4000  -27.23db -107.29°
  5000  -30.26db -119.52°
  7500  -36.41db -137.98°
 10000  -41.23db -148.30°
 15000  -48.77db -159.52°
 20000  -54.92db -165.64°

Now let’s do a nice graph from it using Matplotlib.
frequency-response-demo
Note, this is not the filter that we used before, because the response of that filter is really nasty – it was just for demonstration of the different biquad filters.

Now, we only have to merge this with our DSP upload software with this code and we already have a simple command line tool to upload and modify filters on the HiFiBerry DSP.

First measurements of our HiFiBerry DSP Light

Today we had a look at the noise and distortions of the HiFiBerry DSP light. They look promising. Noise is not a problem at all – which is not the case for every DSP that is available on the market. The distortion figures are a bit above the typical distortions from the datasheet, but still at an acceptable level below 0.01%. The low noise figures show, that the PCB design works well with its clear separation of the analog and the digital part of the circuit.

thd+n-hifiberry-dspNote that these figures are measured with a very cheap power supply and the Raspberry Pi connected to the DSP and running. That means all major noise sources, except the Ethernet port, are already included in this measurement.