在 gnuradio 中从 Float 转换为 Char 时出错
Error when converting from Float to Char in gnuradio
我正在尝试使用我的 USRP E100 捕获 GPS 信号并将它们保存到一个 .bin 文件中,下面是使用 GNU Radio Companion 实现的流程图:
如您所见,我从 GPS 频率接收到 50M 复数样本,并提取了它们的实部和虚部。然后,我将 Float 转换为 Char,并将其保存为 IQIQIQIQ(...) bin 文件。如果没有 Float 到 Char 的转换,一切正常,但如果有,输出文件只填充 0(例如,float 输出 "b502 323a b502 32b8 b502 b239 1d12 0b3a" 被转换为 char 输出 "0000 0000 0000 0000 0000 0000 0000 0000").
我不知道这里发生了什么,因为如果使用 Float to Char 块就会出现错误。我也尝试过使用其他类型转换器,例如 Float to Short,我得到了相同的输出:一个 0 向量。
生成流程图时的结果代码如下:
#!/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()
哪里出错了?也许是 USRP/hardware 问题?或者我无法将 Float 数据转换为 Char 数据?
在复数运算时,USRP 默认将每个 IQ 样本缩放在 [-1, 1] 范围内。
不过,我认为输入信号可能非常微弱,因此每个 IQ 样本值应低于 [-0.5, 0.5]。 Float to Char
块执行从 float 到 char 的转换。但是将浮点数转换为 [-0.5, 0.5] 范围内的整数应该总是产生零。这就是为什么您的文件只包含零的原因。
现在要避免这个问题,有两种可能的解决方案:
解决方案一:
适当缩放传入的 IQ 样本,使其范围超过 [-0.5, 0.5] 范围。这可以通过将信号乘以常数或适当更改 Float to Char
块的 Scale
参数来完成。
方案二:
由于您对 8 位样本精度感兴趣,我建议指示 USRP 以带符号的短(16 位)格式在流程图中传递样本。每个 IQ 样本的范围将在 [-2^15, 2^15] 内。然后直接进行Short to Char
转换即可,但要保证每次采样的幅度不大于2^7,否则会出现削波效果。使用此解决方案,流图中流动的数据要少得多,因为与复杂形式相比,每个 IQ 样本的大小只有一半。此外,整数向下转换速度更快。
我正在尝试使用我的 USRP E100 捕获 GPS 信号并将它们保存到一个 .bin 文件中,下面是使用 GNU Radio Companion 实现的流程图:
如您所见,我从 GPS 频率接收到 50M 复数样本,并提取了它们的实部和虚部。然后,我将 Float 转换为 Char,并将其保存为 IQIQIQIQ(...) bin 文件。如果没有 Float 到 Char 的转换,一切正常,但如果有,输出文件只填充 0(例如,float 输出 "b502 323a b502 32b8 b502 b239 1d12 0b3a" 被转换为 char 输出 "0000 0000 0000 0000 0000 0000 0000 0000").
我不知道这里发生了什么,因为如果使用 Float to Char 块就会出现错误。我也尝试过使用其他类型转换器,例如 Float to Short,我得到了相同的输出:一个 0 向量。
生成流程图时的结果代码如下:
#!/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()
哪里出错了?也许是 USRP/hardware 问题?或者我无法将 Float 数据转换为 Char 数据?
在复数运算时,USRP 默认将每个 IQ 样本缩放在 [-1, 1] 范围内。
不过,我认为输入信号可能非常微弱,因此每个 IQ 样本值应低于 [-0.5, 0.5]。 Float to Char
块执行从 float 到 char 的转换。但是将浮点数转换为 [-0.5, 0.5] 范围内的整数应该总是产生零。这就是为什么您的文件只包含零的原因。
现在要避免这个问题,有两种可能的解决方案:
解决方案一:
适当缩放传入的 IQ 样本,使其范围超过 [-0.5, 0.5] 范围。这可以通过将信号乘以常数或适当更改 Float to Char
块的 Scale
参数来完成。
方案二:
由于您对 8 位样本精度感兴趣,我建议指示 USRP 以带符号的短(16 位)格式在流程图中传递样本。每个 IQ 样本的范围将在 [-2^15, 2^15] 内。然后直接进行Short to Char
转换即可,但要保证每次采样的幅度不大于2^7,否则会出现削波效果。使用此解决方案,流图中流动的数据要少得多,因为与复杂形式相比,每个 IQ 样本的大小只有一半。此外,整数向下转换速度更快。