Quadrature_demod losing weak signals

This seems like a bug, but I want to check first that I’m not having
unreasonable expectations. I’m using GNU Radio 3.7.2.

If the amplitude of the input to quadrature_demod_cf is less than about
10^(-2.23), then the output samples are zero instead of the demodulated
signal.

Since such an exponent is well within the range for (complex)
single-float samples, this seems like a problem with the arithmetic used
by quadrature_demod.

I noticed it because my analog FM receiver would produce complete
silence instead of static, despite not having any squelch enabled;
unfortunately, it also produces silence on weak signals that would
otherwise be intelligible. I have a notion that this did not occur in
older GNU Radio versions (e.g. 3.6) but I’m not in a good position to
test exactly where the problem might have been introduced.

I’ve attached a GRC flowgraph for experimenting with the behavior, and a
screenshot of what the demodulated output looks like just at the
threshold of failure (the signal is 200 samples per cycle).

On Sat, Nov 30, 2013 at 2:50 AM, Kevin R. [email protected] wrote:

I tried your grc file and the scope sink shows a perfect sinewave
here. So maybe it is a voilk issue or the gr::fast_atan2f on your
parchitecture. Mine was using avx_64_mmx_orc

Alex

On Sat, Nov 30, 2013 at 5:09 AM, Alexandru C. [email protected]
wrote:

I’ve attached a GRC flowgraph for experimenting with the behavior, and a
screenshot of what the demodulated output looks like just at the threshold of
failure (the signal is 200 samples per cycle).

I tried your grc file and the scope sink shows a perfect sinewave
here. So maybe it is a voilk issue or the gr::fast_atan2f on your
parchitecture. Mine was using avx_64_mmx_orc

Alex

Works fine for me, too. Alex is probably right that there’s something
going on with the SIMD architecture of your processor. The
quadrature_demod_cf block uses the
volk_32fc_x2_multiply_conjugate_32fc kernel. On my machine, I’m using
the SSE3 version of the kernel for both aligned and unaligned
architectures (in ~/.volk/volk_config). That kernel only has SSE3 and
generic kernels. You might try changing those to ‘generic’ to see if
that makes a difference on your machine.

For more details on VOLK and how the configure file is structured,
see: http://gnuradio.org/redmine/projects/gnuradio/wiki/Volk

Tom

On Sat, Nov 30, 2013 at 10:55 AM, Kevin R. [email protected] wrote:

On Nov 30, 2013, at 2:09, Alexandru C. [email protected] wrote:

On Sat, Nov 30, 2013 at 2:50 AM, Kevin R. [email protected] wrote:

If the amplitude of the input to quadrature_demod_cf is less than about
10^(-2.23), then the output samples are zero instead of the demodulated signal.

I tried your grc file and the scope sink shows a perfect sinewave
here.

Just checking, since I didn’t mention it before: the default value of the slider
is the level well above where it fails. Does it fail for you if you turn it down?

Yes, same behavior if I turn it down; not unexpected giving what you
found below.

Since the preceding multiply_conjugate should square the magnitude, this choice
of epsilon accounts for the threshold I found empirically.

Given this, I’m going to file an issue requesting that this epsilon be reduced.
(The only alternative that comes to mind is to place an AGC block before the
demodulator, which seems unlikely to be better from a numerical perspective).


Kevin R. http://switchb.org/kpreid/

Agreed. This threshold should be reduced. Can you experiment with that
threshold to see if there’s any lower limit that might be problematic
(my default threshold, for some reason, is 1e-20; would want to make
sure that doesn’t cause something else in the math to blow up).

Tom

On Nov 30, 2013, at 2:09, Alexandru C. [email protected] wrote:

On Sat, Nov 30, 2013 at 2:50 AM, Kevin R. [email protected] wrote:

If the amplitude of the input to quadrature_demod_cf is less than about
10^(-2.23), then the output samples are zero instead of the demodulated signal.

I tried your grc file and the scope sink shows a perfect sinewave
here.

Just checking, since I didn’t mention it before: the default value of
the slider is the level well above where it fails. Does it fail for you
if you turn it down?

So maybe it is a voilk issue or the gr::fast_atan2f on your
parchitecture. Mine was using avx_64_mmx_orc

Thank you, I should have mentioned my volk configuration. fast_atan2f
doesn’t appear to have any volk dependency…

…but I think I’ve spotted the problem. In fast_atan2f, we have this
recently-introduced (Nov 6) code, where the epsilon used to be a
comparison with zero:

/* don't divide by zero! */
if((y_abs < 1.5E-5) && (x_abs < 1.5E-5))
  return 0.0;

Since the preceding multiply_conjugate should square the magnitude, this
choice of epsilon accounts for the threshold I found empirically.

Given this, I’m going to file an issue requesting that this epsilon be
reduced. (The only alternative that comes to mind is to place an AGC
block before the demodulator, which seems unlikely to be better from a
numerical perspective).


Kevin R. http://switchb.org/kpreid/

On Nov 30, 2013, at 8:22, Tom R. [email protected] wrote:

threshold to see if there’s any lower limit that might be problematic
(my default threshold, for some reason, is 1e-20; would want to make
sure that doesn’t cause something else in the math to blow up).

I have modified a copy of fast_atan2f to have the test “(y_abs == 0.0f)
&& (x_abs == 0.0f)” and plotted the results of fast_atan2f(ksin(angle),
k
cos(angle)) against both angle and atan2f(ksin(angle), kcos(angle))
at various exponents for k.

At small magnitudes fast_atan2f is a better approximation to regular
atan2f than it is at magnitudes close to 1, and the error compared to
the original angle (which should partly be attributed to representing
sin and cos values) has the same patterning at all scales. At no point
does fast_atan2f emit complete nonsense; it is consistent all the way
down to the point at which both y and x are rounded to 0.0.

My conclusion is that fast_atan2f is as good as it ever is all the way
down to the minimum representable values (~ 1e-45), and that one might
as well revert the code to an equality test with 0.0 (or perhaps “y_abs
<= 0.0” if a linter needs to be satisfied).

That said, I’m no expert on numerics and I might well have missed some
particular undesirable behavior that should be avoided. Therefore, I
will attach the tools I wrote to test the behavior. “main.cc” generates
a table of error values (the parameters are hardcoded), and “run.sh”
will build it and plot the values using the gnuplot script.

(Note that there is a special case in main.cc to emit a constant nonzero
value when x and y are exactly zero after being scaled down; that value
is intended as an out-of-band marker and is not an actual error.)