Search code examples
pythonpython-3.xnumpygnuradio

How to change the precision of a value in a pmt pairs


I am trying to realize a block in gnuradio. It must send a message to the output and command the frequency of a signal source block. The message is a pmt pairs which contains the frequency value in the cdr field. When I put it into the pairs, its precision decreases a lot. For example, with this code

import numpy as np
import pmt

freqval = np.float64(123494235.48994166)
msg = pmt.cons(pmt.intern("freq"), pmt.to_pmt(freqval))

print("freqval : ", freqval)
print("msg : ", msg)

freqval = np.float64(123.49423548994166)
msg = pmt.cons(pmt.intern("freq"), pmt.to_pmt(freqval))

print("freqval : ", freqval)
print("msg : ", msg)

i get

freqval :  123494235.48994166
msg :  (freq . 1.23494e+08)
freqval :  123.49423548994166
msg :  (freq . 123.494)

while I want the value in the msg to be the same as the one contained in freqval. I tried to replace to_pmt() whith from_float() and from_double(), but nothing changed, and making the value as string, but gnuradio raises the warning

gr::log :WARN: sig_source0 - frequency value needs to be a number

Is there a way to change the precision of the pmt pairs value?


Solution

  • This is just the precision of the "pretty print string representation". When you convert your PMT back to a python float or a C double, you should get sufficient precision.

    > value = 1/3
    # one third has very many fractional digits – it 
    # can't be exactly represented in base 10
    # but it can't even be exactly stored in a float,
    # because 1/3 can also not be exactly represented
    # in binary.
    > print(value)
    0.3333333333333333
    # note how most of these digits are just
    # "made up (i.e. the closest approximation to 1/3
    # in binary of given length)"; python floating points
    # don't have 50 significant digits!
    > print(f"{value:.50f}"
    0.33333333333333331482961625624739099293947219848633
    > a = pmt.pmt_to_python.python_to_pmt(value)
    > b = pmt.pmt_to_python.pmt_to_python(a)
    > print(b-value)
    0.0
    > print(f"{b-value:.50f}")
    0.00000000000000000000000000000000000000000000000000
    

    This is basically true for most floating point formats: The way a number is printed is not equal to the number itself!

    PMT knows this and makes a decision to not try and represent many digits when printing – that's really more of a convenience function. When you need to work with the value of a PMT, you'd always convert that PMT to a native type again.