ar1st0crat / NWaves

.NET DSP library with a lot of audio processing functions
MIT License
453 stars 71 forks source link

DiscreteSignal.Samples contain more samples than the original signal #87

Closed MucAcoustics closed 6 months ago

MucAcoustics commented 6 months ago

I made a DiscreteSignal variable from a float[] vector containing 5120 samples:

DiscreteSignal p = new DiscreteSignal(samplingFrequency, rawsamples, true);

The sampling frequency is 51200 1/s. Applying an iir Filter gives more samples at the output than the raw vector contains:

DiscreteSignal pOut = MyFilter.ApplyTo(p, FilteringMethod.OverlapSave);

where pOut has 5631 samples. Apparently, the extra samples chunk is related to the FilteringMethod setting. Using the FilteringMethod.DifferenceEquation pOut does not show the effect. pOut has 5120 samples then. However, this filtering method gives a garbled output signal. If I feed the filter with a pure 1 kHz tone, a low frequent signal interferes with the 1 kHz signal. The interfering signal seems to come from an unstable condition because the amplitude increases with time. To avoid this unstable condition I use the OverlapSave filtering method. But where do the extra samples come from then? What could the solution be to avoid them? NWaves_filtering_clean_but_extended_output_signal NWaves_filtering_garbled_output_signal

ar1st0crat commented 6 months ago

Hi, ApplyTo() methods were initially designed to carry out the convolution, so the output length is signal_length + filter_size - 1 (although in case of diff equation the length is indeed identical to the input length).

First of all, you say you use IIR filter. It means that the impulse response (the filter kernel) has infinite length. For classic OverlapSave implementation it needs to be finite. In NWaves code the impulse response is just truncated at some particular size, i.e. the result can be close to what you expect, but still not precisely correct. So, did you try just auto mode (i.e. not a difference equation)? I.e. DiscreteSignal pOut = MyFilter.ApplyTo(p); or DiscreteSignal pOut = MyFilter.FilterOnline(p);?

If both still produce problems, can you try to use IirFilter64 class (with double precision and call the same methods above?


If you stick with OverlapSave then there are possible solutions (I assume you'll prefer the first one, but maybe 2 and 3 are also ok):

1) use OlsBlockConvolver and FilterOnline() method that processes the signal sample in a loop (just like in online scenario):

// not really correct because yours is IIR filter!
var length = 128; // we'll truncate impulse response by this length
var olsFilter = new OlsBlockConvolver(MyFilter.Tf.ImpulseResponse(length), 512);
var filtered = olsFilter.FilterOnline(signal);
// 512 is the FFT size, should be power of 2: 512, 1024, 2048, etc. (often it's ~4*filter_size)

2) simply ignore last filter_size - 1 samples

3) copy (if you don't care much about the memory): filteredSignal.First(signal.Length)

MucAcoustics commented 6 months ago

Lesson learnt! Thanks a lot for your hints. The IirFilter64 solution does the job. It runs MyFilter.ApplyTo(p), MyFilter now based on an IirFilter64 resp. FilterChain64, without any problems. Straightforward and stable. The default setting "Auto" for the FilterMethod is just as right. Great!