jgaeddert / liquid-dsp

digital signal processing library for software-defined radios
http://liquidsdr.org
MIT License
1.82k stars 426 forks source link

Resampler questionable results #339

Closed thezboe closed 9 months ago

thezboe commented 9 months ago

Attached is a modification of the resamp_crcf_noise_example.c example. Two noise sources are added with a notch in the middle, with a tone added slightly off center. I also added an input argument for the number of filter banks.

With a resampling rate and a cutoff frequency placed between the two noise sources and encompassing the tone, I get very unsatisfactory results from the resample block. The original signal is pretty much unrecognizable in the resampled signal no matter how many banks or taps I afford the resampler.

I've added a standalone firfilt block with the same number of taps as the resampler PFB, and the results before resampling look like it would result in a successful decimation without too much aliasing.

What am I missing? The resampler is configuring a kaiser window LPF, but it's obviously not doing anywhere near the same thing as the one I've designed with the same number of taps. If I need to precede the resampler with another LPF, then I lose out on the very benefits I thought the PFB was designed for.

The program below was run with "-r 0.1 -w 0.04 -s 140 -p 512 -m 8" to get the pictured output. The filter is designed to be 80% of the resample ratio. In this example, the stop band attenuation has to be very large (which I am okay with) in order for aliasing to be below the floor of the notch.

test.txt

mstsc_VpmwfCPyt5

Discussed in https://github.com/jgaeddert/liquid-dsp/discussions/338

jgaeddert commented 9 months ago

I am able to reproduce your results with those command-line options. I think those results make sense, actually; you're trying to design a filter with extremely low stop-band suppression (140 dB) but with very few coefficients (m=8). For the resampling rate you're asking for, this isn't really possible without having really really wide transition bands and thus allowing a lot of the noise signal to alias in.

If instead I run your program with a narrower filter bandwidth (commensurate of the bandwidth of the signals you are trying to suppress), less stop-band suppression (60 dB), and a longer filter (-m 20), I get much more reasonable results

./resamp_crcf_noise_example -r 0.1 -w 0.02 -s 60 -p 512 -m 20
image

Instead of using the resamp_crcf object, you can use the msresamp_crcf object which is almost a drop-in replacement, but performs a series of extremely efficient half-band resampling stages before running the arbitrary rate resampler. From a computation standpoint, this should be much faster, although that might not be your concern.

When I tried this, I'm getting results that I would expect are much closer to what you would want (albeit not as clean as above):

image

Attached is a slightly modified version of your program to use the multi-stage resampler.

resamp_crcf_noise_example.txt

thezboe commented 9 months ago

@jgaeddert I'm hoping this ticket won't reopen when I comment on it, because I think it's a discussion just about DSP and perhaps artifacts of using this library at the moment.

From my understanding, the performance of the filter in the PFB should be determined from the number of coefficients in the entire bank, not just the number in each leg, correct? In that case above, there are m*2*npfb=8k points, or even 20k points in your example, in the PFB and that's why I showed a separate LPF of the same number of coefficients.

The LPF doesn't show any images of the source signal that should be aliasing to such degree back into the passband. In my case, I would really like to see any images of any part of the signal to be very close to or below the level of the original signal, which is why I had picked such an enormous stop band attenuation (I was just trying to find the knob to turn which would give me better results).

I wish it was a bit easier to print out the resulting filter taps so we could visualize what that step is resulting in, it seems that my LPF is not representing what is happening in actuality. Further, I would expect that added coefficients in one form or another (increasing m or npfb), would increase the performance of the filter (by hitting stopband and having a sharper transition band) and I would see some marked benefit in the resulting spectrum, but that also doesn't appear to be so.

Also, let me know if you would like to continue this in the discussions instead of the issues, I don't want to muddy your repo more than I have already!

thezboe commented 9 months ago

Yea, I believe you are right that it's the way the arbitrary resampler is choosing the rounded down leg instead of interpolating between samples. I ended up creating a multistage setup with halfbands and the rational resampler and I'm getting results that are far more inline with what I expect. I'd be interested to see if an arbitrary resampler that interpolates gives me better results or not, but for now I'm satisfied with the answer considering that the rational resampler uses the same PFB block and has great results.