discuss-gnuradio
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Discuss-gnuradio] resample ratio for fractional_resampler


From: Marcus Müller
Subject: Re: [Discuss-gnuradio] resample ratio for fractional_resampler
Date: Tue, 24 Oct 2017 10:40:54 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.3.0

Hi Yang,

Just want to make sure I understand one thing correctly: using rational resampler can be slower than mmse resampler given the same 1/n resampling ratio, however it can lead to a signal with better spectrum? 
it's usually even faster, but you can't use a rational resampler for non-rational resampling. But as long as your resampling ratios are fixed and all rational (which both 1/64 and 1/67.5=2/135 are), I'd recommend using the rational resampler.

Best regards,

Marcus


On 2017-10-24 06:14, Yang Liu wrote:
Hi Marcus,

as you said, the reason that my upsampler is so slow is indeed constantly loading new filter coefficients from RAM for every new samples.

Just want to make sure I understand one thing correctly: using rational resampler can be slower than mmse resampler given the same 1/n resampling ratio, however it can lead to a signal with better spectrum? 

My application requires multiband transmission, which means I need to put multiple upsampler at the transmitter and that's why speed is my big concern. 

Thanks a lot for your help.

Best
Yang
 

On Mon, Oct 23, 2017 at 2:10 PM, Marcus Müller <address@hidden> wrote:

Hi Yang,

in the case of your resampling ratio being 1/f, with 128/f ∈ ℕ, you end up in a case where you only iterate over a subset of the filters in the MMSE filter bank. That probably has large advantages when it comes to L1 caching on your CPU – there's no need to constantly load new filter coefficients from RAM for every new sample. Speaking in terms of group theory, if you represent your resampling rate rᵣₑₛₐₘₚₗₑ = p/q, with p,q ∈ℕ₀ as rational number, then you can look at two special cases

  1. q is coprime to 128:¹ then {q} is generating set of ℤ/128ℤ – you'll step through all the 128 possible filters one by one (though not necessarily in ascending order), and maximize memory bandwidth consumption, in a sequence of length p·q·128.
  2. q is an integer factor of 128:² then {q} is only generator for a true subset C ⊂ ℤ/128ℤ, and that is a subset with size #C = p·128/q.

So, the case where q is a (large) integer factor of 128 and p is small is highly advantageous – and your p=1, q=64 is pretty optimal in that respect (r=1/64): You only alternate between two of the filters. Your second case, r=1/67.5 = 2/135 is the special case "A.", so you go through a very long sequence of filters, thrashing your CPU caches on your way.

However, chances are: If you're resampling by a rate of 1/64, using the "rational resampler" would lead to a better signal, whilst possibly keeping the computational intensity very much at bay.

So, if you ask me, try whether designing a FIR low pass filter and using it in a "Decimating FIR Filter" or even "FFT Filter" with decimation=64 doesn't yield faster results than using the MMSE resampler with 1/64. For a quick comparison, I came up with this quick Jupyter notebook:

from scipy import signal
import numpy
from matplotlib import pyplot

f=pyplot.figure(figsize=(15,10), dpi=150)
legend = []

for taps_to_decim_ratio in (1, 2, 3, 4, 8, 12, 16):
    taps = signal.fir_filter_design.firwin(taps_to_decim_ratio*64, 1./64)
    omega, h = signal.freqz(taps, worN=numpy.linspace(0, numpy.pi/31, 1000))
    pyplot.plot(omega/numpy.pi*64, 10*numpy.log10(numpy.abs(h)**2))
    legend.append("taps/decim {:3d}".format(taps_to_decim_ratio))
pyplot.grid(True)
pyplot.xlabel("$\\frac{f}{f_s} 64$")
pyplot.ylabel("$|\\cdot|^2_{dB}$")
pyplot.ylim((-70,1))
pyplot.legend(legend)
pyplot.tight_layout()
pyplot.show()

From the above figure, I'd say: go for 256 taps; 50 dB of anti-aliasing should probably suffice.
On my machine, the 256 tap FIR filter with decimation=64 ran about 20% faster than the fractional resampler; comparing what they do to white noise, I'd say that whilst the spectral shape of the 256 tap FIR is not perfect, the MMSE is pretty much unusable, I guess:
MMSE vs FIR frequency response

You could also use the same filter, but only decimate by a factor of e.g. 32 (instead of 64), and do the rest (e.g. 67.5/32 ≈ 2.1) with your MMSE / fractional resampler. In fact, I tried that, it looks much better in spectrum, and it's even faster. So, old wisdom:

Get as close as reasonable using a rational resampler, if possible an 1/n band decimating FIR, then do the rest with an arbitrary resampler like the MMSE/fractional resampler.

Best regards,

Marcus


¹ which is synonymous to q being coprime to 128p, since p and q are coprime by above definition
² which is synonymous to being integer factor of 128p, see¹

On 2017-10-23 17:47, Yang Liu wrote:
HI Marcus,

Thank you so much for your help!

Since there's one iteration per output sample and the number of taps of filtering is 8 (fixed), the time it takes to do one iteration is fixed no matter what resampling ratio I set. What slows things down is: as the resampling ratio increase, the number of iteration increases given a fixed number of input items. I just want to make sure I understand things correctly :)

I set the resampling ratio to be (1/67.5) at transmitter, I noticed that (1/67.5) doesn't work as good as the integer (1/64.0), does it mean fractional part will also slow things down?

Thanks,
Yang

On Mon, Oct 23, 2017 at 5:47 AM, Marcus Müller <address@hidden> wrote:

Hi Yang,

for questions of performance, it's usually best to consult the source code itself. By the way, fractional_resampler_** has been renamed mmse_resampler_** on git's "next" branch.

You'll notice the code in {mmse_|fractional_}resampler_cc_impl.cc is:

        while(oo < noutput_items) {
          out[oo++] = d_resamp->interpolate(&in[ii], d_mu);

          double s = d_mu + d_mu_inc;
          double f = floor(s);
          int incr = (int)f;
          d_mu = s - f;
          ii += incr;
        }

        consume_each(ii);
        return noutput_items;

Which means there's one iteration per output sample, invariably, no matter what your resampling ratio is.
What would increase the performance is reducing NTAPS in {mmse_|fractional_}interpolator, but since that is already only 8, which, with a bit of SIMD, your CPU does in a single instruction, I don't seem that much room for improvement there.
The other thing would be reducing NSTEPS, but it's already but a 7 bit quantization of the q in rᵣₑₛₐₘₚₗₑ = n + q, n∈ℕ₀, 0≤q∈ℚ, so I'm not convinced you'd want to do that; the jitter you get for a b bit quantization (i.e. b=log₂ NSTEPS) has a variance of (-20b log₁₀ 2-10 log₁₀ 12) dB ≈ -(6b + 10.8) dB (hoping that I do the math right). If I juggle Cauchy's mean value theorem correctly in my head, that means you basically get that (times the signal power) as the worst-case power in the phase noise introduced by the timing approximation with a critically sampled signal. If I'm right (really, haven't taken the time to write this down), then that means e.g. for NSTEPS=128, that you get -52.8 dB phase noise, whereas a reduction to let's say NSTEPS=16 gives you 24 dB more noise – and -28.8 dB phase noise isn't all that great.

What are the resampling ratios you're working with?

Best regards,
Marcus


On 2017-10-23 05:31, Yang Liu wrote:
Dear all, 

I used fractional resampler(gr::filter::fractional_resampler_cc) at transmitter side to help up sample the signal to the device sample rate before sending it out. In the experiment, I found that this resampler works well for some resample ratio (in terms of speed), and the performance (speed) doesn't necessarily improve as the resample ratio decreases.

Therefore, I am wondering whether this resampling block indeed works better for some sets of resampling ratio? If yes, what are these sets? Knowing this will help me to set the parameters at tx properly especially when the sample rate is high :)

Thanks a lot for your help.

Best, 
Yang


_______________________________________________
Discuss-gnuradio mailing list
address@hidden
https://lists.gnu.org/mailman/listinfo/discuss-gnuradio


_______________________________________________
Discuss-gnuradio mailing list
address@hidden
https://lists.gnu.org/mailman/listinfo/discuss-gnuradio





Attachment: smime.p7s
Description: S/MIME Cryptographic Signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]