Skip to content

Commit

Permalink
Update README and Add Pulse Width Measurement Field in Seconds (#4)
Browse files Browse the repository at this point in the history
* Adding pulse width measurement in units of time to the pdw log file, previously only the pulse width was given as the number of samples in the pulse when logging.

* Update README.md with instruction to generate pulse generator heir block

---------

Co-authored-by: Trip Humphries <jhumphries33@jhumphries5430l.seal-ad.gtri.org>
  • Loading branch information
thumphries-gtri and Trip Humphries authored Jan 11, 2025
1 parent d90792c commit b9a6d2c
Show file tree
Hide file tree
Showing 6 changed files with 173 additions and 73 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ To install from source:

Steps may vary slightly depending on how your particular GNU Radio environment is setup.

Generate Pulse Generator Heir Block:

* Open GNU Radio Companion (GRC)
* Load the Pulse Generator Flowgraph: gr-pdw/examples/pulse_gen_heir.grc
* Generate / Run the Flowgraph

## Contents

* Blocks
Expand Down
6 changes: 3 additions & 3 deletions apps/virtual_pdw.grc
Original file line number Diff line number Diff line change
Expand Up @@ -402,14 +402,14 @@ blocks:
alias: ''
buffer_size: '1000'
comment: ''
enabled: 'False'
file_name: /home/jhumphries33/sdr/git/gr-pdw/examples/test_pdw.hdf5
enabled: 'True'
file_name: ''
fs: samp_rate
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [1144, 428.0]
coordinate: [1168, 412.0]
rotation: 180
state: true
- name: pdw_pulse_detect_0
Expand Down
170 changes: 127 additions & 43 deletions apps/virtual_pdw.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,22 @@

from PyQt5 import Qt
from gnuradio import qtgui
import os
import sys
sys.path.append(os.environ.get('GRC_HIER_PATH', os.path.expanduser('~/.grc_gnuradio')))

from PyQt5 import QtCore
from gnuradio import analog
from gnuradio import blocks
from gnuradio import gr
from gnuradio.filter import firdes
from gnuradio.fft import window
import sys
import signal
from PyQt5 import Qt
from argparse import ArgumentParser
from gnuradio.eng_arg import eng_float, intx
from gnuradio import eng_notation
from gnuradio import uhd
import time
from pulses import pulses # grc-generated hier_block
import pdw
import sip
import threading
Expand Down Expand Up @@ -66,37 +69,57 @@ def __init__(self):
##################################################
# Variables
##################################################
self.threshold = threshold = 0.05
self.threshold = threshold = 0.1
self.sq_amp = sq_amp = 1
self.samp_rate = samp_rate = 1e6
self.ref_level = ref_level = -20
self.freq = freq = 3000e6
self.ref_level = ref_level = -10
self.pw = pw = 5
self.pulse_freq = pulse_freq = 0
self.pri = pri = 1e-3
self.plotUpdateRate = plotUpdateRate = 0.1
self.numPlotItems = numPlotItems = 250
self.maxItemsUpdate = maxItemsUpdate = 10
self.freq = freq = 1e9

##################################################
# Blocks
##################################################

self._threshold_range = qtgui.Range(0, 1, 0.0005, 0.05, 200)
self._threshold_range = qtgui.Range(0, 1, 0.01, 0.1, 200)
self._threshold_win = qtgui.RangeWidget(self._threshold_range, self.set_threshold, "Pulse Threshold", "counter_slider", float, QtCore.Qt.Horizontal)
self.top_grid_layout.addWidget(self._threshold_win, 3, 2, 1, 1)
for r in range(3, 4):
self.top_grid_layout.setRowStretch(r, 1)
for c in range(2, 3):
self.top_grid_layout.setColumnStretch(c, 1)
self.uhd_usrp_source_0 = uhd.usrp_source(
",".join(("", "")),
uhd.stream_args(
cpu_format="fc32",
args='',
channels=list(range(0,1)),
),
)
self.uhd_usrp_source_0.set_samp_rate(samp_rate)
self.uhd_usrp_source_0.set_time_unknown_pps(uhd.time_spec(0))

self.uhd_usrp_source_0.set_center_freq(freq, 0)
self.uhd_usrp_source_0.set_antenna('RX2', 0)
self.uhd_usrp_source_0.set_rx_agc(False, 0)
self.uhd_usrp_source_0.set_gain(30, 0)
self._sq_amp_range = qtgui.Range(0, 1, 0.01, 1, 200)
self._sq_amp_win = qtgui.RangeWidget(self._sq_amp_range, self.set_sq_amp, "Pulse Amplitude", "counter_slider", float, QtCore.Qt.Horizontal)
self.top_grid_layout.addWidget(self._sq_amp_win, 0, 2, 1, 1)
for r in range(0, 1):
self.top_grid_layout.setRowStretch(r, 1)
for c in range(2, 3):
self.top_grid_layout.setColumnStretch(c, 1)
self._pw_range = qtgui.Range(1, 200, 0.1, 5, 200)
self._pw_win = qtgui.RangeWidget(self._pw_range, self.set_pw, "Pulse Width (us)", "counter_slider", float, QtCore.Qt.Horizontal)
self.top_grid_layout.addWidget(self._pw_win, 1, 2, 1, 1)
for r in range(1, 2):
self.top_grid_layout.setRowStretch(r, 1)
for c in range(2, 3):
self.top_grid_layout.setColumnStretch(c, 1)
self._pulse_freq_range = qtgui.Range(-samp_rate/2, samp_rate/2, 10e3, 0, 200)
self._pulse_freq_win = qtgui.RangeWidget(self._pulse_freq_range, self.set_pulse_freq, "Pulse Freq (Hz)", "counter_slider", float, QtCore.Qt.Horizontal)
self.top_grid_layout.addWidget(self._pulse_freq_win, 2, 2, 1, 1)
for r in range(2, 3):
self.top_grid_layout.setRowStretch(r, 1)
for c in range(2, 3):
self.top_grid_layout.setColumnStretch(c, 1)
self._pri_range = qtgui.Range(1e-3, 50e-3, 1e-3, 1e-3, 200)
self._pri_win = qtgui.RangeWidget(self._pri_range, self.set_pri, "PRI", "counter_slider", float, QtCore.Qt.Horizontal)
self.top_grid_layout.addWidget(self._pri_win, 4, 2, 1, 1)
for r in range(4, 5):
self.top_grid_layout.setRowStretch(r, 1)
for c in range(2, 3):
self.top_grid_layout.setColumnStretch(c, 1)
self.qtgui_time_sink_x_0 = qtgui.time_sink_f(
1024, #size
samp_rate, #samp_rate
Expand All @@ -120,13 +143,13 @@ def __init__(self):

labels = ['Signal 1', 'Signal 2', 'Signal 3', 'Signal 4', 'Signal 5',
'Signal 6', 'Signal 7', 'Signal 8', 'Signal 9', 'Signal 10']
widths = [1, 1, 1, 1, 1,
widths = [2, 2, 1, 1, 1,
1, 1, 1, 1, 1]
colors = ['blue', 'red', 'green', 'black', 'cyan',
'magenta', 'yellow', 'dark red', 'dark green', 'dark blue']
alphas = [1.0, 1.0, 1.0, 1.0, 1.0,
1.0, 1.0, 1.0, 1.0, 1.0]
styles = [1, 1, 1, 1, 1,
styles = [1, 2, 1, 1, 1,
1, 1, 1, 1, 1]
markers = [-1, -1, -1, -1, -1,
-1, -1, -1, -1, -1]
Expand All @@ -145,36 +168,46 @@ def __init__(self):

self._qtgui_time_sink_x_0_win = sip.wrapinstance(self.qtgui_time_sink_x_0.qwidget(), Qt.QWidget)
self.top_layout.addWidget(self._qtgui_time_sink_x_0_win)
self.pdw_usrp_power_cal_table_0 = pdw.usrp_power_cal_table(True, freq, ref_level)
self.pulses_0 = pulses(
a=sq_amp,
pri=pri,
pulse_width=(pw*(1e-6)),
samp_rate=samp_rate,
)
self.pdw_virtual_power_cal_table_0 = pdw.virtual_power_cal_table(freq, ref_level)
self.pdw_pulse_extract_0 = pdw.pulse_extract(samp_rate)
self.pdw_pulse_detect_0 = pdw.pulse_detect(threshold, samp_rate)
self.pdw_pulse_detect_0.set_min_output_buffer((2**16))
self.pdw_pdw_to_file_0 = pdw.pdw_to_file('pdw_log.bin', samp_rate, 10000, False)
self.pdw_pdw_plot_0_0_0 = _pdw_plot_pdw_pdw_plot_0_0_0 = pdw.pdw_plot('', 'FREQ', [], 10, 250, 0.1, "white", "white", "red", self)
self.pdw_pdw_to_file_0 = pdw.pdw_to_file('/home/jhumphries33/sdr/git/gr-pdw/examples/test_pdw.hdf5', samp_rate, 1000, True)
self.pdw_pdw_plot_0_0_0 = _pdw_plot_pdw_pdw_plot_0_0_0 = pdw.pdw_plot('', 'FREQ', [(-samp_rate/2)/1e6, ( samp_rate/2)/1e6], maxItemsUpdate, numPlotItems, plotUpdateRate, "white", "white", "red", self)
self.pdw_pdw_plot_0_0_0 = _pdw_plot_pdw_pdw_plot_0_0_0

self.top_grid_layout.addWidget(_pdw_plot_pdw_pdw_plot_0_0_0, 4, 1, 3, 1)
for r in range(4, 7):
self.top_grid_layout.addWidget(_pdw_plot_pdw_pdw_plot_0_0_0, 4, 1, 4, 1)
for r in range(4, 8):
self.top_grid_layout.setRowStretch(r, 1)
for c in range(1, 2):
self.top_grid_layout.setColumnStretch(c, 1)
self.pdw_pdw_plot_0_0 = _pdw_plot_pdw_pdw_plot_0_0 = pdw.pdw_plot('', 'WIDTH', [], 10, 250, 0.1, "white", "white", "red", self)
self.pdw_pdw_plot_0_0 = _pdw_plot_pdw_pdw_plot_0_0 = pdw.pdw_plot('', 'WIDTH', [], maxItemsUpdate, numPlotItems, plotUpdateRate, "white", "white", "red", self)
self.pdw_pdw_plot_0_0 = _pdw_plot_pdw_pdw_plot_0_0

self.top_grid_layout.addWidget(_pdw_plot_pdw_pdw_plot_0_0, 4, 0, 3, 1)
for r in range(4, 7):
self.top_grid_layout.addWidget(_pdw_plot_pdw_pdw_plot_0_0, 4, 0, 4, 1)
for r in range(4, 8):
self.top_grid_layout.setRowStretch(r, 1)
for c in range(0, 1):
self.top_grid_layout.setColumnStretch(c, 1)
self.pdw_pdw_plot_0 = _pdw_plot_pdw_pdw_plot_0 = pdw.pdw_plot('', 'POWER', [], 10, 250, 0.1, "white", "white", "red", self)
self.pdw_pdw_plot_0 = _pdw_plot_pdw_pdw_plot_0 = pdw.pdw_plot('', 'POWER', [-60,0], maxItemsUpdate, numPlotItems, plotUpdateRate, "white", "white", "red", self)
self.pdw_pdw_plot_0 = _pdw_plot_pdw_pdw_plot_0

self.top_grid_layout.addWidget(_pdw_plot_pdw_pdw_plot_0, 0, 0, 3, 2)
for r in range(0, 3):
self.top_grid_layout.addWidget(_pdw_plot_pdw_pdw_plot_0, 0, 0, 4, 2)
for r in range(0, 4):
self.top_grid_layout.setRowStretch(r, 1)
for c in range(0, 2):
self.top_grid_layout.setColumnStretch(c, 1)
self.blocks_throttle2_0 = blocks.throttle( gr.sizeof_gr_complex*1, samp_rate, True, 0 if "auto" == "auto" else max( int(float(0.1) * samp_rate) if "auto" == "time" else int(0.1), 1) )
self.blocks_multiply_xx_0 = blocks.multiply_vcc(1)
self.blocks_complex_to_mag_0 = blocks.complex_to_mag(1)
self.blocks_add_xx_0 = blocks.add_vcc(1)
self.analog_sig_source_x_0 = analog.sig_source_c(samp_rate, analog.GR_COS_WAVE, pulse_freq, 1, 0, 0)
self.analog_fastnoise_source_x_0 = analog.fastnoise_source_c(analog.GR_GAUSSIAN, 0.01, 0, 8192)


##################################################
Expand All @@ -184,13 +217,17 @@ def __init__(self):
self.msg_connect((self.pdw_pulse_extract_0, 'pulse_data'), (self.pdw_pdw_plot_0_0, 'pdw'))
self.msg_connect((self.pdw_pulse_extract_0, 'pulse_data'), (self.pdw_pdw_plot_0_0_0, 'pdw'))
self.msg_connect((self.pdw_pulse_extract_0, 'pulse_data'), (self.pdw_pdw_to_file_0, 'pdw_in'))
self.msg_connect((self.pdw_usrp_power_cal_table_0, 'ref_level_msg'), (self.pdw_pulse_extract_0, 'set_ref_level'))
self.msg_connect((self.pdw_usrp_power_cal_table_0, 'gain_msg'), (self.uhd_usrp_source_0, 'command'))
self.msg_connect((self.pdw_virtual_power_cal_table_0, 'ref_level_msg'), (self.pdw_pulse_extract_0, 'set_ref_level'))
self.connect((self.analog_fastnoise_source_x_0, 0), (self.blocks_add_xx_0, 1))
self.connect((self.analog_sig_source_x_0, 0), (self.blocks_multiply_xx_0, 0))
self.connect((self.blocks_add_xx_0, 0), (self.pdw_pulse_detect_0, 0))
self.connect((self.blocks_complex_to_mag_0, 0), (self.qtgui_time_sink_x_0, 0))
self.connect((self.blocks_multiply_xx_0, 0), (self.blocks_throttle2_0, 0))
self.connect((self.blocks_throttle2_0, 0), (self.blocks_add_xx_0, 0))
self.connect((self.pdw_pulse_detect_0, 0), (self.blocks_complex_to_mag_0, 0))
self.connect((self.pdw_pulse_detect_0, 0), (self.pdw_pulse_extract_0, 0))
self.connect((self.pdw_pulse_detect_0, 1), (self.qtgui_time_sink_x_0, 1))
self.connect((self.uhd_usrp_source_0, 0), (self.pdw_pulse_detect_0, 0))
self.connect((self.pulses_0, 0), (self.blocks_multiply_xx_0, 1))


def closeEvent(self, event):
Expand All @@ -208,28 +245,75 @@ def set_threshold(self, threshold):
self.threshold = threshold
self.pdw_pulse_detect_0.threshold_changed(self.threshold)

def get_sq_amp(self):
return self.sq_amp

def set_sq_amp(self, sq_amp):
self.sq_amp = sq_amp
self.pulses_0.set_a(self.sq_amp)

def get_samp_rate(self):
return self.samp_rate

def set_samp_rate(self, samp_rate):
self.samp_rate = samp_rate
self.analog_sig_source_x_0.set_sampling_freq(self.samp_rate)
self.blocks_throttle2_0.set_sample_rate(self.samp_rate)
self.pulses_0.set_samp_rate(self.samp_rate)
self.qtgui_time_sink_x_0.set_samp_rate(self.samp_rate)
self.uhd_usrp_source_0.set_samp_rate(self.samp_rate)

def get_ref_level(self):
return self.ref_level

def set_ref_level(self, ref_level):
self.ref_level = ref_level
self.pdw_usrp_power_cal_table_0.ref_changed(self.ref_level)
self.pdw_virtual_power_cal_table_0.ref_changed(self.ref_level)

def get_pw(self):
return self.pw

def set_pw(self, pw):
self.pw = pw
self.pulses_0.set_pulse_width((self.pw*(1e-6)))

def get_pulse_freq(self):
return self.pulse_freq

def set_pulse_freq(self, pulse_freq):
self.pulse_freq = pulse_freq
self.analog_sig_source_x_0.set_frequency(self.pulse_freq)

def get_pri(self):
return self.pri

def set_pri(self, pri):
self.pri = pri
self.pulses_0.set_pri(self.pri)

def get_plotUpdateRate(self):
return self.plotUpdateRate

def set_plotUpdateRate(self, plotUpdateRate):
self.plotUpdateRate = plotUpdateRate

def get_numPlotItems(self):
return self.numPlotItems

def set_numPlotItems(self, numPlotItems):
self.numPlotItems = numPlotItems

def get_maxItemsUpdate(self):
return self.maxItemsUpdate

def set_maxItemsUpdate(self, maxItemsUpdate):
self.maxItemsUpdate = maxItemsUpdate

def get_freq(self):
return self.freq

def set_freq(self, freq):
self.freq = freq
self.pdw_usrp_power_cal_table_0.freq_changed(self.freq)
self.uhd_usrp_source_0.set_center_freq(self.freq, 0)
self.pdw_virtual_power_cal_table_0.freq_changed(self.freq)



Expand Down
6 changes: 4 additions & 2 deletions examples/read_pdw_file_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@
print(f"Timestamp: {f.attrs['time_py']}")
print(f"Unix Timestamp: {f.attrs['time_unix']}")

pdw_pw = np.array(f['pulse_width'][:])
pdw_pw = np.array(f['pulse_width_samps'][:])
pdw_pw_secs = np.array(f['pulse_width_secs'][:])
pdw_pp = f['pulse_power'][:]
pdw_np = f['noise_power'][:]
pdw_pf = f['freq_start'][:]
pdw_toa_course = f['toa_course'][:]
pdw_toa_fine = f['toa_fine'][:]

print(pdw_pw)
print(pdw_pw)
print(pdw_pw_secs)
Binary file modified examples/test_pdw.hdf5
Binary file not shown.
Loading

0 comments on commit b9a6d2c

Please sign in to comment.