From 5cfced8855414e54d9e2d10733dce1bb71d04d29 Mon Sep 17 00:00:00 2001 From: fordg1 Date: Tue, 31 Mar 2026 15:16:32 -0400 Subject: [PATCH] Fix merge conflicts and port all imports from utils to ria_toolkit_oss Resolves unresolved merge conflict markers left in committed files across the annotations, view, data, and CLI packages. Updates all remaining imports from the old utils.* namespace to ria_toolkit_oss.datatypes, ria_toolkit_oss.io, and ria_toolkit_oss.view equivalents. --- src/ria_toolkit_oss/annotations/__init__.py | 7 - .../annotations/annotation_transforms.py | 4 - .../annotations/cusum_annotator.py | 8 -- .../annotations/energy_detector.py | 15 +-- .../annotations/parallel_signal_separator.py | 23 ---- .../annotations/qualify_slice.py | 4 - .../annotations/signal_isolation.py | 5 - .../annotations/threshold_qualifier.py | 121 ------------------ src/ria_toolkit_oss/data/recording.py | 28 ++-- .../frequency_translation/upconversion.py | 4 +- src/ria_toolkit_oss/view/recording.py | 8 +- src/ria_toolkit_oss/view/view_signal.py | 33 +---- .../view/view_signal_simple.py | 4 +- .../ria_toolkit_oss/annotate.py | 86 ------------- .../ria_toolkit_oss/commands.py | 4 +- 15 files changed, 26 insertions(+), 328 deletions(-) diff --git a/src/ria_toolkit_oss/annotations/__init__.py b/src/ria_toolkit_oss/annotations/__init__.py index d2d5806..ebb3d10 100644 --- a/src/ria_toolkit_oss/annotations/__init__.py +++ b/src/ria_toolkit_oss/annotations/__init__.py @@ -1,4 +1,3 @@ -<<<<<<< HEAD """ The annotations package contains tools and utilities for creating, managing, and processing annotations. @@ -54,9 +53,3 @@ from .parallel_signal_separator import ( from .qualify_slice import qualify_slice_from_annotations from .signal_isolation import isolate_signal from .threshold_qualifier import threshold_qualifier -======= -from .cusum_annotator import annotate_with_cusum -from .energy_detector import detect_signals_energy -from .parallel_signal_separator import split_recording_annotations -from .threshold_qualifier import threshold_qualifier ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 diff --git a/src/ria_toolkit_oss/annotations/annotation_transforms.py b/src/ria_toolkit_oss/annotations/annotation_transforms.py index d91e13d..47300c1 100644 --- a/src/ria_toolkit_oss/annotations/annotation_transforms.py +++ b/src/ria_toolkit_oss/annotations/annotation_transforms.py @@ -1,8 +1,4 @@ -<<<<<<< HEAD -from utils.data.annotation import Annotation -======= from ria_toolkit_oss.datatypes.annotation import Annotation ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 # TODO figure out how to transfer labels in the merge case diff --git a/src/ria_toolkit_oss/annotations/cusum_annotator.py b/src/ria_toolkit_oss/annotations/cusum_annotator.py index 9837e07..d37186c 100644 --- a/src/ria_toolkit_oss/annotations/cusum_annotator.py +++ b/src/ria_toolkit_oss/annotations/cusum_annotator.py @@ -3,11 +3,7 @@ from typing import Optional import numpy as np -<<<<<<< HEAD -from utils.data import Annotation, Recording -======= from ria_toolkit_oss.datatypes import Annotation, Recording ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 def annotate_with_cusum( @@ -28,11 +24,7 @@ def annotate_with_cusum( changes between a low and high amplitude. :param recording: A ``Recording`` object to annotate. -<<<<<<< HEAD - :type recording: ``utils.data.Recording`` -======= :type recording: ``ria_toolkit_oss.datatypes.Recording`` ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 :param label: Label for the detected segments. :type label: str :param window_size: The length (in samples) of the moving average window. diff --git a/src/ria_toolkit_oss/annotations/energy_detector.py b/src/ria_toolkit_oss/annotations/energy_detector.py index 9706532..109fe6e 100644 --- a/src/ria_toolkit_oss/annotations/energy_detector.py +++ b/src/ria_toolkit_oss/annotations/energy_detector.py @@ -11,11 +11,7 @@ from typing import Tuple import numpy as np from scipy.signal import filtfilt -<<<<<<< HEAD -from utils.data import Annotation, Recording -======= from ria_toolkit_oss.datatypes import Annotation, Recording ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 def detect_signals_energy( @@ -77,13 +73,8 @@ def detect_signals_energy( **Example**:: -<<<<<<< HEAD - >>> from utils.io import load_recording - >>> from utils.annotations import detect_signals_energy -======= >>> from ria.io import load_recording >>> from ria_toolkit_oss.annotations import detect_signals_energy ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 >>> recording = load_recording("capture.sigmf") >>> # Detect with NBW frequency bounds (default, best for real signals) @@ -239,7 +230,7 @@ def calculate_nominal_bandwidth( **Example**:: - >>> from utils.annotations import calculate_nominal_bandwidth + >>> from ria_toolkit_oss.annotations import calculate_nominal_bandwidth >>> nbw, center = calculate_nominal_bandwidth(signal, sampling_rate=10e6) >>> print(f"NBW: {nbw/1e6:.3f} MHz, Center: {center/1e6:.3f} MHz") """ @@ -356,11 +347,7 @@ def annotate_with_obw( **Example**:: -<<<<<<< HEAD - >>> from utils.annotations import annotate_with_obw -======= >>> from ria_toolkit_oss.annotations import annotate_with_obw ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 >>> annotated = annotate_with_obw(recording, label="signal_obw") """ signal = recording.data[0] diff --git a/src/ria_toolkit_oss/annotations/parallel_signal_separator.py b/src/ria_toolkit_oss/annotations/parallel_signal_separator.py index 6a412ed..957cf58 100644 --- a/src/ria_toolkit_oss/annotations/parallel_signal_separator.py +++ b/src/ria_toolkit_oss/annotations/parallel_signal_separator.py @@ -38,11 +38,7 @@ sub-annotations. Example: Two WiFi channels captured simultaneously: -<<<<<<< HEAD - >>> from utils.annotations import find_spectral_components -======= >>> from ria_toolkit_oss.annotations import find_spectral_components ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 >>> # Detect the two distinct channels (returns relative frequencies) >>> components = find_spectral_components(signal, sampling_rate=20e6) >>> print(f"Found {len(components)} components") @@ -59,11 +55,7 @@ import numpy as np from scipy import ndimage from scipy import signal as scipy_signal -<<<<<<< HEAD -from utils.data import Annotation, Recording -======= from ria_toolkit_oss.datatypes import Annotation, Recording ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 def find_spectral_components( @@ -119,13 +111,8 @@ def find_spectral_components( **Example**:: -<<<<<<< HEAD - >>> from utils.io import load_recording - >>> from utils.annotations import find_spectral_components -======= >>> from ria.io import load_recording >>> from ria_toolkit_oss.annotations import find_spectral_components ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 >>> recording = load_recording("capture.sigmf") >>> segment = recording.data[0][start:end] >>> # Components in relative (baseband) frequency @@ -254,13 +241,8 @@ def split_annotation_by_components( **Example**:: -<<<<<<< HEAD - >>> from utils.io import load_recording - >>> from utils.annotations import split_annotation_by_components -======= >>> from ria.io import load_recording >>> from ria_toolkit_oss.annotations import split_annotation_by_components ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 >>> recording = load_recording("capture.sigmf") >>> # Original annotation spans multiple channels >>> original = recording.annotations[0] @@ -387,13 +369,8 @@ def split_recording_annotations( **Example**:: -<<<<<<< HEAD - >>> from utils.io import load_recording - >>> from utils.annotations import split_recording_annotations -======= >>> from ria.io import load_recording >>> from ria_toolkit_oss.annotations import split_recording_annotations ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 >>> recording = load_recording("capture.sigmf") >>> # Split all annotations >>> split_rec = split_recording_annotations(recording) diff --git a/src/ria_toolkit_oss/annotations/qualify_slice.py b/src/ria_toolkit_oss/annotations/qualify_slice.py index 08d590b..2336fe5 100644 --- a/src/ria_toolkit_oss/annotations/qualify_slice.py +++ b/src/ria_toolkit_oss/annotations/qualify_slice.py @@ -1,10 +1,6 @@ import numpy as np -<<<<<<< HEAD -from utils.data import Recording -======= from ria_toolkit_oss.datatypes import Recording ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 def qualify_slice_from_annotations(recording: Recording, slice_length: int): diff --git a/src/ria_toolkit_oss/annotations/signal_isolation.py b/src/ria_toolkit_oss/annotations/signal_isolation.py index 255b95b..47852ae 100644 --- a/src/ria_toolkit_oss/annotations/signal_isolation.py +++ b/src/ria_toolkit_oss/annotations/signal_isolation.py @@ -1,13 +1,8 @@ import numpy as np from scipy.signal import butter, lfilter -<<<<<<< HEAD -from utils.data.annotation import Annotation -from utils.data.recording import Recording -======= from ria_toolkit_oss.datatypes.annotation import Annotation from ria_toolkit_oss.datatypes.recording import Recording ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 def isolate_signal(recording: Recording, annotation: Annotation) -> Recording: diff --git a/src/ria_toolkit_oss/annotations/threshold_qualifier.py b/src/ria_toolkit_oss/annotations/threshold_qualifier.py index 7efb541..338f13c 100644 --- a/src/ria_toolkit_oss/annotations/threshold_qualifier.py +++ b/src/ria_toolkit_oss/annotations/threshold_qualifier.py @@ -46,29 +46,17 @@ from typing import Optional import numpy as np -<<<<<<< HEAD -from utils.data import Annotation, Recording - - -def _find_ranges(indices, window_size): -======= from ria_toolkit_oss.datatypes import Annotation, Recording def _find_ranges(indices, max_gap): ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 """ Groups individual indices into continuous temporal ranges. Args: indices: Array of indices where the signal exceeded a threshold. -<<<<<<< HEAD - window_size: Maximum gap allowed between indices to consider them part - of the same range. -======= max_gap: Maximum gap allowed between indices to consider them part of the same range. ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 Returns: A list of (start, stop) tuples representing detected signal segments. @@ -77,30 +65,6 @@ def _find_ranges(indices, max_gap): if len(indices) == 0: return [] -<<<<<<< HEAD - ranges = [] - - start = indices[0] - in_range = False - - for i in range(1, len(indices)): - # If the gap between current and previous index is within window_size, - # keep the range alive. - if indices[i] - indices[i - 1] <= window_size: - if not in_range: - # Start a new range - start = indices[i - 1] - in_range = True - else: - # Gap is too large; close the current range if one was active. - if in_range: - ranges.append((start, indices[i - 1])) - in_range = False - - # Ensure the final segment is captured if the loop ends while in_range. - if in_range: - ranges.append((start, indices[-1])) -======= start = indices[0] prev = indices[0] ranges = [] @@ -112,19 +76,10 @@ def _find_ranges(indices, max_gap): prev = indices[i] ranges.append((start, prev)) ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 return ranges -<<<<<<< HEAD -def threshold_qualifier( - recording: Recording, - threshold: float, - window_size: Optional[int] = 1024, - label: Optional[str] = None, - annotation_type: Optional[str] = "standalone", -======= def _expand_and_filter_ranges( smoothed_power: np.ndarray, initial_ranges: list[tuple[int, int]], @@ -231,7 +186,6 @@ def threshold_qualifier( label: Optional[str] = None, annotation_type: Optional[str] = "standalone", channel: int = 0, ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 ) -> Recording: """ Annotate a recording with bounding boxes for regions above a threshold. @@ -249,27 +203,15 @@ def threshold_qualifier( Args: recording: The Recording object containing IQ or real signal data. threshold: Sensitivity multiplier (0.0 to 1.0) applied to max power. -<<<<<<< HEAD - window_size: Size of the smoothing filter and max gap for merging hits. - label: Custom string label for annotations. - annotation_type: Metadata string for the 'type' field in the annotation. -======= window_size: Size of the smoothing filter in samples. Defaults to 1ms worth of samples. label: Custom string label for annotations. annotation_type: Metadata string for the 'type' field in the annotation. channel: Index of the channel to annotate. Defaults to 0. ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 Returns: A new Recording object populated with detected Annotations. """ # Extract signal and metadata -<<<<<<< HEAD - sample_data = recording.data[0] - sample_rate = recording.metadata["sample_rate"] - center_frequency = recording.metadata.get("center_frequency", 0) - -======= sample_data = recording.data[channel] sample_rate = recording.metadata["sample_rate"] center_frequency = recording.metadata.get("center_frequency", 0) @@ -277,69 +219,11 @@ def threshold_qualifier( if window_size is None: window_size = max(64, int(sample_rate * 0.001)) ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 # --- 1. SIGNAL CONDITIONING --- # Convert to power (Magnitude squared) power_data = np.abs(sample_data) ** 2 smoothing_window = np.ones(window_size) / window_size smoothed_power = np.convolve(power_data, smoothing_window, mode="same") -<<<<<<< HEAD - - # Define thresholds based on the global peak of the smoothed signal - max_power = np.max(smoothed_power) - trigger_val = threshold * max_power # High threshold to trigger detection - boundary_val = (threshold / 2) * max_power # Low threshold to define signal edges - - # --- 2. INITIAL DETECTION --- - # Identify indices that strictly exceed the high trigger - indices = np.where(smoothed_power > trigger_val)[0] - initial_ranges = _find_ranges(indices=indices, window_size=window_size) - - annotations = [] - - threshold_base = min(sample_rate, len(sample_data)) - - for start, stop in initial_ranges: - if (stop - start) < (threshold_base * 0.01): - continue - - # --- 3. HYSTERESIS (Boundary Expansion) --- - # Search backward from 'start' until power drops below the low boundary_val - true_start = start - while true_start > 0 and smoothed_power[true_start] > boundary_val: - true_start -= 1 - - # Search forward from 'stop' until power drops below the low boundary_val - true_stop = stop - while true_stop < len(smoothed_power) - 1 and smoothed_power[true_stop] > boundary_val: - true_stop += 1 - - # --- 4. SPECTRAL ANALYSIS (Frequency Detection) --- - signal_segment = sample_data[true_start:true_stop] - if len(signal_segment) > 0: - fft_data = np.abs(np.fft.fftshift(np.fft.fft(signal_segment))) - fft_freqs = np.fft.fftshift(np.fft.fftfreq(len(signal_segment), 1 / sample_rate)) - - # Determine frequency bounds where spectral energy is > 15% of segment peak - spectral_thresh = np.max(fft_data) * 0.15 - sig_indices = np.where(fft_data > spectral_thresh)[0] - - # Ensure the signal has some spectral width before annotating - if len(sig_indices) < 5: - continue - - if len(sig_indices) > 0: - f_min, f_max = fft_freqs[sig_indices[0]], fft_freqs[sig_indices[-1]] - else: - # Default to middle half of bandwidth if no clear peaks found - f_min, f_max = -sample_rate / 4, sample_rate / 4 - else: - f_min, f_max = -sample_rate / 4, sample_rate / 4 - - # --- 5. ANNOTATION GENERATION --- - if label is None: - label = f"{int(threshold*100)}%" -======= group_gap_samples = _estimate_group_gap(sample_rate) # Define thresholds using peak relative to baseline. @@ -442,7 +326,6 @@ def threshold_qualifier( # --- 5. ANNOTATION GENERATION --- ann_label = label if label is not None else f"{int(threshold*100)}%" ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 # Pack metadata for the UI/Downstream processing comment_data = { @@ -459,11 +342,7 @@ def threshold_qualifier( sample_count=true_stop - true_start, freq_lower_edge=center_frequency + f_min, freq_upper_edge=center_frequency + f_max, -<<<<<<< HEAD - label=label, -======= label=ann_label, ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 comment=json.dumps(comment_data), detail={"generator": "hysteresis_qualifier"}, ) diff --git a/src/ria_toolkit_oss/data/recording.py b/src/ria_toolkit_oss/data/recording.py index 50e03ee..20939bd 100644 --- a/src/ria_toolkit_oss/data/recording.py +++ b/src/ria_toolkit_oss/data/recording.py @@ -12,7 +12,7 @@ from typing import Any, Iterator, Optional import numpy as np from numpy.typing import ArrayLike -from utils.data.annotation import Annotation +from ria_toolkit_oss.datatypes.annotation import Annotation PROTECTED_KEYS = ["rec_id", "timestamp"] @@ -66,7 +66,7 @@ class Recording: **Examples:** >>> import numpy - >>> from utils.data import Recording, Annotation + >>> from ria_toolkit_oss.datatypes import Recording, Annotation >>> # Create an array of complex samples, just 1s in this case. >>> samples = numpy.ones(10000, dtype=numpy.complex64) @@ -305,7 +305,7 @@ class Recording: Create a recording and add metadata: >>> import numpy - >>> from utils.data import Recording + >>> from ria_toolkit_oss.datatypes import Recording >>> >>> samples = numpy.ones(10000, dtype=numpy.complex64) >>> metadata = { @@ -360,7 +360,7 @@ class Recording: Create a recording and update metadata: >>> import numpy - >>> from utils.data import Recording + >>> from ria_toolkit_oss.datatypes import Recording >>> samples = numpy.ones(10000, dtype=numpy.complex64) >>> metadata = { @@ -414,7 +414,7 @@ class Recording: Create a recording and add metadata: >>> import numpy - >>> from utils.data import Recording + >>> from ria_toolkit_oss.datatypes import Recording >>> samples = numpy.ones(10000, dtype=numpy.complex64) >>> metadata = { @@ -455,7 +455,7 @@ class Recording: Create a recording and view it as a plot in a .png image: >>> import numpy - >>> from utils.data import Recording + >>> from ria_toolkit_oss.datatypes import Recording >>> samples = numpy.ones(10000, dtype=numpy.complex64) >>> metadata = { @@ -466,14 +466,14 @@ class Recording: >>> recording = Recording(data=samples, metadata=metadata) >>> recording.view() """ - from utils.view import view_sig + from ria_toolkit_oss.view import view_sig view_sig(recording=self, output_path=output_path, **kwargs) def simple_view(self, **kwargs) -> None: """Create a plot of various signal visualizations as a PNG or SVG image. - :param kwargs: Keyword arguments passed on to utils.view.view_signal_simple.create_plots. + :param kwargs: Keyword arguments passed on to ria_toolkit_oss.view.view_signal_simple.create_plots. :type: dict of keyword arguments **Examples:** @@ -481,7 +481,7 @@ class Recording: Create a recording and view it as a plot in a .png image: >>> import numpy - >>> from utils.data import Recording + >>> from ria_toolkit_oss.datatypes import Recording >>> samples = numpy.ones(10000, dtype=numpy.complex64) >>> metadata = { @@ -492,7 +492,7 @@ class Recording: >>> recording = Recording(data=samples, metadata=metadata) >>> recording.simple_view() """ - from utils.view.view_signal_simple import view_simple_sig + from ria_toolkit_oss.view.view_signal_simple import view_simple_sig view_simple_sig(recording=self, **kwargs) @@ -530,7 +530,7 @@ class Recording: >>> recording = Recording(data=samples, metadata=metadata) >>> recording.view() """ - from utils.io.recording import to_sigmf + from ria_toolkit_oss.io.recording import to_sigmf to_sigmf(filename=filename, path=path, recording=self, overwrite=overwrite) @@ -565,7 +565,7 @@ class Recording: >>> recording = Recording(data=samples, metadata=metadata) >>> recording.to_npy() """ - from utils.io.recording import to_npy + from ria_toolkit_oss.io.recording import to_npy to_npy(recording=self, filename=filename, path=path, overwrite=overwrite) @@ -611,7 +611,7 @@ class Recording: >>> recording = Recording(data=samples, metadata=metadata) >>> recording.to_wav() """ - from utils.io.recording import to_wav + from ria_toolkit_oss.io.recording import to_wav return to_wav( recording=self, @@ -661,7 +661,7 @@ class Recording: >>> recording = Recording(data=samples, metadata=metadata) >>> recording.to_blue() """ - from utils.io.recording import to_blue + from ria_toolkit_oss.io.recording import to_blue return to_blue(recording=self, filename=filename, path=path, data_format=data_format, overwrite=overwrite) diff --git a/src/ria_toolkit_oss/signal/block_generator/frequency_translation/upconversion.py b/src/ria_toolkit_oss/signal/block_generator/frequency_translation/upconversion.py index 18f5464..c0272c3 100644 --- a/src/ria_toolkit_oss/signal/block_generator/frequency_translation/upconversion.py +++ b/src/ria_toolkit_oss/signal/block_generator/frequency_translation/upconversion.py @@ -1,6 +1,6 @@ import numpy as np -from utils.signal.block_generator.block import Block -from utils.signal.block_generator.data_types import DataType +from ria_toolkit_oss.signal.block_generator.block import Block +from ria_toolkit_oss.signal.block_generator.data_types import DataType class FrequencyUpConversion(Block): diff --git a/src/ria_toolkit_oss/view/recording.py b/src/ria_toolkit_oss/view/recording.py index 381f07e..b9c413b 100644 --- a/src/ria_toolkit_oss/view/recording.py +++ b/src/ria_toolkit_oss/view/recording.py @@ -11,7 +11,7 @@ def spectrogram(rec: Recording, thumbnail: bool = False) -> Figure: """Create a spectrogram for the recording. :param rec: Signal to plot. - :type rec: utils.data.Recording + :type rec: ria_toolkit_oss.datatypes.Recording :param thumbnail: Whether to return a small thumbnail version or full plot. :type thumbnail: bool @@ -95,7 +95,7 @@ def iq_time_series(rec: Recording) -> Figure: """Create a time series plot of the real and imaginary parts of signal. :param rec: Signal to plot. - :type rec: utils.data.Recording + :type rec: ria_toolkit_oss.datatypes.Recording :return: Time series plot as a Plotly figure. """ @@ -125,7 +125,7 @@ def frequency_spectrum(rec: Recording) -> Figure: """Create a frequency spectrum plot from the recording. :param rec: Input signal to plot. - :type rec: utils.data.Recording + :type rec: ria_toolkit_oss.datatypes.Recording :return: Frequency spectrum as a Plotly figure. """ @@ -160,7 +160,7 @@ def constellation(rec: Recording) -> Figure: """Create a constellation plot from the recording. :param rec: Input signal to plot. - :type rec: utils.data.Recording + :type rec: ria_toolkit_oss.datatypes.Recording :return: Constellation as a Plotly figure. """ diff --git a/src/ria_toolkit_oss/view/view_signal.py b/src/ria_toolkit_oss/view/view_signal.py index 38b6056..86cfbe7 100644 --- a/src/ria_toolkit_oss/view/view_signal.py +++ b/src/ria_toolkit_oss/view/view_signal.py @@ -13,8 +13,8 @@ from scipy.fft import fft, fftshift from scipy.signal import spectrogram from scipy.signal.windows import hann -from utils.data.recording import Recording -from utils.view.tools import COLORS, decimate, extract_metadata_fields, set_path +from ria_toolkit_oss.datatypes.recording import Recording +from ria_toolkit_oss.view.tools import COLORS, decimate, extract_metadata_fields, set_path def get_fft_size(plot_length): @@ -58,17 +58,6 @@ def view_annotations( sample_rate, center_frequency, _ = extract_metadata_fields(recording.metadata) annotations = recording.annotations -<<<<<<< HEAD - # 2. Setup Color Mapping (No more hardcoded yellow fallback!) - # available_colors = [ - # COLORS.get("magenta", "magenta"), - # COLORS.get("accent", "cyan"), - # COLORS.get("light", "white"), - # "lime", - # ] - - palette = ["#FF00FF", "#00FF00", "#00FFFF", "#FFFF00", "#FF8000"] -======= # 2. Setup Color Mapping available_colors = [ COLORS.get("magenta", "magenta"), @@ -78,7 +67,6 @@ def view_annotations( ] palette = ["#2196F3", "#9C27B0", "#64B5F6", "#7B1FA2", "#5C6BC0", "#CE93D8", "#1565C0", "#7C4DFF"] ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 unique_labels = sorted(list(set(ann.label for ann in annotations if ann.label))) label_to_color = {label: palette[i % len(palette)] for i, label in enumerate(unique_labels)} @@ -87,11 +75,6 @@ def view_annotations( complex_signal, NFFT=256, Fs=sample_rate, Fc=center_frequency, noverlap=128, cmap="twilight" ) -<<<<<<< HEAD - # 4. Draw Annotations - for annotation in annotations: - # --- DEFINING VARIABLES FIRST --- -======= # 4. Draw Annotations (highest threshold % first so lower % renders on top) def _threshold_sort_key(ann): try: @@ -100,21 +83,13 @@ def view_annotations( return 0 for annotation in sorted(annotations, key=_threshold_sort_key, reverse=True): ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 t_start = annotation.sample_start / sample_rate t_width = annotation.sample_count / sample_rate f_start = annotation.freq_lower_edge f_height = annotation.freq_upper_edge - annotation.freq_lower_edge -<<<<<<< HEAD - # Look up the color for this specific label ann_color = label_to_color.get(annotation.label, "gray") - # Draw the Rectangle -======= - ann_color = label_to_color.get(annotation.label, "gray") - ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 rect = plt.Rectangle( (t_start, f_start), t_width, f_height, linewidth=1.5, edgecolor=ann_color, facecolor="none", alpha=0.8 ) @@ -130,11 +105,7 @@ def view_annotations( ax.set_title(title, fontsize=title_fontsize, pad=20) ax.set_xlabel("Time (s)", fontsize=12) ax.set_ylabel("Frequency (MHz)", fontsize=12) -<<<<<<< HEAD - ax.grid(alpha=0.1) # Add faint grid -======= ax.grid(alpha=0.1) ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 output_path, _ = set_path(output_path=output_path) plt.savefig(output_path, dpi=dpi, bbox_inches="tight") diff --git a/src/ria_toolkit_oss/view/view_signal_simple.py b/src/ria_toolkit_oss/view/view_signal_simple.py index 248486f..d97452e 100644 --- a/src/ria_toolkit_oss/view/view_signal_simple.py +++ b/src/ria_toolkit_oss/view/view_signal_simple.py @@ -12,8 +12,8 @@ import numpy as np from scipy.fft import fft, fftshift from scipy.signal.windows import hann -from utils.data.recording import Recording -from utils.view.tools import COLORS, decimate, extract_metadata_fields, set_path +from ria_toolkit_oss.datatypes.recording import Recording +from ria_toolkit_oss.view.tools import COLORS, decimate, extract_metadata_fields, set_path def _add_annotations(annotations, compact_mode, show_labels, sample_rate_hz, center_freq_hz, ax2): diff --git a/src/ria_toolkit_oss_cli/ria_toolkit_oss/annotate.py b/src/ria_toolkit_oss_cli/ria_toolkit_oss/annotate.py index 1bbad66..cdfabb5 100644 --- a/src/ria_toolkit_oss_cli/ria_toolkit_oss/annotate.py +++ b/src/ria_toolkit_oss_cli/ria_toolkit_oss/annotate.py @@ -11,13 +11,8 @@ from ria_toolkit_oss.annotations import ( split_recording_annotations, threshold_qualifier, ) -<<<<<<< HEAD -from ria_toolkit_oss.data import Annotation -from ria_toolkit_oss.data.recording import Recording -======= from ria_toolkit_oss.datatypes import Annotation from ria_toolkit_oss.datatypes.recording import Recording ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 from ria_toolkit_oss.io import load_recording, to_blue, to_npy, to_sigmf, to_wav from ria_toolkit_oss_cli.ria_toolkit_oss.common import format_frequency, format_sample_count @@ -55,15 +50,6 @@ def detect_input_format(filepath): def determine_output_path(input_path, output_path, fmt, quiet, overwrite): input_path = Path(input_path) -<<<<<<< HEAD - - if output_path: - target = Path(output_path) - final_path = target - else: - annotated_name = f"{input_path.stem}_annotated" - target = input_path.with_name(f"{annotated_name}{input_path.suffix}") -======= input_is_annotated = input_path.stem.endswith("_annotated") if output_path: @@ -73,7 +59,6 @@ def determine_output_path(input_path, output_path, fmt, quiet, overwrite): target = input_path else: target = input_path.with_name(f"{input_path.stem}_annotated{input_path.suffix}") ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 if fmt == "sigmf": final_path = normalize_sigmf_path(target) @@ -84,15 +69,10 @@ def determine_output_path(input_path, output_path, fmt, quiet, overwrite): if not quiet: click.echo(f"Saving to: {final_path}") -<<<<<<< HEAD - if final_path.exists() and not overwrite and final_path != input_path: - click.echo(f"Error: {final_path} already exists. Use --overwrite to replace it.", err=True) -======= # Always allow writing to _annotated files; guard against overwriting originals target_is_annotated = final_path.stem.endswith("_annotated") if final_path.exists() and not target_is_annotated and final_path != input_path: click.echo(f"Error: {final_path} is not an annotated file and cannot be overwritten.", err=True) ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 return None return final_path @@ -250,13 +230,8 @@ def list(input, verbose): \b Examples: -<<<<<<< HEAD - utils annotate list recording.sigmf-data - utils annotate list signal.npy --verbose -======= ria annotate list recording.sigmf-data ria annotate list signal.npy --verbose ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 """ try: recording = load_recording(input) @@ -324,13 +299,8 @@ def add(input, start, count, label, freq_lower, freq_upper, comment, annotation_ \b Examples: -<<<<<<< HEAD - utils annotate add file.npy --start 1000 --count 500 --label wifi - utils annotate add signal.sigmf-data --start 0 --count 1000 --label burst --comment "Strong signal" -======= ria annotate add file.npy --start 1000 --count 500 --label wifi ria annotate add signal.sigmf-data --start 0 --count 1000 --label burst --comment "Strong signal" ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 """ try: recording = load_recording(input) @@ -412,21 +382,12 @@ def add(input, start, count, label, freq_lower, freq_upper, comment, annotation_ def remove(input, index, output, overwrite, quiet): """Remove annotation by index. -<<<<<<< HEAD - Use 'utils annotate list' to see annotation indices. - - \b - Examples: - utils annotate remove signal.sigmf-data 2 - utils annotate remove file.npy 0 -======= Use 'ria annotate list' to see annotation indices. \b Examples: ria annotate remove signal.sigmf-data 2 ria annotate remove file.npy 0 ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 """ try: recording = load_recording(input) @@ -475,13 +436,8 @@ def clear(input, output, overwrite, force, quiet): \b Examples: -<<<<<<< HEAD - utils annotate clear signal.sigmf-data - utils annotate clear file.npy --force -======= ria annotate clear signal.sigmf-data ria annotate clear file.npy --force ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 """ try: recording = load_recording(input) @@ -576,17 +532,10 @@ def energy( \b Examples: -<<<<<<< HEAD - utils annotate energy capture.sigmf-data --label burst - utils annotate energy signal.npy --threshold 1.5 --min-distance 10000 - utils annotate energy signal.sigmf-data --freq-method obw - utils annotate energy signal.sigmf-data --freq-method full-detected -======= ria annotate energy capture.sigmf-data --label burst ria annotate energy signal.npy --threshold 1.5 --min-distance 10000 ria annotate energy signal.sigmf-data --freq-method obw ria annotate energy signal.sigmf-data --freq-method full-detected ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 """ try: @@ -662,13 +611,8 @@ def cusum(input, label, min_duration, window_size, tolerance, annotation_type, o \b Examples: -<<<<<<< HEAD - utils annotate cusum signal.sigmf-data --min-duration 5.0 - utils annotate cusum data.npy --min-duration 10.0 --label state -======= ria annotate cusum signal.sigmf-data --min-duration 5.0 ria annotate cusum data.npy --min-duration 10.0 --label state ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 """ try: recording = load_recording(input) @@ -714,11 +658,7 @@ def cusum(input, label, min_duration, window_size, tolerance, annotation_type, o @click.argument("input", type=click.Path(exists=True)) @click.option("--threshold", type=float, required=True, help="Threshold (0.0-1.0, fraction of max magnitude)") @click.option("--label", type=str, default=None, help="Annotation label") -<<<<<<< HEAD -@click.option("--window-size", type=int, default=1024, help="Smoothing window size") -======= @click.option("--window-size", type=int, default=None, help="Smoothing window size in samples (default: 1ms at recording sample rate)") ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 @click.option( "--type", "annotation_type", @@ -726,18 +666,11 @@ def cusum(input, label, min_duration, window_size, tolerance, annotation_type, o default="standalone", help="Annotation type", ) -<<<<<<< HEAD -@click.option("--output", "-o", type=click.Path(), help="Output file path") -@click.option("--overwrite", is_flag=True, help="Overwrite input file (non-SigMF only)") -@click.option("--quiet", is_flag=True, help="Quiet mode") -def threshold(input, threshold, label, window_size, annotation_type, output, overwrite, quiet): -======= @click.option("--channel", type=int, default=0, help="Channel index to annotate (default: 0)") @click.option("--output", "-o", type=click.Path(), help="Output file path") @click.option("--overwrite", is_flag=True, help="Overwrite input file (non-SigMF only)") @click.option("--quiet", is_flag=True, help="Quiet mode") def threshold(input, threshold, label, window_size, annotation_type, channel, output, overwrite, quiet): ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 """Auto-detect signals using threshold method. Detects samples above a percentage of maximum magnitude. Best for simple @@ -745,13 +678,8 @@ def threshold(input, threshold, label, window_size, annotation_type, channel, ou \b Examples: -<<<<<<< HEAD - utils annotate threshold signal.sigmf-data --threshold 0.7 --label wifi - utils annotate threshold data.npy --threshold 0.5 --window-size 2048 -======= ria annotate threshold signal.sigmf-data --threshold 0.7 --label wifi ria annotate threshold data.npy --threshold 0.5 --window-size 2048 ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 """ if not (0.0 <= threshold <= 1.0): raise click.ClickException(f"--threshold must be between 0.0 and 1.0, got {threshold}") @@ -766,12 +694,8 @@ def threshold(input, threshold, label, window_size, annotation_type, channel, ou if not quiet: click.echo("\nDetecting signals using threshold qualifier...") click.echo(f" Threshold: {threshold * 100:.1f}% of max magnitude") -<<<<<<< HEAD - click.echo(f" Window size: {window_size} samples") -======= click.echo(f" Window size: {'auto (1ms)' if window_size is None else f'{window_size} samples'}") click.echo(f" Channel: {channel}") ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 try: initial_count = len(recording.annotations) @@ -781,10 +705,7 @@ def threshold(input, threshold, label, window_size, annotation_type, channel, ou window_size=window_size, label=label, annotation_type=annotation_type, -<<<<<<< HEAD -======= channel=channel, ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 ) added = len(recording.annotations) - initial_count @@ -833,17 +754,10 @@ def separate(input, indices, nfft, noise_threshold_db, min_component_bw, output, \b Examples: -<<<<<<< HEAD - utils annotate separate capture.sigmf-data - utils annotate separate signal.npy --indices 0,1,2 - utils annotate separate data.sigmf-data --noise-threshold-db -70 - utils annotate separate signal.npy --min-component-bw 100000 -======= ria annotate separate capture.sigmf-data ria annotate separate signal.npy --indices 0,1,2 ria annotate separate data.sigmf-data --noise-threshold-db -70 ria annotate separate signal.npy --min-component-bw 100000 ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 """ try: diff --git a/src/ria_toolkit_oss_cli/ria_toolkit_oss/commands.py b/src/ria_toolkit_oss_cli/ria_toolkit_oss/commands.py index 1377ac6..53cf37f 100644 --- a/src/ria_toolkit_oss_cli/ria_toolkit_oss/commands.py +++ b/src/ria_toolkit_oss_cli/ria_toolkit_oss/commands.py @@ -2,10 +2,8 @@ """ This module contains all the CLI bindings for the ria package. """ -<<<<<<< HEAD -======= ->>>>>>> 2bb2d9d5a780dbc17172135a5a1f10eba14b1af4 + from .annotate import annotate from .capture import capture from .combine import combine