Source code for piel.analysis.signals.time.core.offset

import numpy as np
from piel.types import TimeSignalData


[docs] def offset_to_first_rising_edge( waveform: TimeSignalData, lower_threshold_ratio: float = 0.1, upper_threshold_ratio: float = 0.9, ) -> TimeSignalData: """ Offsets the waveform's time axis so that the first rising edge occurs at time zero. A rising edge is defined as the point where the signal transitions from below the lower threshold to above the upper threshold. Parameters: waveform (TimeSignalData): The input waveform data. lower_threshold_ratio (float): Lower threshold as a ratio of the amplitude range. upper_threshold_ratio (float): Upper threshold as a ratio of the amplitude range. Returns: TimeSignalData: A new waveform with the time offset applied. Raises: ValueError: If no rising edge is found in the waveform. """ # Convert time and data to numpy arrays for efficient computation time = np.array(waveform.time_s) data = np.array(waveform.data) # Validate input lengths if len(time) != len(data): raise ValueError("Time and data arrays must have the same length.") # Calculate amplitude range data_min = np.min(data) data_max = np.max(data) amplitude_range = data_max - data_min if amplitude_range == 0: raise ValueError("Signal has zero amplitude range; cannot detect rising edge.") # Define thresholds based on the amplitude range lower_threshold = data_min + amplitude_range * lower_threshold_ratio upper_threshold = data_min + amplitude_range * upper_threshold_ratio # Identify indices where signal crosses the lower threshold below_lower = data < lower_threshold # above_lower = data >= lower_threshold rising_cross_lower = np.where(~below_lower[:-1] & below_lower[1:])[0] + 1 # Iterate through potential rising edges to find the first that crosses the upper threshold for idx in rising_cross_lower: # Check if subsequent data points cross the upper threshold if data[idx] >= upper_threshold: offset_time = time[idx] break # Alternatively, find the exact crossing point using interpolation # Find where the signal crosses the upper threshold after the lower threshold crossing_indices = np.where(data[idx:] >= upper_threshold)[0] if crossing_indices.size > 0: crossing_idx = idx + crossing_indices[0] offset_time = time[crossing_idx] break else: raise ValueError("No rising edge found that crosses the specified thresholds.") # Apply the offset offset_time_array = time - offset_time # Create a new TimeSignalData instance with the offset time offset_signal = TimeSignalData( time_s=offset_time_array.tolist(), data=data.tolist(), data_name=waveform.data_name, ) return offset_signal