Source code for qumphy.data.signal_preprocessing.noise

"""
File: qumphy/data/signal_preprocessing/noise.py
Project: 22HLT01 QUMPHY
Contact: oskar.pfeffer@ptb.de
Gitlab: https://gitlab.com/qumphy
Description: Functions for adding noise to the signals.
"""

import numpy as np
import qumphy.data.signal_preprocessing.filters as filters


[docs] def add_noise(data: np.ndarray, noise_params: dict = None): """ Adds noise to the given data. Parameters ---------- data : np.ndarray Input data. Returns ------- np.ndarray Data with added noise. """ if noise_params is not None: if noise_params["type"] == "gaussian": return gaussian_noise(data, **noise_params["kwargs"]) elif noise_params["type"] == "powerline": return powerline_noise(data, **noise_params["kwargs"]) elif noise_params["type"] == "baseline_wander": return baseline_wander_noise(data, **noise_params["kwargs"]) else: return data
[docs] def baseline_wander_noise( signal: np.ndarray, signal_frequency: float, snr: float, cutoff: float = 0.5, seed: int = None, ) -> np.ndarray: """ Add baseline wander noise to a signal. Parameters ---------- signal : np.ndarray Input array with shape (..., L), where the last dimension is the signal length and all preceding dimensions index different signals (e.g. (batch, channels, length)) snr : float The signal-to-noise ratio (SNR) in decibels. cutoff : float The cutoff frequency of the low-pass filter. seed : int or None, optional Seed of the RNG. Returns ------- np.ndarray The signal with added baseline wander noise. """ rng = np.random.default_rng(seed) white_noise = rng.normal(0, 1, size=signal.shape) filtered_noise = filters.lowpass_filter(white_noise, cutoff, signal_frequency) base_power = np.mean(filtered_noise**2, axis=-1, keepdims=True) signal_power = np.mean(signal**2, axis=-1, keepdims=True) snr_linear = 10 ** (snr / 10) noise_power = signal_power / snr_linear / (base_power + 1e-10) noise = filtered_noise * np.sqrt(noise_power) return signal + noise
[docs] def gaussian_noise(signal: np.ndarray, snr: float, seed: int = None) -> np.ndarray: """ Add Gaussian noise to a signal. Parameters ---------- signal : np.ndarray Input array with shape (..., L), where the last dimension is the signal length and all preceding dimensions index different signals (e.g. (batch, channels, length)) snr : float The signal-to-noise ratio (SNR) in decibels. seed : int or None, optional Seed of the RNG. Returns ------- np.ndarray The signal with added Gaussian noise. """ rng = np.random.default_rng(seed) signal_power = np.mean(signal**2, axis=-1, keepdims=True) snr_linear = 10 ** (snr / 10) noise_power = signal_power / snr_linear noise = rng.normal(0, np.sqrt(noise_power), size=signal.shape) return signal + noise
[docs] def powerline_noise( signal: np.ndarray, signal_frequency: float, snr: float, noise_frequency: float = 50.0, ) -> np.ndarray: """ Add powerline noise to a signal. Typically, powerline noise is a sinusoidal signal with a frequency of 50 or 60 Hz. Parameters ---------- signal : np.ndarray Input array with shape (..., L), where the last dimension is the signal length and all preceding dimensions index different signals (e.g. (batch, channels, length)) signal_frequency : float The sampling frequency (Hz) of the signal. snr : float The signal-to-noise ratio (SNR) in decibels. noise_frequency : float The frequency (Hz) of the powerline noise. Returns ------- np.ndarray The signal with added powerline noise. """ t = np.arange(signal.shape[-1]) / signal_frequency noise = np.sin(2 * np.pi * noise_frequency * t) signal_power = np.mean(signal**2, axis=-1, keepdims=True) snr_linear = 10 ** (snr / 10) noise_power = signal_power / snr_linear noise = noise * np.sqrt(noise_power) return signal + noise