Search code examples
floating-pointgnuradiousrpgnuradio-companion

Error when converting from Float to Char in gnuradio


I'm trying to capture GPS signals and save them into a .bin file with my USRP E100 and the following flow diagram implemented with GNU Radio Companion:

enter image description here

As you can see, I recieve 50M complex samples from GPS frequency, and I take the real and imaginary part of them. Then, I do a Float to Char conversion, and I save it as an IQIQIQIQ(...) bin file. If there is no Float to Char conversion, everything works well, but if there is, the output file is filled with 0's only (e.g. the float output "b502 323a b502 32b8 b502 b239 1d12 0b3a" is converted into the char output "0000 0000 0000 0000 0000 0000 0000 0000").

I don't know what is happening here, because the error appears if the Float to Char block used. I also have tried to use other Type Converters such as Float to Short, and I get the same output: a vector of 0's.

The resulting code when generating the flow graph is presented as follows:

#!/usr/bin/env python
##################################################
# Gnuradio Python Flow Graph
# Title: Gps Datagrabber
# Generated: Wed Feb  3 10:01:35 2016
##################################################

from gnuradio import eng_notation
from gnuradio import gr
from gnuradio import uhd
from gnuradio.eng_option import eng_option
from gnuradio.gr import firdes
from optparse import OptionParser

class GPS_datagrabber(gr.top_block):

    def __init__(self):
        gr.top_block.__init__(self, "Gps Datagrabber")

        ##################################################
        # Variables
        ##################################################
        self.samp_rate = samp_rate = 5*1000000
        self.Tiempo_sec = Tiempo_sec = 10
        self.gain = gain = 15
        self.center_freq = center_freq = int(1.57542e9)
        self.band = band = int(40e6)
        self.Samples = Samples = Tiempo_sec*samp_rate

        ##################################################
        # Blocks
        ##################################################
        self.gr_interleave_0 = gr.interleave(gr.sizeof_char*1)
        self.gr_head_0 = gr.head(gr.sizeof_gr_complex*1, 50000000)
        self.gr_float_to_char_1 = gr.float_to_char()
        self.gr_float_to_char_0 = gr.float_to_char()
        self.gr_file_sink_0 = gr.file_sink(gr.sizeof_char*1, "/home/root/Desktop/USRP_E100")
        self.gr_file_sink_0.set_unbuffered(True)
        self.gr_complex_to_real_0 = gr.complex_to_real(1)
        self.gr_complex_to_imag_0 = gr.complex_to_imag(1)
        self.USRP_sync_123 = uhd.usrp_source(
            device_addr="addr0=192.168.10.1",
            stream_args=uhd.stream_args(
                cpu_format="fc32",
                channels=range(1),
            ),
        )
        self.USRP_sync_123.set_clock_source("external", 0)
        self.USRP_sync_123.set_time_source("external", 0)
        self.USRP_sync_123.set_samp_rate(samp_rate)
        self.USRP_sync_123.set_center_freq(center_freq, 0)
        self.USRP_sync_123.set_gain(gain, 0)
        self.USRP_sync_123.set_antenna("TX/RX", 0)
        self.USRP_sync_123.set_bandwidth(band, 0)

        ##################################################
        # Connections
        ##################################################
        self.connect((self.USRP_sync_123, 0), (self.gr_head_0, 0))
        self.connect((self.gr_head_0, 0), (self.gr_complex_to_real_0, 0))
        self.connect((self.gr_interleave_0, 0), (self.gr_file_sink_0, 0))
        self.connect((self.gr_complex_to_real_0, 0), (self.gr_float_to_char_0, 0))
        self.connect((self.gr_float_to_char_0, 0), (self.gr_interleave_0, 0))
        self.connect((self.gr_complex_to_imag_0, 0), (self.gr_float_to_char_1, 0))
        self.connect((self.gr_float_to_char_1, 0), (self.gr_interleave_0, 1))
        self.connect((self.gr_head_0, 0), (self.gr_complex_to_imag_0, 0))

    def get_samp_rate(self):
        return self.samp_rate

    def set_samp_rate(self, samp_rate):
        self.samp_rate = samp_rate
        self.set_Samples(self.Tiempo_sec*self.samp_rate)
        self.USRP_sync_123.set_samp_rate(self.samp_rate)

    def get_Tiempo_sec(self):
        return self.Tiempo_sec

    def set_Tiempo_sec(self, Tiempo_sec):
        self.Tiempo_sec = Tiempo_sec
        self.set_Samples(self.Tiempo_sec*self.samp_rate)

    def get_gain(self):
        return self.gain

    def set_gain(self, gain):
        self.gain = gain
        self.USRP_sync_123.set_gain(self.gain, 0)
        self.USRP_sync_123.set_gain(self.gain, 1)
        self.USRP_sync_123.set_gain(self.gain, 2)

    def get_center_freq(self):
        return self.center_freq

    def set_center_freq(self, center_freq):
        self.center_freq = center_freq
        self.USRP_sync_123.set_center_freq(self.center_freq, 0)
        self.USRP_sync_123.set_center_freq(self.center_freq, 1)
        self.USRP_sync_123.set_center_freq(self.center_freq, 2)

    def get_band(self):
        return self.band

    def set_band(self, band):
        self.band = band
        self.USRP_sync_123.set_bandwidth(self.band, 0)
        self.USRP_sync_123.set_bandwidth(self.band, 1)
        self.USRP_sync_123.set_bandwidth(self.band, 2)

    def get_Samples(self):
        return self.Samples

    def set_Samples(self, Samples):
        self.Samples = Samples

if __name__ == '__main__':
    parser = OptionParser(option_class=eng_option, usage="%prog: [options]")
    (options, args) = parser.parse_args()
    tb = GPS_datagrabber()
    tb.run()

Where is the error? Maybe is an USRP/hardware problem? Or maybe I cannot convert that Float data into Char data?


Solution

  • When operating in complex numbers, the USRP by default scale each IQ samples in the range of [-1, 1].

    However, I believe that the input signal may be quite weak so each IQ sample value should be below [-0.5, 0.5]. The Float to Char block performs a casting from float to char. But casting a float to an integer on the range of [-0.5, 0.5] should always produce zero. That why your file contains only zeros.

    To avoid now this problem, there are two possible solutions:

    Solution 1: Scale the incoming IQ samples properly so their range exceeds the [-0.5, 0.5] range. This can be done either by multiplying the signal with a constant or changing properly the Scale parameter of the Float to Char block.

    Solution 2: As you are interested in 8-bit sample accuracy, I would suggest to instruct the USRP to pass samples at the flowgraph in signed short (16-bit) format. The range of each IQ sample will be in [-2^15, 2^15]. Then just perform Short to Char conversion, but make sure that the amplitude of each sample is not greater than 2^7, otherwise you will get a clipping effect. With this solution the data that are flowing in your flowgraph are much less, because each IQ sample has the half size comparing with the complex form. Also, integer down-castings are faster.