Skip to content

Commit

Permalink
Add I/Q view (#1007)
Browse files Browse the repository at this point in the history
  • Loading branch information
andynoack authored Oct 14, 2022
1 parent 6ae113d commit a4f8db4
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 28 deletions.
19 changes: 12 additions & 7 deletions data/ui/signal_frame.ui
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@
</font>
</property>
<property name="text">
<string>Signal View:</string>
<string>Signal view:</string>
</property>
</widget>
</item>
Expand Down Expand Up @@ -282,7 +282,7 @@
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For &lt;span style=&quot; font-weight:600;&quot;&gt;higher order&lt;/span&gt; modulations (&amp;gt; 1 Bits/Symbol), there are &lt;span style=&quot; font-weight:600;&quot;&gt;multiple&lt;/span&gt; centers. We assume that the &lt;span style=&quot; font-weight:600;&quot;&gt;spacing&lt;/span&gt; between all possible symbols is &lt;span style=&quot; font-weight:600;&quot;&gt;constant&lt;/span&gt;. Therefore you configure the spacing between centers.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Center Spacing:</string>
<string>Center spacing:</string>
</property>
</widget>
</item>
Expand Down Expand Up @@ -351,7 +351,7 @@
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;This is the error tolerance for determining the &lt;span style=&quot; font-weight:600;&quot;&gt;pulse lengths&lt;/span&gt; in the demodulated signal.&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:400; font-style:italic;&quot;&gt;Example:&lt;/span&gt; Say, we are reading a ones pulse and the tolerance value was set to 5. Then 5 errors (which must follow sequentially) are accepted.&lt;/p&gt;&lt;p&gt;Tune this value if you have &lt;span style=&quot; font-weight:600;&quot;&gt;spiky data&lt;/span&gt; after demodulation.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Error Tolerance:</string>
<string>Error tolerance:</string>
</property>
</widget>
</item>
Expand Down Expand Up @@ -405,7 +405,7 @@
</sizepolicy>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Choose the view of your signal. Analog, Demodulated or Spectrogram.&lt;/p&gt;&lt;p&gt;The quadrature demodulation uses a &lt;span style=&quot; font-weight:600;&quot;&gt;threshold of magnitudes,&lt;/span&gt; to &lt;span style=&quot; font-weight:600;&quot;&gt;suppress noise&lt;/span&gt;. All samples with a magnitude lower than this threshold will be eliminated after demodulation.&lt;/p&gt;&lt;p&gt;Tune this value by selecting a &lt;span style=&quot; font-style:italic;&quot;&gt;noisy area&lt;/span&gt; and mark it as noise using &lt;span style=&quot; font-weight:600;&quot;&gt;context menu&lt;/span&gt;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Choose the view of your signal. Analog, Demodulated, Spectrogram or I/Q view.&lt;/p&gt;&lt;p&gt;The quadrature demodulation uses a &lt;span style=&quot; font-weight:600;&quot;&gt;threshold of magnitudes,&lt;/span&gt; to &lt;span style=&quot; font-weight:600;&quot;&gt;suppress noise&lt;/span&gt;. All samples with a magnitude lower than this threshold will be eliminated after demodulation.&lt;/p&gt;&lt;p&gt;Tune this value by selecting a &lt;span style=&quot; font-style:italic;&quot;&gt;noisy area&lt;/span&gt; and mark it as noise using &lt;span style=&quot; font-weight:600;&quot;&gt;context menu&lt;/span&gt;.&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Signal colors&lt;/span&gt;:&lt;br/&gt;I =&amp;gt; &lt;span style=&quot; font-weight:600; color:#3232e1;&quot;&gt;blue&lt;/span&gt;&lt;br/&gt;Q =&amp;gt; &lt;span style=&quot; font-weight:600;&quot;&gt;black&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<item>
<property name="text">
Expand All @@ -422,6 +422,11 @@
<string>Spectrogram</string>
</property>
</item>
<item>
<property name="text">
<string>I/Q view</string>
</property>
</item>
</widget>
</item>
<item row="2" column="1">
Expand Down Expand Up @@ -545,7 +550,7 @@
<string>If this is set to true, your selected protocol bits will show up in the signal view, and vice versa.</string>
</property>
<property name="text">
<string>Sync Selection</string>
<string>Sync selection</string>
</property>
<property name="checked">
<bool>true</bool>
Expand Down Expand Up @@ -574,7 +579,7 @@
If you want your protocol to be better separated, edit the PauseLen using right-click menu from a selection in SignalView or ProtocolView.</string>
</property>
<property name="text">
<string>Show Signal as</string>
<string>Show data as</string>
</property>
</widget>
</item>
Expand Down Expand Up @@ -660,7 +665,7 @@ If you want your protocol to be better separated, edit the PauseLen using right-
<item row="20" column="0">
<widget class="QLabel" name="labelFFTWindowSize">
<property name="text">
<string>FFT Window Size:</string>
<string>FFT window size:</string>
</property>
</widget>
</item>
Expand Down
4 changes: 2 additions & 2 deletions src/urh/controller/widgets/SignalFrame.py
Original file line number Diff line number Diff line change
Expand Up @@ -685,8 +685,8 @@ def on_noise_threshold_changed(self):
self.ui.spinBoxNoiseTreshold.setValue(self.signal.noise_threshold_relative)
minimum = self.signal.noise_min_plot
maximum = self.signal.noise_max_plot
if self.ui.cbSignalView.currentIndex() == 0:
# Draw Noise only in Analog View
if self.ui.cbSignalView.currentIndex() == 0 or self.ui.cbSignalView.currentIndex() == 3:
# Draw Noise only in analog and I/Q view
self.ui.gvSignal.scene().draw_noise_area(minimum, maximum - minimum)

@pyqtSlot(int)
Expand Down
2 changes: 2 additions & 0 deletions src/urh/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ def get_qt_settings_filename():
TRANSPARENT_COLOR = QColor(Qt.transparent)

LINECOLOR = QColor.fromRgb(225, 225, 225)
LINECOLOR_I = QColor.fromRgb(50, 50, 225)
LINECOLOR_Q = QColor.fromRgb(55, 53, 53)
BGCOLOR = QColor.fromRgb(55, 53, 53)
AXISCOLOR = QColor.fromRgb(200, 200, 200, 100)
ARROWCOLOR = QColor.fromRgb(204, 120, 50)
Expand Down
7 changes: 7 additions & 0 deletions src/urh/signalprocessing/Signal.py
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,13 @@ def real_plot_data(self):
except AttributeError:
return np.zeros(0, dtype=np.float32)

@property
def imag_plot_data(self):
try:
return self.iq_array.imag
except AttributeError:
return np.zeros(0, dtype=np.float32)

@property
def changed(self) -> bool:
"""
Expand Down
29 changes: 21 additions & 8 deletions src/urh/ui/painting/SceneManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,12 @@ def plot_data(self, value):

@property
def num_samples(self):
if isinstance(self.plot_data, list):
return len(self.plot_data[0])
return len(self.plot_data)

def show_scene_section(self, x1: float, x2: float, subpath_ranges=None, colors=None):
"""
:param x1: start of section to show
:param x2: end of section to show
:param subpath_ranges: for coloring subpaths
Expand All @@ -44,12 +45,21 @@ def show_scene_section(self, x1: float, x2: float, subpath_ranges=None, colors=N
start, end = self.__limit_value(x1), self.__limit_value(x2)

if end > start:
paths = path_creator.create_path(self.plot_data, start=start, end=end,
subpath_ranges=subpath_ranges)
self.set_path(paths, colors=colors)

def set_path(self, paths: list, colors=None):
self.clear_path()
if isinstance(self.plot_data, list):
paths_i = path_creator.create_path(self.plot_data[0], start=start, end=end,
subpath_ranges=subpath_ranges)
paths_q = path_creator.create_path(self.plot_data[1], start=start, end=end,
subpath_ranges=subpath_ranges)
self.set_path(paths_i, colors=[settings.LINECOLOR_I] * len(paths_i))
self.set_path(paths_q, colors=[settings.LINECOLOR_Q] * len(paths_q), run_clear_path=False)
else:
paths = path_creator.create_path(self.plot_data, start=start, end=end,
subpath_ranges=subpath_ranges)
self.set_path(paths, colors=colors)

def set_path(self, paths: list, colors=None, run_clear_path=True):
if run_clear_path:
self.clear_path()
colors = [settings.LINECOLOR] * len(paths) if colors is None else colors
assert len(paths) == len(colors)
for path, color in zip(paths, colors):
Expand All @@ -67,7 +77,10 @@ def init_scene(self):
if self.num_samples == 0:
return

minimum, maximum = IQArray.min_max_for_dtype(self.plot_data.dtype)
if isinstance(self.plot_data, list):
minimum, maximum = IQArray.min_max_for_dtype(self.plot_data[0].dtype)
else:
minimum, maximum = IQArray.min_max_for_dtype(self.plot_data.dtype)
self.scene.setSceneRect(0, minimum, self.num_samples, maximum - minimum)
self.scene.setBackgroundBrush(settings.BGCOLOR)

Expand Down
13 changes: 10 additions & 3 deletions src/urh/ui/painting/SignalSceneManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,24 @@ class SignalSceneManager(SceneManager):
def __init__(self, signal: Signal, parent):
super().__init__(parent)
self.signal = signal
self.scene_type = 0 # 0 = Analog Signal, 1 = QuadDemodView
self.scene_type = 0 # 0 = Analog Signal, 1 = QuadDemodView, 2 = Spectogram, 3 = I/Q view
self.mod_type = "ASK"

def show_scene_section(self, x1: float, x2: float, subpath_ranges=None, colors=None):
self.plot_data = self.signal.real_plot_data if self.scene_type == 0 else self.signal.qad
if self.scene_type == 0:
self.plot_data = self.signal.real_plot_data
elif self.scene_type == 3:
self.plot_data = [self.signal.imag_plot_data, self.signal.real_plot_data]
else:
self.plot_data = self.signal.qad
super().show_scene_section(x1, x2, subpath_ranges=subpath_ranges, colors=colors)

def init_scene(self):
if self.scene_type == 0:
# Ensure real plot has same y Axis
self.plot_data = self.signal.real_plot_data
elif self.scene_type == 3:
self.plot_data = [self.signal.imag_plot_data, self.signal.real_plot_data]
else:
self.plot_data = self.signal.qad

Expand All @@ -28,7 +35,7 @@ def init_scene(self):

self.line_item.setLine(0, 0, 0, 0) # Hide Axis

if self.scene_type == 0:
if self.scene_type == 0 or self.scene_type == 3:
self.scene.draw_noise_area(self.signal.noise_min_plot, self.signal.noise_max_plot - self.signal.noise_min_plot)
else:
self.scene.draw_sep_area(-self.signal.center_thresholds)
Expand Down
Loading

0 comments on commit a4f8db4

Please sign in to comment.