Source code for fracspy.utils.synthutils

import numpy as np

[docs] def add_noise(data:np.ndarray, noise_type:str="white", snr:float=1, trind:int=None, seed: int = None): r"""Contaminate seismic data with noise of different type. Parameters ---------- data : :obj:`numpy.ndarray` Input seismic data of shape :math:`n_r \times n_t` noise_type: :obj:`str`, optional, default: "white" Type of noise: "white" for random white noise, "spiky" for noise that manifests as sharp spikes in the data. "ringy" for noise that creates a ringing effect in the data. snr: :obj:`float`, optional, default: 1 Signal-to-noise ratio to determine noise strength defined as maximum amplitude of the signal divided by the maximum amplitude of noise trind: :obj:`int`, optional, default: None (add to all traces) Array of indices of traces to which noise must be added (must be >= 0 and <= nr and non-repeating) seed: :obj:`int`, optional, default: None Seed for the random number generator to ensure reproducibility Returns ------- data_contaminated : :obj:`numpy.ndarray` Data contaminated with noise of the selected noise type, size: :math:`n_r \times n_t` Raises ------ ValueError If `trind` contains indices that are out of the valid range (>= 0 and < nr) or if `trind` contains non-unique values. Notes ----- Maximum amplitude of the signal is calculated as maximum amplitude of the input data. The ringing effect in seismic data refers to a specific type of noise or distortion that appears as a series of oscillations or reverberations in the seismic trace. This effect is characterized by a repetitive, wave-like pattern that continues after the main seismic event, resembling the ringing of a bell. Key aspects of the ringing effect include: - Appearance: It looks like a series of alternating positive and negative amplitudes that gradually decrease over time. - Causes: Ringing can be caused by various factors, including: - Instrument response: Poor coupling between the seismometer and the ground - Resonance in the recording system - Near-surface reverberations - Data processing artifacts, particularly from improper filtering - Impact: Ringing can obscure real seismic events and make interpretation difficult, especially for later arrivals or subtle features. - Frequency: The ringing often occurs at a characteristic frequency, which can help in identifying its source. - Duration: It can persist for a significant portion of the trace, sometimes lasting longer than the actual seismic signal of interest. """ # Set the random seed if provided if seed is not None: np.random.seed(seed) # Get the shape of the input data, which should be (nr, nt) nr, nt = data.shape # Calculate the noise max based on SNR noise_max = np.max(data) / snr # Assign noise array noise = np.zeros_like(data) # Check trace indices if trind is None: trind = np.arange(0, nr).astype(int) else: # Ensure trind contains unique, valid indices trind = np.unique(trind) # Remove duplicates if np.any(trind < 0) or np.any(trind >= nr): raise ValueError("All indices in trind must be >= 0 and < nr") if noise_type == "white": # Generate white noise noise[trind,:] = np.random.normal(0, noise_max, (len(trind), data.shape[1])) elif noise_type == "spiky": # Generate spiky noise for trace in trind: num_spikes = np.random.randint(1, 5) # Random number of spikes spike_positions = np.random.choice(nt, num_spikes, replace=False) noise[trace, spike_positions] = noise_max * np.random.uniform(-1, 1, num_spikes) elif noise_type == "ringy": # Generate ringy noise frequency = np.random.uniform(5, 15) # Random frequency for the ringing effect for trace in trind: t = np.arange(nt) ringy_wave = noise_max * np.exp(-t/nt) * np.sin(2 * np.pi * frequency * t / nt) noise[trace, :] = ringy_wave else: raise ValueError(f"Invalid noise type: {noise_type}") # Add noise to the data data_contaminated = data + noise return data_contaminated