Skip to main content
replaced http://dsp.stackexchange.com/ with https://dsp.stackexchange.com/
Source Link

So, in your comments to my previous answerprevious answer you added a different specification; summing it up here.

So, in your comments to my previous answer you added a different specification; summing it up here.

So, in your comments to my previous answer you added a different specification; summing it up here.

added 289 characters in body
Source Link
Marcus Müller
  • 32.5k
  • 4
  • 35
  • 62

However, let's just take the same 64 coefficient IIR, as the FIR hasn't changed length that much. And Olli's excellent answer shows that we can most likely link FIR and IIR length.

Now, the takeaway was that you'd need to be extremely clever to implement the IIR with 64bit floats; the Cortex-M4 only has hardware support for 32bit, as far as I know; that's making things a lot more complicated.

Recommendation: Cascade $\frac12$-band (Nyquist) FIRs with an IIR.

Now, with a microcontroller as target, there's no tricks such as multiplexing high-rate multiplier hardware units as in FPGAs; there's one FPU, and only a little RAM, so you'll have to write your filter with these constraints in mind:

A halfband Nyquist-M filter has only half of its taps + 1 $\ne 0$, and it can be designed symmetrical, so that you'd only need roughly one quarter of the taps of a "normal" FIR. Since RAM and fast ROM are really sparse on Cortex-M processors, that is something that you'll have to exploit.

I don't know which actual microcontroller you use, but chances are that whoever took ARM's Cortex-M4F core and used it in his silicone didn't add a memory cache controller to its RAM interface (a Cortex-M4 is a microcontroller, after all), so we can't optimize towards "cacheability", but would still much rather work on blocks of samples than on individual samples, reducing the control flow overhead (grossly oversimplifying: "do the same operation on the next 256 values, then do this operation on the resulting 128 values" is less CPU-intense than "multiply this value with a, that value with b, add that up and save it in the first output value; go back to beginning (do that 128 times)"), you'd instruct your ADC/DMA controller to give you as many consecutive samples as possible in a fixed region of RAM before triggering a CPU interrupt to process these.


Also note that, if you're using the ADC of your microcontroller, many manufacturers have an averaging filter built into the ADC controller to allow for sample-rate reduction before the samples even reach RAM.

Using the same halfband decimator sequentially first on the input rate, then on the saved half-input-rate samples, and then on the saved quarter-input-rate samples will make for a relatively efficient $2^n$ decimator, but your $n$ will be very limited by RAM (luckily, you can re-use the input sample storage space of your last stage as output of your current) and by the fact that for your 64,000 decimation, you'd need $n=15$ stages; you'd need to start pipelining things a lot so that you don't have to process the full 64,000 samples input buffer at once (which you probably won't be done with before the next bunch of samples comes in and overwrites your input...).

So, again, combine halfband FIRs with a good IIR, and come up with a clever scheduling scheme so that your data marshalling doesn't interfere with your algorithms.

Allow me one general note: When going for a decimation of 64,000, the best approach might really be an analog one; there's awesome analog filter architectures and ready-made ICs; for example, Maxim sells switched capacitance elliptic filters, which you'd have to chain with a simple one- or two-stage RC filter before connecting it to your ADC's input, and you could then really run at much lower sampling rates/ignore a lot of samples; these ICs can be configured for really low cutoff frequencies!

However, let's just take the same 64 coefficient IIR, as the FIR hasn't changed length that much.

However, let's just take the same 64 coefficient IIR, as the FIR hasn't changed length that much. And Olli's excellent answer shows that we can most likely link FIR and IIR length.

Now, the takeaway was that you'd need to be extremely clever to implement the IIR with 64bit floats; the Cortex-M4 only has hardware support for 32bit, as far as I know; that's making things a lot more complicated.

Recommendation: Cascade $\frac12$-band (Nyquist) FIRs with an IIR.

Now, with a microcontroller as target, there's no tricks such as multiplexing high-rate multiplier hardware units as in FPGAs; there's one FPU, and only a little RAM, so you'll have to write your filter with these constraints in mind:

A halfband Nyquist-M filter has only half of its taps + 1 $\ne 0$, and it can be designed symmetrical, so that you'd only need roughly one quarter of the taps of a "normal" FIR. Since RAM and fast ROM are really sparse on Cortex-M processors, that is something that you'll have to exploit.

I don't know which actual microcontroller you use, but chances are that whoever took ARM's Cortex-M4F core and used it in his silicone didn't add a memory cache controller to its RAM interface (a Cortex-M4 is a microcontroller, after all), so we can't optimize towards "cacheability", but would still much rather work on blocks of samples than on individual samples, reducing the control flow overhead (grossly oversimplifying: "do the same operation on the next 256 values, then do this operation on the resulting 128 values" is less CPU-intense than "multiply this value with a, that value with b, add that up and save it in the first output value; go back to beginning (do that 128 times)"), you'd instruct your ADC/DMA controller to give you as many consecutive samples as possible in a fixed region of RAM before triggering a CPU interrupt to process these.


Also note that, if you're using the ADC of your microcontroller, many manufacturers have an averaging filter built into the ADC controller to allow for sample-rate reduction before the samples even reach RAM.

Using the same halfband decimator sequentially first on the input rate, then on the saved half-input-rate samples, and then on the saved quarter-input-rate samples will make for a relatively efficient $2^n$ decimator, but your $n$ will be very limited by RAM (luckily, you can re-use the input sample storage space of your last stage as output of your current) and by the fact that for your 64,000 decimation, you'd need $n=15$ stages; you'd need to start pipelining things a lot so that you don't have to process the full 64,000 samples input buffer at once (which you probably won't be done with before the next bunch of samples comes in and overwrites your input...).

So, again, combine halfband FIRs with a good IIR, and come up with a clever scheduling scheme so that your data marshalling doesn't interfere with your algorithms.

Allow me one general note: When going for a decimation of 64,000, the best approach might really be an analog one; there's awesome analog filter architectures and ready-made ICs; for example, Maxim sells switched capacitance elliptic filters, which you'd have to chain with a simple one- or two-stage RC filter before connecting it to your ADC's input, and you could then really run at much lower sampling rates/ignore a lot of samples; these ICs can be configured for really low cutoff frequencies!

added 289 characters in body
Source Link
Marcus Müller
  • 32.5k
  • 4
  • 35
  • 62

So, in your comments to my previous answer you added a different specification; summing it up here.

Note that I assume that you'll take the cutoff frequency you specify as the sample rate coming out of your decimating filter.

Now, we first need to think about attenuation:

with -40dB you probably meant that "the total power of all the noise that gets aliased back into my passband should be attenuated by 40 dB". Now, let's act if that noise had a constant PSD, so in every frequency band there was an equal amount of noise. We're decimating by $d$ to a bandwidth $f_2$. That means that there are $d-1\approx d$ noise-containing bandwidths, each $f_2$ wide, that get aliased onto your passband. Hence, your stopband attenuation should be $d\left[\text{dB}\right]+ 40\text{ dB}$.


> $$ \begin{align*} f_s &= 6.4 \cdot 10^4 \text{ Hz}\\[1.2em] f_1 &= 5 \cdot 10^{-2} \text{ Hz}\\ f_2 &= 1 \text{ Hz}\\[1.2em] \Delta f &= f_2 - f_1\\ &= 9.5 \cdot 10^{-1} \text{ Hz}\\[1.2em] d &= \frac{f_s}{f_2}\\ &= 6.4\cdot10^4\\[1.2em] \delta_1 &= -40\text{ dB}\\ &= 10^{-4}\\ \delta_2 &= \delta_1\cdot d\\ &= 10^{-4}\cdot \frac{1}{6.4\cdot10^4}\\ &= 1.563\cdot 10^-9\\ &\approx -88dB\\[1.2em] \frac{f_s}{\Delta f} &=\frac{6.4}{9.5}\,10^5\\ &\approx 6.737\cdot 10^4 \end{align*} $$ > Working on an ARM-Cortex M4F

Notice that this kind of interpreting your attenuation requirements makes the attenuation even stronger than before.


FIR

Minimal phase equiripple filter $$ \begin{align*} N_e' &\approx \frac 16 \log_{10}\left(\frac{1}{10\delta_1\delta_2^2}\right)\frac{f_s}{\Delta f}\\ &\approx \frac 16 \log_{10}\left(\frac{1}{10\cdot10^{-4}(1.563\cdot10^{-9})^2}\right)\cdot6.737\cdot10^4\\ &\approx \frac 16 \log_{10}\left(\frac{1}{2.441\cdot10^{-21}}\right)\cdot6.737\cdot10^4\\ &\approx \frac 16 20.61 \cdot6.737\cdot10^4\\ &\approx 2.314\cdot10^8 \end{align*}$$

So, no, not much luck reducing the filter length by increasing transition width whilst also increasing attenuation demands.

Considering a polyphase implementation, where only $\frac 1d$ coefficients would be used per input sample, $d$ being the decimation:

$$\begin{align*} N_{e,PP}' &= \frac{N_e'}{d}\\ &\approx 3617 \end{align*} $$

3617 Floating-Point Multiply-Accumulates at the sampling rate, which happens to be $\frac1d\text{ Hz}$ means your CPU would need to do 231.4 MFlop/s (a floating point operation being an Multiplication and Accumulation combined); that's certainly in the possible range for Desktop CPUs, but definitely impossible with the Cortex M4 – you'd have to store all the coefficients (minimal phase FIR isn't symmetrical¹), and at a 32bit floating point precision, that'll be more than 882 MB of coefficient storage; your device probably won't have more than 256kB of space for that.


**IIR**

Now, in my last answer I used $\frac {f_1}{f_s}$ with $f_1 =4.99\text{ Hz}$; this time $f_1 = 0.05$. In this situation, Bellanger's approximation formula must fall flat.

However, let's just take the same 64 coefficient IIR, as the FIR hasn't changed length that much.


¹ by the way, often you'd go for "the best FIR I can do with this architecture" on a general purpose, e.g. PC, CPU. In that case, a good rule of thumb is to go for a linear phase filter with a little less than twice as many coefficients as fit into a CPU cache line. Linear filters are symmetrical, so you can fit your whole filter into CPU cache at once, and fetching a value from RAM rather than cache typically takes $approx 100$ times the amount of time you'd spent calculating one multiply-accumulate (at least for naively programmed x86s; using hand-optimized SIMD, e.g. SSE4, you can typically increase multiplication speed, also).

So, in your comments to my previous answer you added a different specification; summing it up here.

Note that I assume that you'll take the cutoff frequency you specify as the sample rate coming out of your decimating filter.

Now, we first need to think about attenuation:

with -40dB you probably meant that "the total power of all the noise that gets aliased back into my passband should be attenuated by 40 dB". Now, let's act if that noise had a constant PSD, so in every frequency band there was an equal amount of noise. We're decimating by $d$ to a bandwidth $f_2$. That means that there are $d-1\approx d$ noise-containing bandwidths, each $f_2$ wide, that get aliased onto your passband. Hence, your stopband attenuation should be $d\left[\text{dB}\right]+ 40\text{ dB}$.


> $$ \begin{align*} f_s &= 6.4 \cdot 10^4 \text{ Hz}\\[1.2em] f_1 &= 5 \cdot 10^{-2} \text{ Hz}\\ f_2 &= 1 \text{ Hz}\\[1.2em] \Delta f &= f_2 - f_1\\ &= 9.5 \cdot 10^{-1} \text{ Hz}\\[1.2em] d &= \frac{f_s}{f_2}\\ &= 6.4\cdot10^4\\[1.2em] \delta_1 &= -40\text{ dB}\\ &= 10^{-4}\\ \delta_2 &= \delta_1\cdot d\\ &= 10^{-4}\cdot \frac{1}{6.4\cdot10^4}\\ &= 1.563\cdot 10^-9\\ &\approx -88dB\\[1.2em] \frac{f_s}{\Delta f} &=\frac{6.4}{9.5}\,10^5\\ &\approx 6.737\cdot 10^4 \end{align*} $$ > Working on an ARM-Cortex M4F

Notice that this kind of interpreting your attenuation requirements makes the attenuation even stronger than before.


FIR

Minimal phase equiripple filter $$ \begin{align*} N_e' &\approx \frac 16 \log_{10}\left(\frac{1}{10\delta_1\delta_2^2}\right)\frac{f_s}{\Delta f}\\ &\approx \frac 16 \log_{10}\left(\frac{1}{10\cdot10^{-4}(1.563\cdot10^{-9})^2}\right)\cdot6.737\cdot10^4\\ &\approx \frac 16 \log_{10}\left(\frac{1}{2.441\cdot10^{-21}}\right)\cdot6.737\cdot10^4\\ &\approx \frac 16 20.61 \cdot6.737\cdot10^4\\ &\approx 2.314\cdot10^8 \end{align*}$$

So, no, not much luck reducing the filter length by increasing transition width whilst also increasing attenuation demands.

Considering a polyphase implementation, where only $\frac 1d$ coefficients would be used per input sample, $d$ being the decimation:

$$\begin{align*} N_{e,PP}' &= \frac{N_e'}{d}\\ &\approx 3617 \end{align*} $$

3617 Floating-Point Multiply-Accumulates at the sampling rate, which happens to be $\frac1d\text{ Hz}$ means your CPU would need to do 231.4 MFlop/s (a floating point operation being an Multiplication and Accumulation combined); that's certainly in the possible range for Desktop CPUs, but definitely impossible with the Cortex M4 – you'd have to store all the coefficients (minimal phase FIR isn't symmetrical¹), and at a 32bit floating point precision, that'll be more than 882 MB of coefficient storage; your device probably won't have more than 256kB of space for that.


¹ by the way, often you'd go for "the best FIR I can do with this architecture" on a general purpose, e.g. PC, CPU. In that case, a good rule of thumb is to go for a linear phase filter with a little less than twice as many coefficients as fit into a CPU cache line. Linear filters are symmetrical, so you can fit your whole filter into CPU cache at once, and fetching a value from RAM rather than cache typically takes $approx 100$ times the amount of time you'd spent calculating one multiply-accumulate (at least for naively programmed x86s; using hand-optimized SIMD, e.g. SSE4, you can typically increase multiplication speed, also).

So, in your comments to my previous answer you added a different specification; summing it up here.

Note that I assume that you'll take the cutoff frequency you specify as the sample rate coming out of your decimating filter.

Now, we first need to think about attenuation:

with -40dB you probably meant that "the total power of all the noise that gets aliased back into my passband should be attenuated by 40 dB". Now, let's act if that noise had a constant PSD, so in every frequency band there was an equal amount of noise. We're decimating by $d$ to a bandwidth $f_2$. That means that there are $d-1\approx d$ noise-containing bandwidths, each $f_2$ wide, that get aliased onto your passband. Hence, your stopband attenuation should be $d\left[\text{dB}\right]+ 40\text{ dB}$.


> $$ \begin{align*} f_s &= 6.4 \cdot 10^4 \text{ Hz}\\[1.2em] f_1 &= 5 \cdot 10^{-2} \text{ Hz}\\ f_2 &= 1 \text{ Hz}\\[1.2em] \Delta f &= f_2 - f_1\\ &= 9.5 \cdot 10^{-1} \text{ Hz}\\[1.2em] d &= \frac{f_s}{f_2}\\ &= 6.4\cdot10^4\\[1.2em] \delta_1 &= -40\text{ dB}\\ &= 10^{-4}\\ \delta_2 &= \delta_1\cdot d\\ &= 10^{-4}\cdot \frac{1}{6.4\cdot10^4}\\ &= 1.563\cdot 10^-9\\ &\approx -88dB\\[1.2em] \frac{f_s}{\Delta f} &=\frac{6.4}{9.5}\,10^5\\ &\approx 6.737\cdot 10^4 \end{align*} $$ > Working on an ARM-Cortex M4F

Notice that this kind of interpreting your attenuation requirements makes the attenuation even stronger than before.


FIR

Minimal phase equiripple filter $$ \begin{align*} N_e' &\approx \frac 16 \log_{10}\left(\frac{1}{10\delta_1\delta_2^2}\right)\frac{f_s}{\Delta f}\\ &\approx \frac 16 \log_{10}\left(\frac{1}{10\cdot10^{-4}(1.563\cdot10^{-9})^2}\right)\cdot6.737\cdot10^4\\ &\approx \frac 16 \log_{10}\left(\frac{1}{2.441\cdot10^{-21}}\right)\cdot6.737\cdot10^4\\ &\approx \frac 16 20.61 \cdot6.737\cdot10^4\\ &\approx 2.314\cdot10^8 \end{align*}$$

So, no, not much luck reducing the filter length by increasing transition width whilst also increasing attenuation demands.

Considering a polyphase implementation, where only $\frac 1d$ coefficients would be used per input sample, $d$ being the decimation:

$$\begin{align*} N_{e,PP}' &= \frac{N_e'}{d}\\ &\approx 3617 \end{align*} $$

3617 Floating-Point Multiply-Accumulates at the sampling rate, which happens to be $\frac1d\text{ Hz}$ means your CPU would need to do 231.4 MFlop/s (a floating point operation being an Multiplication and Accumulation combined); that's certainly in the possible range for Desktop CPUs, but definitely impossible with the Cortex M4 – you'd have to store all the coefficients (minimal phase FIR isn't symmetrical¹), and at a 32bit floating point precision, that'll be more than 882 MB of coefficient storage; your device probably won't have more than 256kB of space for that.


**IIR**

Now, in my last answer I used $\frac {f_1}{f_s}$ with $f_1 =4.99\text{ Hz}$; this time $f_1 = 0.05$. In this situation, Bellanger's approximation formula must fall flat.

However, let's just take the same 64 coefficient IIR, as the FIR hasn't changed length that much.


¹ by the way, often you'd go for "the best FIR I can do with this architecture" on a general purpose, e.g. PC, CPU. In that case, a good rule of thumb is to go for a linear phase filter with a little less than twice as many coefficients as fit into a CPU cache line. Linear filters are symmetrical, so you can fit your whole filter into CPU cache at once, and fetching a value from RAM rather than cache typically takes $approx 100$ times the amount of time you'd spent calculating one multiply-accumulate (at least for naively programmed x86s; using hand-optimized SIMD, e.g. SSE4, you can typically increase multiplication speed, also).
Source Link
Marcus Müller
  • 32.5k
  • 4
  • 35
  • 62
Loading