FIR filter 'filterN' method

I’m designing an adaptive FIR filter base class.

In the guts of all the current FIR filter types, there are filterN and
filterNdec methods that compute multiple outputs as a batch. These are
called in the ::work method of the calling signal processing block:

if (decimation() == 1)
d_fir->filterN (out, in, noutput_items);

else
d_fir->filterNdec (out, in, noutput_items, decimation());

As far as I can tell, in all the various types, these are implemented
identically as simple loops calling the ‘filter’ method to calculate
single outputs iteratively:


void
gr_fir_ccf_generic::filterN (gr_complex output[],
const gr_complex input[],
unsigned long n)
{
for (unsigned i = 0; i < n; i++)
output[i] = filter (&input[i]);
}

In an adaptive filter, the class needs to update the filter taps after
each output sample. So I’d like to call ‘filter’ directly in my own loop
in my ::work function, followed by a call to update_weights during the
same loop iteration.

Is there any reason not to do it this way? Since all the existing
filterN functions are implemented as this simple loop, can I just do the
same thing myself in my ::work function instead? Will there ever be
additional stuff implemented in filterN in some FIR class that won’t
ever get called because I’m bypassing it to do myself?

-Johnathan

On Mon, Jul 03, 2006 at 01:50:11PM -0700, Johnathan C. wrote:

void
each output sample. So I’d like to call ‘filter’ directly in my own loop
in my ::work function, followed by a call to update_weights during the
same loop iteration.

OK.

The filterN{,dec} function was defined to allow for possible
future optimization.

Is there any reason not to do it this way? Since all the existing
filterN functions are implemented as this simple loop, can I just do the
same thing myself in my ::work function instead? Will there ever be
additional stuff implemented in filterN in some FIR class that won’t
ever get called because I’m bypassing it to do myself?

Yes, we could be adding stuff in the future.

A bigger issue however, is that setting/adjusting the taps on the SIMD
versions is fairly expensive. If your filter is always adapting,
you’ll probably want to reimplement it in terms of the generic FIR
code, bypassing the SIMD speedups.

Eric

Eric B. wrote:

A bigger issue however, is that setting/adjusting the taps on the SIMD
versions is fairly expensive. If your filter is always adapting,
you’ll probably want to reimplement it in terms of the generic FIR
code, bypassing the SIMD speedups.

I realize now that changing the FIR taps each output sample will pretty
much wipe out the performance gains of the SIMD optimizations, at which
point it doesn’t make sense to go with any of the gr_fir_xxx functions.

Per our offline discussion, I’m going to implement my own FIR
calculation using regular multiplies and hope the compiler can optimize
things somewhat. I’ll be able to combine the FIR calculation, the error
calculation and weight updates in a nested loop, while they’re all still
(hopefully) hanging out in registers.

It does mean that I can’t do a generic “adaptive_fir” class that can be
subclassed and specialized into classes like cma_equalizer,
noise_reduction, etc. Instead each one will end up being unique. I
guess that’s the price you pay for speed.

-Johnathan, AE6HO

I suggest a block adaptive approach. Why won’t this work?

Bob

Johnathan C. wrote:

much wipe out the performance gains of the SIMD optimizations, at which
noise_reduction, etc. Instead each one will end up being unique. I


AMSAT VP Engineering. Member: ARRL, AMSAT-DL, TAPR, Packrats,
NJQRP/AMQRP, QRP ARCI, QCWA, FRC. ARRL SDR Wrk Grp Chairman
Time for a new motto, what should I choose?

Robert McGwier wrote:

I suggest a block adaptive approach. Why won’t this work?

Well, it could, I suppose. I’m just specifically interested in a
per-sample adaptive FIR function. Once I get that going I may look to
extend it with a block length per weight update.

-Johnathan, AE6HO

On Mon, Jul 03, 2006 at 09:55:39PM -0400, Robert McGwier wrote:

I suggest a block adaptive approach. Why won’t this work?

That would work if that’s what he wanted.
My understanding was that he wanted to adapt on every sample.

Johnathan C. wrote:

It does mean that I can’t do a generic “adaptive_fir” class that can be
subclassed and specialized into classes like cma_equalizer,
noise_reduction, etc. Instead each one will end up being unique. I
guess that’s the price you pay for speed.

Well, I’ve gone back to the original idea of a base class for an
adaptive fir filter with a derived class overriding the error and tap
update methods to create a particular type of adaptive filter. This has
been checked in.

The adaptive FIR class is complete but unoptimized. Instead of using an
existing gr_fir_xx class, it internally implements a generic dot product
for the FIR output calculation. It presently is only implemented for
_ccf signature but it would be possible to make it into a template.

I’ve created a constant modulus filter skeleton with null error and tap
update methods. The default taps start with 1.0 and the remainder are
zeros so the output is identical to the input.

I’ll be working on the CMA class tomorrow. Depending on speed it may
make sense to eliminate the base class, but I’m hoping not to have to.

-Johnathan, AE6HO