Compare commits
No commits in common. "e5a3d327e5bf37c1acac9ec72f5d0b0cad1fb927" and "9a304faa00b3aaddb79149845ec7e8a6af55946b" have entirely different histories.
e5a3d327e5
...
9a304faa00
|
|
@ -414,18 +414,12 @@ Device selection (``--device``) is optional if only one device is detected. Exac
|
|||
ria view capture.npy --show --no-save
|
||||
ria view old.npy --legacy --type simple
|
||||
ria view recordings\qam64_35.npy --type simple
|
||||
ria view recordings\qam64_35.npy --type full
|
||||
|
||||
.. figure:: ../images/recordings/qam64_35.png
|
||||
.. figure:: ../images/qam64_35.png
|
||||
:alt: Example output of ria view recordings\qam64_35.npy --type simple
|
||||
|
||||
Output of ``ria view recordings\qam64_35.npy --type simple``
|
||||
|
||||
.. figure:: ../images/recordings/qam64_35-full.png
|
||||
:alt: Example output of ria view recordings\qam64_35.npy --type full
|
||||
|
||||
Output of ``ria view recordings\qam64_35.npy --type full``
|
||||
|
||||
|
||||
.. _cmd-annotate:
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
Data Package (ria_toolkit_oss.data)
|
||||
=======================================
|
||||
Datatypes Package (ria_toolkit_oss.data)
|
||||
=============================================
|
||||
|
||||
.. |br| raw:: html
|
||||
|
||||
|
|
@ -3,12 +3,11 @@ import os
|
|||
import textwrap
|
||||
from typing import Optional
|
||||
|
||||
import matplotlib
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
from matplotlib import gridspec, ticker
|
||||
from matplotlib import gridspec
|
||||
from matplotlib.patches import Patch
|
||||
from PIL import Image, UnidentifiedImageError
|
||||
from PIL import Image
|
||||
from scipy.fft import fft, fftshift
|
||||
from scipy.signal import spectrogram
|
||||
from scipy.signal.windows import hann
|
||||
|
|
@ -186,7 +185,7 @@ def view_sig(
|
|||
logo: Optional[bool] = True,
|
||||
dark: Optional[bool] = True,
|
||||
spines: Optional[bool] = False,
|
||||
title_fontsize: Optional[int] = 25,
|
||||
title_fontsize: Optional[int] = 35,
|
||||
subtitle_fontsize: Optional[int] = 15,
|
||||
) -> None:
|
||||
"""
|
||||
|
|
@ -231,24 +230,11 @@ def view_sig(
|
|||
complex_signal = recording.data[0]
|
||||
sample_rate, center_frequency, _ = extract_metadata_fields(recording.metadata)
|
||||
|
||||
subplot_height = 3 * (plot_spectrogram) + 2 * (iq + frequency) + 3 * (constellation or metadata or logo)
|
||||
subplot_height = 2 * (plot_spectrogram + iq + frequency) + 3 * (constellation or metadata or logo)
|
||||
subplot_width = max((constellation + metadata or 1), logo * 3)
|
||||
|
||||
if dark:
|
||||
plt.style.use("dark_background")
|
||||
matplotlib.rcParams.update({
|
||||
"figure.facecolor": "#161616",
|
||||
"axes.facecolor": "#161616",
|
||||
"savefig.facecolor": "#161616",
|
||||
"savefig.edgecolor": "#161616",
|
||||
"font.size": 10,
|
||||
"axes.titlesize": 15,
|
||||
"axes.labelsize": 10,
|
||||
"xtick.labelsize": 10,
|
||||
"ytick.labelsize": 10,
|
||||
"legend.frameon": False,
|
||||
"legend.facecolor": "none",
|
||||
})
|
||||
logo_path = os.path.dirname(__file__) + "/graphics/Qoherent-logo-white-transparent.png"
|
||||
else:
|
||||
plt.style.use("default")
|
||||
|
|
@ -266,8 +252,8 @@ def view_sig(
|
|||
plot_x_indx = 0
|
||||
|
||||
if plot_spectrogram:
|
||||
spec_ax = plt.subplot(gs[plot_y_indx : plot_y_indx + 3, :])
|
||||
plot_y_indx = plot_y_indx + 3
|
||||
spec_ax = plt.subplot(gs[plot_y_indx : plot_y_indx + 2, :])
|
||||
plot_y_indx = plot_y_indx + 2
|
||||
fft_size = get_fft_size(plot_length=plot_length)
|
||||
|
||||
_, t_spec, Sxx = spectrogram(
|
||||
|
|
@ -294,12 +280,7 @@ def view_sig(
|
|||
)
|
||||
|
||||
set_spines(spec_ax, spines)
|
||||
spec_ax.set_title("Spectrogram", loc="left", fontsize=subtitle_fontsize)
|
||||
spec_ax.set_xlabel("Time (s)")
|
||||
spec_ax.set_ylabel("Frequency (MHz)")
|
||||
spec_ax.yaxis.set_major_formatter(
|
||||
ticker.FuncFormatter(lambda x, _: f"{x / 1e6:.1f}")
|
||||
)
|
||||
spec_ax.set_title("Spectrogram", loc="center", fontsize=subtitle_fontsize)
|
||||
|
||||
if iq:
|
||||
iq_ax = plt.subplot(gs[plot_y_indx : plot_y_indx + 2, :])
|
||||
|
|
@ -310,13 +291,12 @@ def view_sig(
|
|||
|
||||
iq_ax.plot(t, plot_iq.real, color=COLORS["purple"], linewidth=0.6, alpha=0.8, label="I")
|
||||
iq_ax.plot(t, plot_iq.imag, color=COLORS["magenta"], linewidth=0.6, alpha=0.8, label="Q")
|
||||
iq_ax.grid(True, alpha=0.2, linewidth=0.5)
|
||||
iq_ax.grid(False)
|
||||
|
||||
iq_ax.set_ylabel("Amplitude")
|
||||
iq_ax.set_xlim([min(t), max(t)])
|
||||
iq_ax.set_xlabel("Time (s)")
|
||||
iq_ax.set_title("IQ Sample Plot", loc="left", fontsize=subtitle_fontsize)
|
||||
iq_ax.legend(loc="upper right", fontsize=10)
|
||||
iq_ax.set_title("IQ Sample Plot", fontsize=subtitle_fontsize)
|
||||
set_spines(iq_ax, spines)
|
||||
|
||||
if frequency:
|
||||
|
|
@ -330,12 +310,10 @@ def view_sig(
|
|||
# Convert to dB
|
||||
spectrum_db = 20 * np.log10(spectrum + 1e-12) # 20*log for magnitude
|
||||
|
||||
freqs = (np.linspace(-sample_rate / 2, sample_rate / 2, len(complex_signal[:plot_length])) + center_frequency) / 1e6
|
||||
freqs = np.linspace(-sample_rate / 2, sample_rate / 2, len(complex_signal[:plot_length])) + center_frequency
|
||||
freq_ax.plot(freqs, spectrum_db, color=COLORS["accent"], linewidth=0.8)
|
||||
freq_ax.set_xlabel("Frequency (MHz)")
|
||||
freq_ax.set_ylabel("Magnitude (dB)")
|
||||
freq_ax.grid(True, alpha=0.2, linewidth=0.5)
|
||||
freq_ax.set_title("Frequency Spectrum (Windowed FFT)", loc="left", fontsize=subtitle_fontsize)
|
||||
freq_ax.set_title("Frequency Spectrum (Windowed FFT)", fontsize=subtitle_fontsize)
|
||||
set_spines(freq_ax, spines)
|
||||
|
||||
if constellation:
|
||||
|
|
@ -348,7 +326,7 @@ def view_sig(
|
|||
const_ax.set_ylim([-1 * dimension, dimension])
|
||||
const_ax.set_xlabel("In-phase (I)")
|
||||
const_ax.set_ylabel("Quadrature (Q)")
|
||||
const_ax.set_title("Constellation", loc="left", fontsize=subtitle_fontsize)
|
||||
const_ax.set_title("Constellation", fontsize=subtitle_fontsize)
|
||||
const_ax.set_aspect("equal")
|
||||
|
||||
if not spines:
|
||||
|
|
@ -397,8 +375,8 @@ def view_sig(
|
|||
image = Image.open(logo_path) # Open the PNG image using PIL
|
||||
logo_ax.imshow(image)
|
||||
|
||||
except (FileNotFoundError, UnidentifiedImageError, OSError) as exc:
|
||||
print(f"Warning, could not load logo image: {logo_path}. Reason: {exc}")
|
||||
except FileNotFoundError:
|
||||
print(f"Warning, {logo_path} not found.")
|
||||
|
||||
fig.subplots_adjust(
|
||||
left=0.1, # Left margin
|
||||
|
|
|
|||
|
|
@ -119,19 +119,24 @@ def setup_style(*, labels_mode: bool = False, compact_mode: bool = False) -> Non
|
|||
label_font = 14
|
||||
else:
|
||||
base_font = 10
|
||||
title_font = 15
|
||||
title_font = 12
|
||||
label_font = 10
|
||||
|
||||
matplotlib.rcParams.update(
|
||||
{
|
||||
"figure.facecolor": "#161616",
|
||||
"axes.facecolor": "#161616",
|
||||
"savefig.facecolor": "#161616",
|
||||
"savefig.edgecolor": "#161616",
|
||||
"figure.facecolor": "#0f172a",
|
||||
"axes.facecolor": "#1e293b",
|
||||
"axes.edgecolor": COLORS["muted"],
|
||||
"axes.labelcolor": COLORS["light"],
|
||||
"text.color": COLORS["light"],
|
||||
"xtick.color": COLORS["muted"],
|
||||
"ytick.color": COLORS["muted"],
|
||||
"grid.color": COLORS["muted"],
|
||||
"grid.alpha": 0.3,
|
||||
"font.size": base_font,
|
||||
"axes.titlesize": title_font,
|
||||
"axes.labelsize": label_font,
|
||||
"figure.titlesize": title_font + 4,
|
||||
"figure.titlesize": title_font + 2,
|
||||
"legend.frameon": False,
|
||||
"legend.facecolor": "none",
|
||||
"xtick.labelsize": base_font,
|
||||
|
|
@ -189,7 +194,7 @@ def view_simple_sig(
|
|||
constellation_mode: Optional[bool] = False,
|
||||
labels_mode: Optional[bool] = False,
|
||||
slice: Optional[tuple] = None,
|
||||
title: Optional[str] = "Signal Plot",
|
||||
title: Optional[str] = "Signal",
|
||||
):
|
||||
"""
|
||||
Create a simple plot of various signal visualizations as a png or svg image.
|
||||
|
|
@ -232,7 +237,7 @@ def view_simple_sig(
|
|||
spec_signal = signal
|
||||
|
||||
if compact_mode:
|
||||
fig, (ax2, ax1) = plt.subplots(2, 1, figsize=(12, 6), gridspec_kw={"height_ratios": [5, 1]})
|
||||
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 6), gridspec_kw={"height_ratios": [1, 5]})
|
||||
show_title = False
|
||||
show_labels = False
|
||||
ax_constellation = ax_psd = None
|
||||
|
|
@ -248,24 +253,25 @@ def view_simple_sig(
|
|||
ax_psd = None
|
||||
else:
|
||||
if constellation_mode:
|
||||
fig, ((ax2, ax1), (ax3, ax4)) = plt.subplots(2, 2, figsize=(16, 12))
|
||||
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(16, 12))
|
||||
ax_constellation, ax_psd = ax3, ax4
|
||||
else:
|
||||
fig, (ax2, ax1) = plt.subplots(2, 1, figsize=(14, 10))
|
||||
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(14, 10))
|
||||
ax_constellation = ax_psd = None
|
||||
show_title = True
|
||||
show_labels = labels_mode
|
||||
|
||||
if show_title:
|
||||
fig.suptitle(title, fontsize=25)
|
||||
fig.patch.set_facecolor(matplotlib.rcParams["figure.facecolor"])
|
||||
fig.suptitle(title, fontsize=16, color=COLORS["light"], y=0.96)
|
||||
fig.patch.set_facecolor("#0f172a")
|
||||
|
||||
total_duration_s = len(signal) / sample_rate_hz if sample_rate_hz else 0.0
|
||||
t_s = np.linspace(0, total_duration_s, len(display_signal)) if len(display_signal) else np.array([])
|
||||
|
||||
ax1.plot(t_s, display_signal.real, color=COLORS["purple"], linewidth=0.6, alpha=0.8, label="I")
|
||||
ax1.plot(t_s, display_signal.imag, color=COLORS["magenta"], linewidth=0.6, alpha=0.8, label="Q")
|
||||
ax1.grid(True, alpha=0.2, linewidth=0.5)
|
||||
ax1.plot(t_s, display_signal.real, color=COLORS["purple"], linewidth=0.8, alpha=0.8, label="I")
|
||||
ax1.plot(t_s, display_signal.imag, color=COLORS["magenta"], linewidth=0.8, alpha=0.8, label="Q")
|
||||
ax1.set_xlim(0, total_duration_s)
|
||||
ax1.grid(True, alpha=0.3)
|
||||
|
||||
nfft, overlap = _get_nfft_size(signal=signal, fast_mode=fast_mode)
|
||||
|
||||
|
|
@ -279,7 +285,7 @@ def view_simple_sig(
|
|||
)
|
||||
|
||||
ax2.set_ylim(center_freq_hz - sample_rate_hz / 2, center_freq_hz + sample_rate_hz / 2)
|
||||
ax1.set_xlim(ax2.get_xlim())
|
||||
ax2.set_xlim(0, total_duration_s)
|
||||
|
||||
if show_labels:
|
||||
if horizontal_mode:
|
||||
|
|
@ -288,26 +294,20 @@ def view_simple_sig(
|
|||
ax2.set_xlabel("Time (s)")
|
||||
|
||||
ax1.set_ylabel("Amplitude")
|
||||
ax1.set_title(f"IQ Sample Plot - {sdr} SDR", loc="left", pad=10, fontsize=15)
|
||||
ax1.legend(loc="upper right", fontsize=10)
|
||||
ax1.set_title(f"Time Series - {sdr} SDR", loc="left", pad=10)
|
||||
ax1.legend(loc="upper right")
|
||||
|
||||
ax2.set_ylabel("Frequency (MHz)")
|
||||
ax2.set_ylabel("Frequency (Hz)")
|
||||
ax2.set_title(
|
||||
f"Spectrogram - {center_freq_hz / 1e6:.1f} MHz ± {sample_rate_hz / 2e6:.1f} MHz", loc="left", pad=10, fontsize=15
|
||||
)
|
||||
ax2.yaxis.set_major_formatter(
|
||||
matplotlib.ticker.FuncFormatter(lambda x, _: f"{x / 1e6:.1f}")
|
||||
f"Spectrogram - {center_freq_hz / 1e6:.1f} MHz ± {sample_rate_hz / 2e6:.1f} MHz", loc="left", pad=10
|
||||
)
|
||||
yticks = ax2.get_yticks()
|
||||
ax2.set_yticklabels([f"{y / 1e6:.1f}" for y in yticks])
|
||||
elif not compact_mode:
|
||||
ax1.set_title("IQ Sample Plot", loc="left", pad=10, fontsize=15)
|
||||
ax1.legend(loc="upper right", fontsize=10)
|
||||
ax1.set_title("Time Series", loc="left", pad=10)
|
||||
ax1.legend(loc="upper right", fontsize=8)
|
||||
|
||||
ax2.set_xlabel("Time (s)")
|
||||
ax2.set_ylabel("Frequency (MHz)")
|
||||
ax2.set_title("Spectrogram", loc="left", pad=10, fontsize=15)
|
||||
ax2.yaxis.set_major_formatter(
|
||||
matplotlib.ticker.FuncFormatter(lambda x, _: f"{x / 1e6:.1f}")
|
||||
)
|
||||
ax2.set_title("Spectrogram", loc="left", pad=10)
|
||||
|
||||
_add_annotations(
|
||||
annotations=annotations,
|
||||
|
|
@ -339,8 +339,8 @@ def view_simple_sig(
|
|||
)
|
||||
ax_constellation.set_xlabel("In-phase (I)")
|
||||
ax_constellation.set_ylabel("Quadrature (Q)")
|
||||
ax_constellation.set_title("Constellation", loc="left", fontsize=15)
|
||||
ax_constellation.grid(True, alpha=0.2, linewidth=0.5)
|
||||
ax_constellation.set_title("Constellation")
|
||||
ax_constellation.grid(True, alpha=0.3)
|
||||
ax_constellation.set_aspect("equal")
|
||||
|
||||
if ax_psd is not None:
|
||||
|
|
@ -351,11 +351,11 @@ def view_simple_sig(
|
|||
freqs = freqs + center_freq_hz
|
||||
spectrum_db = 10 * np.log10(spectrum + 1e-12)
|
||||
|
||||
ax_psd.plot(freqs / 1e6, spectrum_db, color=COLORS["accent"], linewidth=0.8)
|
||||
ax_psd.plot(freqs / 1e6, spectrum_db, color=COLORS["accent"], linewidth=1.0)
|
||||
ax_psd.set_xlabel("Frequency (MHz)")
|
||||
ax_psd.set_ylabel("Power (dB)")
|
||||
ax_psd.set_title("Power Spectral Density", loc="left", fontsize=15)
|
||||
ax_psd.grid(True, alpha=0.2, linewidth=0.5)
|
||||
ax_psd.set_title("Power Spectral Density")
|
||||
ax_psd.grid(True, alpha=0.3)
|
||||
|
||||
if compact_mode:
|
||||
ax1.set_xticks([])
|
||||
|
|
@ -367,20 +367,13 @@ def view_simple_sig(
|
|||
else:
|
||||
plt.tight_layout()
|
||||
if show_title:
|
||||
plt.subplots_adjust(top=0.9)
|
||||
plt.subplots_adjust(top=0.92)
|
||||
|
||||
if saveplot:
|
||||
output_path, extension = set_path(output_path=output_path)
|
||||
dpi_value = _set_dpi(fast_mode=fast_mode, labels_mode=labels_mode, extension=extension)
|
||||
|
||||
plt.savefig(
|
||||
output_path,
|
||||
dpi=dpi_value,
|
||||
bbox_inches="tight",
|
||||
pad_inches=0.3,
|
||||
facecolor=matplotlib.rcParams["savefig.facecolor"],
|
||||
edgecolor=matplotlib.rcParams["savefig.edgecolor"],
|
||||
)
|
||||
plt.savefig(output_path, dpi=dpi_value, bbox_inches="tight", facecolor="#0f172a", edgecolor="none")
|
||||
print(f"Saved signal plot to {output_path}")
|
||||
return output_path
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user