On Wed, 2017-12-27 at 16:18 -0500, Andy Walls wrote:
> Hi Eugene
> 
> > From:       Eugene Grayver
> > Date:       Thu, 9 Nov 2017 19:52:35 +0000
> > 
> > There is a major problem with the way tags are propagated in blocks
> > with non-integer relative rate. If the ratio is not a power of two,
> > the numerical accuracy of the floating point will cause the output
> > tags to diverge from the input tags.  Consider the fractional
> > resampler. It accumulates the timing offset in the range of 0 to 1.
> > However tag propagation multiplies the ratio by the sample number.
> > As
> > the sample number grows the LSB accuracy of the ratio gets scaled
> > by
> > the ever larger value. For a ratio of 1.001 we saw divergence of
> > 1000s of samples over a few minutes at 10msps.

OK, I've got a working fix for this:

https://github.com/gnuradio/gnuradio/pull/1543
or
https://github.com/awalls-cx18/gnuradio.git  branch tag_fix4

You will need to install the mpir and mpir-devel packages for your
distro, as this change adds a dependency on the MPIR library
(libmpirxx.so and libmpir.so).

With the attached GRC flowgraph, the fixed code shows no slips after 8
hours of continuous running on a modest laptop.  Compare that with the
baseline of gnuradio master, where after 8 hours, the tags have slipped
5 output samples to the right.

You were right about it being a floating point precision problem, but
the problem with the fractional resampler over short runs was (moslty)
not in the gnuradio runtime, but the fractional resampler block itself:

1. The gnuradio-runtime propagated tags with double arithmetic; the
fractional resampler block used mixed float & double arithmetic to
propagate tags.

2. Floating point reciprocals aren't exact in the lsb's, so specifying
set_relative_rate(1.0/resamp_ratio) was also introducing errors.  I.e.:

    [    andy@pinto     sw]$ ./rational3 1.001
    Resample ratio: 1.0009999999999999
    Resample ratio: 2254051613498933/2251799813685248
    Numerator: 2254051613498933
    Denominator: 2251799813685248

    Relative rate: 0.99900099900099915
    Relative rate: 4499100526843653/4503599627370496
    Numerator: 4499100526843653
    Denominator: 4503599627370496

Notice how the relative rate's numerator and denominator are not the
same as the resample ratio's denominator and numerator.

Geof:

Could you please take a look at the newly added cmake module
FindMPIR.cmake to see if it need changes for the Windows build?


Jeff and Marcus:

I'll address possible solutions for your observations (non-fixed
relative rate and fraction tag offsets) in a separate post.
I have a concept on how to address both, I think, but they can't be on
master branch due to API changes.

Regards,
Andy

Attachment: tag_prop_test.grc
Description: XML document

#include <stdlib.h>
#include <iostream>
#include <cmath>
#include <boost/math/common_factor_rt.hpp>
#include <mpirxx.h>
#include <limits>

int main(int argc, char *argv[])
{
        double resamp_ratio = strtod(argv[1], NULL);
        double relative_rate = 1/resamp_ratio;

        std::cout.precision(std::numeric_limits<double>::max_digits10);
        //---------------------------------------------------------------------
        // Using MPIR's C++ interface
        static const mpq_class one_half(1,2);
        mpq_class resamp_ratio_q(resamp_ratio);
        mpq_class relative_rate_q(relative_rate);
        //ratio.canonicalize();
        std::cout << "Resample ratio: " << resamp_ratio << std::endl;
        std::cout << "Resample ratio: " << resamp_ratio_q << std::endl;
        std::cout << "Numerator: " << resamp_ratio_q.get_num().get_ui() << std::endl;
        std::cout << "Denominator: " << resamp_ratio_q.get_den().get_ui() << std::endl;
        std::cout << std::endl;
        std::cout << "Relative rate: " << relative_rate << std::endl;
        std::cout << "Relative rate: " << relative_rate_q << std::endl;
        std::cout << "Numerator: " << relative_rate_q.get_num().get_ui() << std::endl;
        std::cout << "Denominator: " << relative_rate_q.get_den().get_ui() << std::endl;
        std::cout << std::endl;
#if 0
        //mpz_class offset(0x0800000000000003);
        uint64_t offset = 0x0800000000000003;
        mpq_class scaled = offset*ratio;
        mpz_class rscaled(scaled + one_half);
        mpz_class rscaled2;
        rscaled2 = offset * ratio + one_half;
        rscaled2 = offset * ratio + one_half + 2;
        std::cout << "Offset:        " << offset << std::endl;
        std::cout << "Scaled offset: " << scaled << std::endl;
        std::cout << "Rounded scaled offset: " << rscaled << std::endl;
        std::cout << "Rounded scaled offset2: " << rscaled2 << std::endl;
        uint64_t rscaledint = rscaled.get_ui();
        std::cout << "Native rounded scaled offset: " << rscaledint << std::endl;
#endif
        exit(0);
}
_______________________________________________
Discuss-gnuradio mailing list
Discuss-gnuradio@gnu.org
https://lists.gnu.org/mailman/listinfo/discuss-gnuradio

Reply via email to