Transforms
Signal transforms including Fourier, short-time Fourier, and wavelet transforms.
Transform utilities.
This module provides signal transforms for time-frequency analysis: - Fourier transforms (FFT, RFFT, 2D FFT) - Short-Time Fourier Transform (STFT) and spectrograms - Wavelet transforms (CWT and DWT)
- class pytcl.mathematical_functions.transforms.PowerSpectrum(frequencies, psd)[source]
Bases:
NamedTupleResult of power spectrum estimation.
- frequencies
Frequency values in Hz.
- Type:
ndarray
- psd
Power spectral density estimate.
- Type:
ndarray
- class pytcl.mathematical_functions.transforms.CrossSpectrum(frequencies, csd)[source]
Bases:
NamedTupleResult of cross-spectrum estimation.
- frequencies
Frequency values in Hz.
- Type:
ndarray
- csd
Cross-spectral density estimate (complex).
- Type:
ndarray
- class pytcl.mathematical_functions.transforms.CoherenceResult(frequencies, coherence)[source]
Bases:
NamedTupleResult of coherence estimation.
- frequencies
Frequency values in Hz.
- Type:
ndarray
- coherence
Magnitude-squared coherence, values between 0 and 1.
- Type:
ndarray
- pytcl.mathematical_functions.transforms.fft(x, n=None, axis=-1, norm=None)[source]
Compute the one-dimensional discrete Fourier Transform.
- Parameters:
x (array_like) – Input array, can be complex.
n (int, optional) – Length of the transformed axis of the output. If n is smaller than the length of the input, the input is cropped. If it is larger, the input is padded with zeros.
axis (int, optional) – Axis over which to compute the FFT. Default is -1.
norm ({None, "ortho", "forward", "backward"}, optional) – Normalization mode. Default is None (backward).
- Returns:
out – The truncated or zero-padded input, transformed along the axis.
- Return type:
ndarray
Examples
>>> import numpy as np >>> x = np.array([1.0, 2.0, 1.0, -1.0]) >>> X = fft(x) >>> np.allclose(X, [3.+0.j, 0.-2.j, 1.+0.j, 0.+2.j]) True
- pytcl.mathematical_functions.transforms.ifft(X, n=None, axis=-1, norm=None)[source]
Compute the one-dimensional inverse discrete Fourier Transform.
- Parameters:
- Returns:
out – The truncated or zero-padded input, transformed along the axis.
- Return type:
ndarray
Examples
>>> import numpy as np >>> X = np.array([3.+0.j, 0.-2.j, 1.+0.j, 0.+2.j]) >>> x = ifft(X) >>> np.allclose(x, [1.0, 2.0, 1.0, -1.0]) True
- pytcl.mathematical_functions.transforms.rfft(x, n=None, axis=-1, norm=None)[source]
Compute the one-dimensional FFT for real input.
This function computes the one-dimensional n-point discrete Fourier Transform (DFT) of a real-valued array by means of an efficient algorithm called the Fast Fourier Transform (FFT).
- Parameters:
x (array_like) – Input array, must be real.
n (int, optional) – Number of points to use. If n is smaller than the length of the input, the input is cropped. If it is larger, the input is padded with zeros.
axis (int, optional) – Axis over which to compute the FFT. Default is -1.
norm ({None, "ortho", "forward", "backward"}, optional) – Normalization mode.
- Returns:
out – The FFT of the input along the indicated axis. Only the non-negative frequency terms are returned (n//2 + 1 points).
- Return type:
ndarray
Examples
>>> import numpy as np >>> x = np.array([0., 1., 0., 0.]) >>> X = rfft(x) >>> len(X) # Only positive frequencies 3
- pytcl.mathematical_functions.transforms.irfft(X, n=None, axis=-1, norm=None)[source]
Compute the inverse FFT for real output.
- Parameters:
X (array_like) – Input array (typically from rfft).
n (int, optional) – Length of the output (along the transformed axis). If not given, n = 2*(len(X)-1).
axis (int, optional) – Axis over which to compute the inverse FFT. Default is -1.
norm ({None, "ortho", "forward", "backward"}, optional) – Normalization mode.
- Returns:
out – Real-valued inverse FFT result.
- Return type:
ndarray
Examples
>>> import numpy as np >>> X = rfft([0., 1., 0., 0.]) >>> x = irfft(X) >>> np.allclose(x, [0., 1., 0., 0.]) True
- pytcl.mathematical_functions.transforms.fft2(x, s=None, axes=(-2, -1), norm=None)[source]
Compute the 2-dimensional discrete Fourier Transform.
- Parameters:
- Returns:
out – The 2D FFT of the input.
- Return type:
ndarray
Examples
>>> import numpy as np >>> x = np.array([[1, 0], [0, 1]], dtype=float) >>> X = fft2(x) >>> X.shape (2, 2)
- pytcl.mathematical_functions.transforms.ifft2(X, s=None, axes=(-2, -1), norm=None)[source]
Compute the 2-dimensional inverse discrete Fourier Transform.
- Parameters:
X (array_like) – Input array, can be complex.
s (tuple of ints, optional) – Shape (length of each transformed axis) of the output.
axes (tuple of ints, optional) – Axes over which to compute the inverse FFT. Default is (-2, -1).
norm ({None, "ortho", "forward", "backward"}, optional) – Normalization mode.
- Returns:
out – The 2D inverse FFT of the input.
- Return type:
ndarray
- pytcl.mathematical_functions.transforms.fftshift(x, axes=None)[source]
Shift the zero-frequency component to the center of the spectrum.
- Parameters:
- Returns:
y – The shifted array.
- Return type:
ndarray
Examples
>>> import numpy as np >>> freqs = np.fft.fftfreq(10, 0.1) >>> freqs array([ 0., 1., 2., 3., 4., -5., -4., -3., -2., -1.]) >>> fftshift(freqs) array([-5., -4., -3., -2., -1., 0., 1., 2., 3., 4.])
- pytcl.mathematical_functions.transforms.ifftshift(x, axes=None)[source]
Inverse of fftshift. Shift zero-frequency back to beginning.
- pytcl.mathematical_functions.transforms.frequency_axis(n, fs, shift=False)[source]
Generate frequency axis values for FFT output.
- Parameters:
- Returns:
freqs – Frequency values in Hz.
- Return type:
ndarray
Examples
>>> frequency_axis(8, 100.0) array([ 0. , 12.5, 25. , 37.5, -50. , -37.5, -25. , -12.5]) >>> frequency_axis(8, 100.0, shift=True) array([-50. , -37.5, -25. , -12.5, 0. , 12.5, 25. , 37.5])
- pytcl.mathematical_functions.transforms.rfft_frequency_axis(n, fs)[source]
Generate frequency axis values for rfft output.
- Parameters:
- Returns:
freqs – Non-negative frequency values in Hz.
- Return type:
ndarray
Examples
>>> rfft_frequency_axis(8, 100.0) array([ 0. , 12.5, 25. , 37.5, 50. ])
- pytcl.mathematical_functions.transforms.power_spectrum(x, fs=1.0, window='hann', nperseg=None, noverlap=None, nfft=None, detrend='constant', scaling='density')[source]
Estimate power spectral density using Welch’s method.
- Parameters:
x (array_like) – Time series data.
fs (float, optional) – Sampling frequency in Hz. Default is 1.0.
window (str, optional) – Window function to use. Default is ‘hann’.
nperseg (int, optional) – Length of each segment. Default is 256.
noverlap (int, optional) – Number of points to overlap between segments. Default is nperseg//2.
nfft (int, optional) – Length of the FFT used. Default is nperseg.
detrend (str or bool, optional) – Detrending method: ‘constant’, ‘linear’, or False. Default is ‘constant’.
scaling ({'density', 'spectrum'}, optional) – ‘density’ for power spectral density (V^2/Hz), ‘spectrum’ for power spectrum (V^2). Default is ‘density’.
- Returns:
result – Named tuple with frequencies and power spectral density.
- Return type:
Examples
>>> import numpy as np >>> fs = 1000 # 1 kHz >>> t = np.arange(0, 1, 1/fs) >>> x = np.sin(2 * np.pi * 100 * t) # 100 Hz sine >>> result = power_spectrum(x, fs=fs) >>> peak_freq = result.frequencies[np.argmax(result.psd)] >>> abs(peak_freq - 100) < 5 # Peak near 100 Hz True
Notes
Uses Welch’s method which averages modified periodograms of overlapping segments to reduce variance of the spectral estimate.
- pytcl.mathematical_functions.transforms.cross_spectrum(x, y, fs=1.0, window='hann', nperseg=None, noverlap=None, nfft=None, detrend='constant')[source]
Estimate cross-spectral density between two signals.
- Parameters:
x (array_like) – First time series.
y (array_like) – Second time series.
fs (float, optional) – Sampling frequency in Hz. Default is 1.0.
window (str, optional) – Window function. Default is ‘hann’.
nperseg (int, optional) – Length of each segment. Default is 256.
noverlap (int, optional) – Number of points to overlap between segments. Default is nperseg//2.
nfft (int, optional) – Length of FFT. Default is nperseg.
detrend (str or bool, optional) – Detrending method. Default is ‘constant’.
- Returns:
result – Named tuple with frequencies and cross-spectral density.
- Return type:
Examples
>>> import numpy as np >>> fs = 1000 >>> t = np.arange(0, 1, 1/fs) >>> x = np.sin(2 * np.pi * 50 * t) >>> y = np.sin(2 * np.pi * 50 * t + np.pi/4) # Same freq, phase shifted >>> result = cross_spectrum(x, y, fs=fs) >>> len(result.frequencies) > 0 True
- pytcl.mathematical_functions.transforms.coherence(x, y, fs=1.0, window='hann', nperseg=None, noverlap=None, nfft=None, detrend='constant')[source]
Estimate magnitude-squared coherence between two signals.
The coherence measures the linear correlation between two signals as a function of frequency. Values range from 0 (no correlation) to 1 (perfect correlation).
- Parameters:
x (array_like) – First time series.
y (array_like) – Second time series.
fs (float, optional) – Sampling frequency in Hz. Default is 1.0.
window (str, optional) – Window function. Default is ‘hann’.
nperseg (int, optional) – Length of each segment. Default is 256.
noverlap (int, optional) – Number of overlap points. Default is nperseg//2.
nfft (int, optional) – Length of FFT. Default is nperseg.
detrend (str or bool, optional) – Detrending method. Default is ‘constant’.
- Returns:
result – Named tuple with frequencies and coherence values.
- Return type:
Examples
>>> import numpy as np >>> fs = 1000 >>> t = np.arange(0, 1, 1/fs) >>> x = np.sin(2 * np.pi * 50 * t) >>> y = 2 * x + 0.1 * np.random.randn(len(t)) # Correlated >>> result = coherence(x, y, fs=fs) >>> np.max(result.coherence) > 0.9 # High coherence at 50 Hz True
Notes
- Coherence is defined as:
C_xy = |S_xy|^2 / (S_xx * S_yy)
where S_xy is the cross-spectral density and S_xx, S_yy are the power spectral densities.
- pytcl.mathematical_functions.transforms.periodogram(x, fs=1.0, window=None, nfft=None, detrend='constant', scaling='density')[source]
Estimate power spectral density using a periodogram.
Unlike Welch’s method, the periodogram uses the entire signal without segmentation and averaging. This gives higher frequency resolution but higher variance.
- Parameters:
x (array_like) – Time series data.
fs (float, optional) – Sampling frequency in Hz. Default is 1.0.
window (str, optional) – Window function. Default is None (rectangular).
nfft (int, optional) – Length of FFT. Default is len(x).
detrend (str or bool, optional) – Detrending method. Default is ‘constant’.
scaling ({'density', 'spectrum'}, optional) – Scaling mode. Default is ‘density’.
- Returns:
result – Named tuple with frequencies and power spectral density.
- Return type:
Examples
>>> import numpy as np >>> fs = 1000 >>> t = np.arange(0, 1, 1/fs) >>> x = np.sin(2 * np.pi * 100 * t) >>> result = periodogram(x, fs=fs) >>> len(result.frequencies) == len(result.psd) True
- pytcl.mathematical_functions.transforms.magnitude_spectrum(X, scale='linear')[source]
Compute magnitude spectrum from FFT coefficients.
- Parameters:
X (array_like) – Complex FFT coefficients.
scale ({'linear', 'dB'}, optional) – Output scale. Default is ‘linear’.
- Returns:
mag – Magnitude spectrum.
- Return type:
ndarray
Examples
>>> import numpy as np >>> X = np.array([4+0j, 0-2j, 0+0j, 0+2j]) >>> magnitude_spectrum(X) array([4., 2., 0., 2.]) >>> magnitude_spectrum(X, scale='dB') array([12.04..., 6.02..., -inf, 6.02...])
- pytcl.mathematical_functions.transforms.phase_spectrum(X, unwrap=False)[source]
Compute phase spectrum from FFT coefficients.
- Parameters:
X (array_like) – Complex FFT coefficients.
unwrap (bool, optional) – If True, unwrap the phase to remove discontinuities. Default is False.
- Returns:
phase – Phase spectrum in radians.
- Return type:
ndarray
Examples
>>> import numpy as np >>> X = np.array([1+0j, 0+1j, -1+0j, 0-1j]) >>> phase = phase_spectrum(X) >>> np.allclose(phase, [0, np.pi/2, np.pi, -np.pi/2]) True
- class pytcl.mathematical_functions.transforms.STFTResult(frequencies, times, Zxx)[source]
Bases:
NamedTupleResult of Short-Time Fourier Transform.
- frequencies
Frequency values in Hz.
- Type:
ndarray
- times
Time values in seconds (segment centers).
- Type:
ndarray
- Zxx
STFT matrix (complex), shape (n_frequencies, n_times).
- Type:
ndarray
- class pytcl.mathematical_functions.transforms.Spectrogram(frequencies, times, power)[source]
Bases:
NamedTupleResult of spectrogram computation.
- frequencies
Frequency values in Hz.
- Type:
ndarray
- times
Time values in seconds.
- Type:
ndarray
- pytcl.mathematical_functions.transforms.stft(x, fs=1.0, window='hann', nperseg=256, noverlap=None, nfft=None, detrend=False, return_onesided=True, boundary='zeros', padded=True)[source]
Compute the Short-Time Fourier Transform.
- Parameters:
x (array_like) – Input time-domain signal.
fs (float, optional) – Sampling frequency in Hz. Default is 1.0.
window (str, tuple, or array_like, optional) – Window function. Default is ‘hann’.
nperseg (int, optional) – Length of each segment. Default is 256.
noverlap (int, optional) – Number of points to overlap between segments. Default is nperseg // 2.
nfft (int, optional) – Length of the FFT used. Default is nperseg.
detrend (str or bool, optional) – Detrending: ‘constant’, ‘linear’, or False. Default is False.
return_onesided (bool, optional) – If True, return only non-negative frequencies for real input. Default is True.
boundary (str or None, optional) – Boundary extension: ‘zeros’, ‘even’, ‘odd’, or None. Default is ‘zeros’.
padded (bool, optional) – Whether to pad the signal. Default is True.
- Returns:
result – Named tuple with frequencies, times, and STFT matrix.
- Return type:
Examples
>>> import numpy as np >>> fs = 1000 >>> t = np.arange(0, 1, 1/fs) >>> x = np.sin(2 * np.pi * 50 * t) # 50 Hz sine >>> result = stft(x, fs=fs, nperseg=128) >>> result.Zxx.shape # (n_freq, n_time) (65, 16)
Notes
The STFT provides a time-frequency representation where: - Time resolution = nperseg / fs - Frequency resolution = fs / nfft
There is a trade-off between time and frequency resolution (uncertainty principle): better time resolution requires shorter segments, which reduces frequency resolution, and vice versa.
- pytcl.mathematical_functions.transforms.istft(Zxx, fs=1.0, window='hann', nperseg=None, noverlap=None, nfft=None, input_onesided=True, boundary=True)[source]
Compute the inverse Short-Time Fourier Transform.
- Parameters:
Zxx (array_like) – STFT matrix from stft function.
fs (float, optional) – Sampling frequency in Hz. Default is 1.0.
window (str, tuple, or array_like, optional) – Window function (should match the one used in stft). Default is ‘hann’.
nperseg (int, optional) – Length of each segment. Default is inferred from Zxx.
noverlap (int, optional) – Overlap between segments. Default is nperseg // 2.
nfft (int, optional) – FFT length. Default is inferred from Zxx.
input_onesided (bool, optional) – If True, interpret Zxx as one-sided. Default is True.
boundary (bool, optional) – Whether boundary extension was used. Default is True.
- Returns:
times (ndarray) – Time values in seconds.
x (ndarray) – Reconstructed time-domain signal.
- Return type:
tuple[ndarray[tuple[Any, …], dtype[floating]], ndarray[tuple[Any, …], dtype[floating]]]
Examples
>>> import numpy as np >>> fs = 1000 >>> t = np.arange(0, 1, 1/fs) >>> x = np.sin(2 * np.pi * 50 * t) >>> result = stft(x, fs=fs, nperseg=128) >>> t_rec, x_rec = istft(result.Zxx, fs=fs, nperseg=128) >>> np.allclose(x, x_rec[:len(x)], atol=1e-10) True
Notes
The inverse STFT uses the overlap-add method. For perfect reconstruction, the window function and overlap must satisfy the constant overlap-add (COLA) constraint.
- pytcl.mathematical_functions.transforms.spectrogram(x, fs=1.0, window='hann', nperseg=256, noverlap=None, nfft=None, detrend='constant', scaling='density', mode='psd')[source]
Compute a spectrogram (power spectral density over time).
- Parameters:
x (array_like) – Input time-domain signal.
fs (float, optional) – Sampling frequency in Hz. Default is 1.0.
window (str, tuple, or array_like, optional) – Window function. Default is ‘hann’.
nperseg (int, optional) – Length of each segment. Default is 256.
noverlap (int, optional) – Overlap between segments. Default is nperseg // 8.
nfft (int, optional) – FFT length. Default is nperseg.
detrend (str or bool, optional) – Detrending: ‘constant’, ‘linear’, or False. Default is ‘constant’.
scaling ({'density', 'spectrum'}, optional) – ‘density’ for PSD (V^2/Hz), ‘spectrum’ for power (V^2). Default is ‘density’.
mode ({'psd', 'complex', 'magnitude', 'angle', 'phase'}, optional) – Return type. Default is ‘psd’.
- Returns:
result – Named tuple with frequencies, times, and power spectrogram.
- Return type:
Examples
>>> import numpy as np >>> fs = 1000 >>> t = np.arange(0, 2, 1/fs) >>> # Chirp from 50 to 200 Hz >>> x = np.sin(2 * np.pi * (50 + 75*t) * t) >>> result = spectrogram(x, fs=fs, nperseg=128) >>> result.power.shape # (n_freq, n_time) (65, 31)
Notes
The spectrogram is computed by taking the magnitude squared of the STFT. It shows how the spectral content of the signal evolves over time.
- pytcl.mathematical_functions.transforms.get_window(window, length, fftbins=True)[source]
Generate a window function.
- Parameters:
window (str, tuple, or array_like) – Window type. Can be: - String: ‘hann’, ‘hamming’, ‘blackman’, ‘bartlett’, ‘kaiser’, etc. - Tuple: (window_name, parameter) for parameterized windows - Array: Custom window values
length (int) – Length of the window.
fftbins (bool, optional) – If True, create a periodic window for FFT use. Default is True.
- Returns:
window – Window function values.
- Return type:
ndarray
Examples
>>> w = get_window('hann', 256) >>> len(w) 256 >>> w[0], w[-1] # Near-zero at edges (0.0, 0.0038...) >>> w = get_window(('kaiser', 8.0), 256) # Kaiser with beta=8 >>> len(w) 256
Notes
Common window functions: - ‘rectangular’: No tapering (unity) - ‘hann’: Good frequency resolution, low leakage - ‘hamming’: Similar to Hann, slightly different sidelobes - ‘blackman’: Very low sidelobes, wider main lobe - ‘kaiser’: Parameterized trade-off between resolution and leakage
- pytcl.mathematical_functions.transforms.window_bandwidth(window, length)[source]
Compute the equivalent noise bandwidth of a window.
The equivalent noise bandwidth (ENBW) is the width of an ideal rectangular filter that would pass the same amount of white noise power.
- Parameters:
- Returns:
enbw – Equivalent noise bandwidth in bins.
- Return type:
Examples
>>> enbw = window_bandwidth('hann', 256) >>> 1.4 < enbw < 1.6 # Hann window ENBW is about 1.5 bins True
- pytcl.mathematical_functions.transforms.reassigned_spectrogram(x, fs=1.0, window='hann', nperseg=256, noverlap=None, nfft=None)[source]
Compute reassigned spectrogram for improved time-frequency resolution.
The reassigned spectrogram sharpens the time-frequency representation by moving energy to the center of gravity of each analysis frame.
- Parameters:
x (array_like) – Input signal.
fs (float, optional) – Sampling frequency in Hz. Default is 1.0.
window (str, tuple, or array_like, optional) – Window function. Default is ‘hann’.
nperseg (int, optional) – Segment length. Default is 256.
noverlap (int, optional) – Overlap. Default is nperseg - 1.
nfft (int, optional) – FFT length. Default is nperseg.
- Returns:
frequencies (ndarray) – Frequency values in Hz.
times (ndarray) – Time values in seconds.
Sxx (ndarray) – Reassigned spectrogram power.
- Return type:
tuple[ndarray[tuple[Any, …], dtype[floating]], ndarray[tuple[Any, …], dtype[floating]], ndarray[tuple[Any, …], dtype[floating]]]
Notes
The reassignment method improves readability of the spectrogram by concentrating the spectral energy, making it easier to track frequency components. However, it requires more computation than a standard spectrogram.
- pytcl.mathematical_functions.transforms.mel_spectrogram(x, fs, n_mels=128, fmin=0.0, fmax=None, window='hann', nperseg=2048, noverlap=None)[source]
Compute mel-scaled spectrogram.
The mel scale is a perceptual scale of pitches that approximates human auditory perception. Mel spectrograms are widely used in audio analysis and speech recognition.
- Parameters:
x (array_like) – Input audio signal.
fs (float) – Sampling frequency in Hz.
n_mels (int, optional) – Number of mel bands. Default is 128.
fmin (float, optional) – Minimum frequency in Hz. Default is 0.0.
fmax (float, optional) – Maximum frequency in Hz. Default is fs/2.
window (str, optional) – Window function. Default is ‘hann’.
nperseg (int, optional) – Segment length. Default is 2048.
noverlap (int, optional) – Overlap. Default is nperseg // 4.
- Returns:
mel_freqs (ndarray) – Mel frequency band centers in Hz.
times (ndarray) – Time values in seconds.
mel_spec (ndarray) – Mel spectrogram (n_mels, n_times).
- Return type:
tuple[ndarray[tuple[Any, …], dtype[floating]], ndarray[tuple[Any, …], dtype[floating]], ndarray[tuple[Any, …], dtype[floating]]]
Examples
>>> import numpy as np >>> fs = 22050 >>> x = np.random.randn(fs) # 1 second of noise >>> mel_freqs, times, mel_spec = mel_spectrogram(x, fs, n_mels=64) >>> mel_spec.shape[0] 64
- class pytcl.mathematical_functions.transforms.CWTResult(coefficients, scales, frequencies)[source]
Bases:
NamedTupleResult of Continuous Wavelet Transform.
- coefficients
CWT coefficient matrix (complex), shape (n_scales, n_samples).
- Type:
ndarray
- scales
Scale values used.
- Type:
ndarray
- frequencies
Approximate frequencies corresponding to each scale.
- Type:
ndarray
- class pytcl.mathematical_functions.transforms.DWTResult(cA, cD, levels, wavelet)[source]
Bases:
NamedTupleResult of Discrete Wavelet Transform.
- cA
Approximation coefficients at the coarsest level.
- Type:
ndarray
- pytcl.mathematical_functions.transforms.morlet_wavelet(M, w=5.0, s=1.0, complete=True)[source]
Generate a Morlet wavelet.
The Morlet wavelet is a sinusoid windowed by a Gaussian, commonly used for time-frequency analysis.
- Parameters:
- Returns:
wavelet – Complex Morlet wavelet.
- Return type:
ndarray
Examples
>>> wav = morlet_wavelet(128, w=5.0) >>> len(wav) 128 >>> np.abs(wav[len(wav)//2]) > 0 # Peak in center True
Notes
- The Morlet wavelet is defined as:
psi(t) = exp(i*w*t) * exp(-t^2/2)
- With the complete correction:
psi(t) = (exp(i*w*t) - exp(-w^2/2)) * exp(-t^2/2)
- pytcl.mathematical_functions.transforms.ricker_wavelet(points, a=1.0)[source]
Generate a Ricker wavelet (Mexican hat wavelet).
The Ricker wavelet is the negative normalized second derivative of a Gaussian function. It is real-valued and commonly used in seismology.
- Parameters:
- Returns:
wavelet – Ricker wavelet.
- Return type:
ndarray
Examples
>>> wav = ricker_wavelet(128, a=4.0) >>> len(wav) 128 >>> wav[len(wav)//2] # Peak at center 1.0
Notes
- The Ricker wavelet is defined as:
psi(t) = (1 - 2*(pi*f*t)^2) * exp(-(pi*f*t)^2)
where f = 1/(sqrt(2)*pi*a) is the central frequency.
- pytcl.mathematical_functions.transforms.gaussian_wavelet(M, order=1, sigma=1.0)[source]
Generate a Gaussian derivative wavelet.
- Parameters:
- Returns:
wavelet – Gaussian derivative wavelet.
- Return type:
ndarray
Examples
>>> wav = gaussian_wavelet(128, order=1) >>> len(wav) 128
- pytcl.mathematical_functions.transforms.cwt(signal, scales, wavelet='morlet', fs=1.0, method='fft')[source]
Compute the Continuous Wavelet Transform.
- Parameters:
signal (array_like) – Input signal.
scales (array_like) – Scale values to use.
wavelet (str or callable, optional) – Wavelet to use. Options: ‘morlet’, ‘ricker’, ‘gaussian1’, ‘gaussian2’, or a callable. Default is ‘morlet’.
fs (float, optional) – Sampling frequency in Hz. Default is 1.0.
method ({'fft', 'conv'}, optional) – Computation method. ‘fft’ is faster for long signals. Default is ‘fft’.
- Returns:
result – Named tuple with coefficients, scales, and frequencies.
- Return type:
Examples
>>> import numpy as np >>> fs = 1000 >>> t = np.arange(0, 1, 1/fs) >>> x = np.sin(2 * np.pi * 50 * t) >>> scales = np.arange(1, 128) >>> result = cwt(x, scales, wavelet='morlet', fs=fs) >>> result.coefficients.shape (127, 1000)
Notes
- The CWT is computed as:
W(a, b) = integral s(t) * (1/sqrt(a)) * psi*((t-b)/a) dt
where a is the scale, b is the translation, and psi is the wavelet.
- pytcl.mathematical_functions.transforms.scales_to_frequencies(scales, wavelet='morlet', fs=1.0)[source]
Convert CWT scales to approximate frequencies.
- Parameters:
- Returns:
frequencies – Approximate frequencies in Hz.
- Return type:
ndarray
Examples
>>> scales = np.array([1, 2, 4, 8, 16]) >>> freqs = scales_to_frequencies(scales, wavelet='morlet', fs=1000) >>> len(freqs) 5 >>> freqs[0] > freqs[-1] # Smaller scale = higher frequency True
- pytcl.mathematical_functions.transforms.frequencies_to_scales(frequencies, wavelet='morlet', fs=1.0)[source]
Convert desired frequencies to CWT scales.
- pytcl.mathematical_functions.transforms.dwt(signal, wavelet='db4', level=None, mode='symmetric')[source]
Compute the Discrete Wavelet Transform.
The DWT decomposes a signal into approximation and detail coefficients at multiple resolution levels.
- Parameters:
- Returns:
result – Named tuple with approximation and detail coefficients.
- Return type:
Examples
>>> import numpy as np >>> x = np.random.randn(256) >>> result = dwt(x, wavelet='db4', level=4) >>> len(result.cD) # 4 levels of detail 4
Notes
Requires the pywavelets package. Install with: pip install pywavelets
Common wavelet families: - ‘haar’: Simplest wavelet - ‘dbN’: Daubechies wavelets (N=1..38) - ‘symN’: Symlets (N=2..20) - ‘coifN’: Coiflets (N=1..17) - ‘biorN.M’: Biorthogonal wavelets
- pytcl.mathematical_functions.transforms.idwt(coeffs, mode='symmetric')[source]
Compute the inverse Discrete Wavelet Transform.
- Parameters:
- Returns:
signal – Reconstructed signal.
- Return type:
ndarray
Examples
>>> import numpy as np >>> x = np.random.randn(256) >>> result = dwt(x, wavelet='db4', level=4) >>> x_rec = idwt(result) >>> np.allclose(x, x_rec) True
- pytcl.mathematical_functions.transforms.dwt_single_level(signal, wavelet='db4', mode='symmetric')[source]
Compute single-level DWT decomposition.
- pytcl.mathematical_functions.transforms.idwt_single_level(cA, cD, wavelet='db4', mode='symmetric')[source]
Compute single-level inverse DWT.
- pytcl.mathematical_functions.transforms.wpt(signal, wavelet='db4', level=None, mode='symmetric')[source]
Compute the Wavelet Packet Transform.
The WPT provides a more flexible time-frequency decomposition than DWT by also decomposing the detail coefficients.
- Parameters:
- Returns:
nodes – Dictionary mapping node paths to coefficients. Path format: ‘a’ for approximation, ‘d’ for detail. Example: ‘aad’ means approx->approx->detail.
- Return type:
Examples
>>> import numpy as np >>> x = np.random.randn(256) >>> nodes = wpt(x, wavelet='db4', level=2) >>> 'aa' in nodes # Level 2 approximation True >>> 'dd' in nodes # Level 2 detail of detail True
- pytcl.mathematical_functions.transforms.available_wavelets()[source]
List available wavelet families for DWT.
- pytcl.mathematical_functions.transforms.wavelet_info(wavelet)[source]
Get information about a wavelet.
- pytcl.mathematical_functions.transforms.threshold_coefficients(coeffs, threshold='soft', value=None)[source]
Threshold DWT coefficients for denoising.
- Parameters:
- Returns:
result – Thresholded coefficients.
- Return type:
Examples
>>> import numpy as np >>> from pytcl.mathematical_functions.transforms import dwt, threshold_coefficients, idwt >>> # Create noisy signal >>> t = np.linspace(0, 1, 256) >>> signal = np.sin(2 * np.pi * 5 * t) >>> noise = 0.5 * np.random.randn(256) >>> noisy_signal = signal + noise >>> # Denoise using wavelet thresholding >>> coeffs = dwt(noisy_signal, wavelet='db4', level=3) >>> # Apply soft threshold (default automatic threshold value) >>> coeffs_denoised = threshold_coefficients(coeffs, threshold='soft') >>> # Reconstruct signal from thresholded coefficients >>> signal_denoised = idwt(coeffs_denoised) >>> len(signal_denoised) == len(noisy_signal) True
Notes
- When value is None, the universal threshold is computed as:
sigma * sqrt(2 * log(n))
where sigma is estimated from the finest detail coefficients and n is the total number of coefficients.
Fourier Transforms
FFT, power spectrum, and frequency analysis functions.
Fourier transform utilities.
This module provides wrappers and utilities for Discrete Fourier Transform operations, power spectral density estimation, and spectral analysis.
Functions
fft, ifft: Complex FFT and inverse
rfft, irfft: Real-signal FFT and inverse
fftshift, ifftshift: Shift zero-frequency to center
power_spectrum: Power spectral density estimation
cross_spectrum: Cross-spectral density
coherence: Magnitude-squared coherence
frequency_axis: Generate frequency axis for FFT
References
- class pytcl.mathematical_functions.transforms.fourier.PowerSpectrum(frequencies, psd)[source]
Bases:
NamedTupleResult of power spectrum estimation.
- frequencies
Frequency values in Hz.
- Type:
ndarray
- psd
Power spectral density estimate.
- Type:
ndarray
- class pytcl.mathematical_functions.transforms.fourier.CrossSpectrum(frequencies, csd)[source]
Bases:
NamedTupleResult of cross-spectrum estimation.
- frequencies
Frequency values in Hz.
- Type:
ndarray
- csd
Cross-spectral density estimate (complex).
- Type:
ndarray
- class pytcl.mathematical_functions.transforms.fourier.CoherenceResult(frequencies, coherence)[source]
Bases:
NamedTupleResult of coherence estimation.
- frequencies
Frequency values in Hz.
- Type:
ndarray
- coherence
Magnitude-squared coherence, values between 0 and 1.
- Type:
ndarray
- pytcl.mathematical_functions.transforms.fourier.fft(x, n=None, axis=-1, norm=None)[source]
Compute the one-dimensional discrete Fourier Transform.
- Parameters:
x (array_like) – Input array, can be complex.
n (int, optional) – Length of the transformed axis of the output. If n is smaller than the length of the input, the input is cropped. If it is larger, the input is padded with zeros.
axis (int, optional) – Axis over which to compute the FFT. Default is -1.
norm ({None, "ortho", "forward", "backward"}, optional) – Normalization mode. Default is None (backward).
- Returns:
out – The truncated or zero-padded input, transformed along the axis.
- Return type:
ndarray
Examples
>>> import numpy as np >>> x = np.array([1.0, 2.0, 1.0, -1.0]) >>> X = fft(x) >>> np.allclose(X, [3.+0.j, 0.-2.j, 1.+0.j, 0.+2.j]) True
- pytcl.mathematical_functions.transforms.fourier.ifft(X, n=None, axis=-1, norm=None)[source]
Compute the one-dimensional inverse discrete Fourier Transform.
- Parameters:
- Returns:
out – The truncated or zero-padded input, transformed along the axis.
- Return type:
ndarray
Examples
>>> import numpy as np >>> X = np.array([3.+0.j, 0.-2.j, 1.+0.j, 0.+2.j]) >>> x = ifft(X) >>> np.allclose(x, [1.0, 2.0, 1.0, -1.0]) True
- pytcl.mathematical_functions.transforms.fourier.rfft(x, n=None, axis=-1, norm=None)[source]
Compute the one-dimensional FFT for real input.
This function computes the one-dimensional n-point discrete Fourier Transform (DFT) of a real-valued array by means of an efficient algorithm called the Fast Fourier Transform (FFT).
- Parameters:
x (array_like) – Input array, must be real.
n (int, optional) – Number of points to use. If n is smaller than the length of the input, the input is cropped. If it is larger, the input is padded with zeros.
axis (int, optional) – Axis over which to compute the FFT. Default is -1.
norm ({None, "ortho", "forward", "backward"}, optional) – Normalization mode.
- Returns:
out – The FFT of the input along the indicated axis. Only the non-negative frequency terms are returned (n//2 + 1 points).
- Return type:
ndarray
Examples
>>> import numpy as np >>> x = np.array([0., 1., 0., 0.]) >>> X = rfft(x) >>> len(X) # Only positive frequencies 3
- pytcl.mathematical_functions.transforms.fourier.irfft(X, n=None, axis=-1, norm=None)[source]
Compute the inverse FFT for real output.
- Parameters:
X (array_like) – Input array (typically from rfft).
n (int, optional) – Length of the output (along the transformed axis). If not given, n = 2*(len(X)-1).
axis (int, optional) – Axis over which to compute the inverse FFT. Default is -1.
norm ({None, "ortho", "forward", "backward"}, optional) – Normalization mode.
- Returns:
out – Real-valued inverse FFT result.
- Return type:
ndarray
Examples
>>> import numpy as np >>> X = rfft([0., 1., 0., 0.]) >>> x = irfft(X) >>> np.allclose(x, [0., 1., 0., 0.]) True
- pytcl.mathematical_functions.transforms.fourier.fft2(x, s=None, axes=(-2, -1), norm=None)[source]
Compute the 2-dimensional discrete Fourier Transform.
- Parameters:
- Returns:
out – The 2D FFT of the input.
- Return type:
ndarray
Examples
>>> import numpy as np >>> x = np.array([[1, 0], [0, 1]], dtype=float) >>> X = fft2(x) >>> X.shape (2, 2)
- pytcl.mathematical_functions.transforms.fourier.ifft2(X, s=None, axes=(-2, -1), norm=None)[source]
Compute the 2-dimensional inverse discrete Fourier Transform.
- Parameters:
X (array_like) – Input array, can be complex.
s (tuple of ints, optional) – Shape (length of each transformed axis) of the output.
axes (tuple of ints, optional) – Axes over which to compute the inverse FFT. Default is (-2, -1).
norm ({None, "ortho", "forward", "backward"}, optional) – Normalization mode.
- Returns:
out – The 2D inverse FFT of the input.
- Return type:
ndarray
- pytcl.mathematical_functions.transforms.fourier.fftshift(x, axes=None)[source]
Shift the zero-frequency component to the center of the spectrum.
- Parameters:
- Returns:
y – The shifted array.
- Return type:
ndarray
Examples
>>> import numpy as np >>> freqs = np.fft.fftfreq(10, 0.1) >>> freqs array([ 0., 1., 2., 3., 4., -5., -4., -3., -2., -1.]) >>> fftshift(freqs) array([-5., -4., -3., -2., -1., 0., 1., 2., 3., 4.])
- pytcl.mathematical_functions.transforms.fourier.ifftshift(x, axes=None)[source]
Inverse of fftshift. Shift zero-frequency back to beginning.
- pytcl.mathematical_functions.transforms.fourier.frequency_axis(n, fs, shift=False)[source]
Generate frequency axis values for FFT output.
- Parameters:
- Returns:
freqs – Frequency values in Hz.
- Return type:
ndarray
Examples
>>> frequency_axis(8, 100.0) array([ 0. , 12.5, 25. , 37.5, -50. , -37.5, -25. , -12.5]) >>> frequency_axis(8, 100.0, shift=True) array([-50. , -37.5, -25. , -12.5, 0. , 12.5, 25. , 37.5])
- pytcl.mathematical_functions.transforms.fourier.rfft_frequency_axis(n, fs)[source]
Generate frequency axis values for rfft output.
- Parameters:
- Returns:
freqs – Non-negative frequency values in Hz.
- Return type:
ndarray
Examples
>>> rfft_frequency_axis(8, 100.0) array([ 0. , 12.5, 25. , 37.5, 50. ])
- pytcl.mathematical_functions.transforms.fourier.power_spectrum(x, fs=1.0, window='hann', nperseg=None, noverlap=None, nfft=None, detrend='constant', scaling='density')[source]
Estimate power spectral density using Welch’s method.
- Parameters:
x (array_like) – Time series data.
fs (float, optional) – Sampling frequency in Hz. Default is 1.0.
window (str, optional) – Window function to use. Default is ‘hann’.
nperseg (int, optional) – Length of each segment. Default is 256.
noverlap (int, optional) – Number of points to overlap between segments. Default is nperseg//2.
nfft (int, optional) – Length of the FFT used. Default is nperseg.
detrend (str or bool, optional) – Detrending method: ‘constant’, ‘linear’, or False. Default is ‘constant’.
scaling ({'density', 'spectrum'}, optional) – ‘density’ for power spectral density (V^2/Hz), ‘spectrum’ for power spectrum (V^2). Default is ‘density’.
- Returns:
result – Named tuple with frequencies and power spectral density.
- Return type:
Examples
>>> import numpy as np >>> fs = 1000 # 1 kHz >>> t = np.arange(0, 1, 1/fs) >>> x = np.sin(2 * np.pi * 100 * t) # 100 Hz sine >>> result = power_spectrum(x, fs=fs) >>> peak_freq = result.frequencies[np.argmax(result.psd)] >>> abs(peak_freq - 100) < 5 # Peak near 100 Hz True
Notes
Uses Welch’s method which averages modified periodograms of overlapping segments to reduce variance of the spectral estimate.
- pytcl.mathematical_functions.transforms.fourier.cross_spectrum(x, y, fs=1.0, window='hann', nperseg=None, noverlap=None, nfft=None, detrend='constant')[source]
Estimate cross-spectral density between two signals.
- Parameters:
x (array_like) – First time series.
y (array_like) – Second time series.
fs (float, optional) – Sampling frequency in Hz. Default is 1.0.
window (str, optional) – Window function. Default is ‘hann’.
nperseg (int, optional) – Length of each segment. Default is 256.
noverlap (int, optional) – Number of points to overlap between segments. Default is nperseg//2.
nfft (int, optional) – Length of FFT. Default is nperseg.
detrend (str or bool, optional) – Detrending method. Default is ‘constant’.
- Returns:
result – Named tuple with frequencies and cross-spectral density.
- Return type:
Examples
>>> import numpy as np >>> fs = 1000 >>> t = np.arange(0, 1, 1/fs) >>> x = np.sin(2 * np.pi * 50 * t) >>> y = np.sin(2 * np.pi * 50 * t + np.pi/4) # Same freq, phase shifted >>> result = cross_spectrum(x, y, fs=fs) >>> len(result.frequencies) > 0 True
- pytcl.mathematical_functions.transforms.fourier.coherence(x, y, fs=1.0, window='hann', nperseg=None, noverlap=None, nfft=None, detrend='constant')[source]
Estimate magnitude-squared coherence between two signals.
The coherence measures the linear correlation between two signals as a function of frequency. Values range from 0 (no correlation) to 1 (perfect correlation).
- Parameters:
x (array_like) – First time series.
y (array_like) – Second time series.
fs (float, optional) – Sampling frequency in Hz. Default is 1.0.
window (str, optional) – Window function. Default is ‘hann’.
nperseg (int, optional) – Length of each segment. Default is 256.
noverlap (int, optional) – Number of overlap points. Default is nperseg//2.
nfft (int, optional) – Length of FFT. Default is nperseg.
detrend (str or bool, optional) – Detrending method. Default is ‘constant’.
- Returns:
result – Named tuple with frequencies and coherence values.
- Return type:
Examples
>>> import numpy as np >>> fs = 1000 >>> t = np.arange(0, 1, 1/fs) >>> x = np.sin(2 * np.pi * 50 * t) >>> y = 2 * x + 0.1 * np.random.randn(len(t)) # Correlated >>> result = coherence(x, y, fs=fs) >>> np.max(result.coherence) > 0.9 # High coherence at 50 Hz True
Notes
- Coherence is defined as:
C_xy = |S_xy|^2 / (S_xx * S_yy)
where S_xy is the cross-spectral density and S_xx, S_yy are the power spectral densities.
- pytcl.mathematical_functions.transforms.fourier.periodogram(x, fs=1.0, window=None, nfft=None, detrend='constant', scaling='density')[source]
Estimate power spectral density using a periodogram.
Unlike Welch’s method, the periodogram uses the entire signal without segmentation and averaging. This gives higher frequency resolution but higher variance.
- Parameters:
x (array_like) – Time series data.
fs (float, optional) – Sampling frequency in Hz. Default is 1.0.
window (str, optional) – Window function. Default is None (rectangular).
nfft (int, optional) – Length of FFT. Default is len(x).
detrend (str or bool, optional) – Detrending method. Default is ‘constant’.
scaling ({'density', 'spectrum'}, optional) – Scaling mode. Default is ‘density’.
- Returns:
result – Named tuple with frequencies and power spectral density.
- Return type:
Examples
>>> import numpy as np >>> fs = 1000 >>> t = np.arange(0, 1, 1/fs) >>> x = np.sin(2 * np.pi * 100 * t) >>> result = periodogram(x, fs=fs) >>> len(result.frequencies) == len(result.psd) True
- pytcl.mathematical_functions.transforms.fourier.magnitude_spectrum(X, scale='linear')[source]
Compute magnitude spectrum from FFT coefficients.
- Parameters:
X (array_like) – Complex FFT coefficients.
scale ({'linear', 'dB'}, optional) – Output scale. Default is ‘linear’.
- Returns:
mag – Magnitude spectrum.
- Return type:
ndarray
Examples
>>> import numpy as np >>> X = np.array([4+0j, 0-2j, 0+0j, 0+2j]) >>> magnitude_spectrum(X) array([4., 2., 0., 2.]) >>> magnitude_spectrum(X, scale='dB') array([12.04..., 6.02..., -inf, 6.02...])
- pytcl.mathematical_functions.transforms.fourier.phase_spectrum(X, unwrap=False)[source]
Compute phase spectrum from FFT coefficients.
- Parameters:
X (array_like) – Complex FFT coefficients.
unwrap (bool, optional) – If True, unwrap the phase to remove discontinuities. Default is False.
- Returns:
phase – Phase spectrum in radians.
- Return type:
ndarray
Examples
>>> import numpy as np >>> X = np.array([1+0j, 0+1j, -1+0j, 0-1j]) >>> phase = phase_spectrum(X) >>> np.allclose(phase, [0, np.pi/2, np.pi, -np.pi/2]) True
Short-Time Fourier Transform
STFT, spectrogram, and time-frequency analysis.
Short-Time Fourier Transform (STFT) and spectrogram computation.
The STFT provides time-frequency analysis of signals by computing the Fourier transform of short, overlapping segments of the signal. This reveals how the frequency content of a signal changes over time.
Functions
stft: Compute Short-Time Fourier Transform
istft: Inverse Short-Time Fourier Transform
spectrogram: Compute power spectrogram
get_window: Generate window functions
References
Allen, J. (1977). Short term spectral analysis, synthesis, and modification by discrete Fourier transform. IEEE Transactions on Acoustics, Speech, and Signal Processing, 25(3), 235-238.
Griffin, D., & Lim, J. (1984). Signal estimation from modified short-time Fourier transform. IEEE Transactions on Acoustics, Speech, and Signal Processing, 32(2), 236-243.
- class pytcl.mathematical_functions.transforms.stft.STFTResult(frequencies, times, Zxx)[source]
Bases:
NamedTupleResult of Short-Time Fourier Transform.
- frequencies
Frequency values in Hz.
- Type:
ndarray
- times
Time values in seconds (segment centers).
- Type:
ndarray
- Zxx
STFT matrix (complex), shape (n_frequencies, n_times).
- Type:
ndarray
- class pytcl.mathematical_functions.transforms.stft.Spectrogram(frequencies, times, power)[source]
Bases:
NamedTupleResult of spectrogram computation.
- frequencies
Frequency values in Hz.
- Type:
ndarray
- times
Time values in seconds.
- Type:
ndarray
- pytcl.mathematical_functions.transforms.stft.get_window(window, length, fftbins=True)[source]
Generate a window function.
- Parameters:
window (str, tuple, or array_like) – Window type. Can be: - String: ‘hann’, ‘hamming’, ‘blackman’, ‘bartlett’, ‘kaiser’, etc. - Tuple: (window_name, parameter) for parameterized windows - Array: Custom window values
length (int) – Length of the window.
fftbins (bool, optional) – If True, create a periodic window for FFT use. Default is True.
- Returns:
window – Window function values.
- Return type:
ndarray
Examples
>>> w = get_window('hann', 256) >>> len(w) 256 >>> w[0], w[-1] # Near-zero at edges (0.0, 0.0038...) >>> w = get_window(('kaiser', 8.0), 256) # Kaiser with beta=8 >>> len(w) 256
Notes
Common window functions: - ‘rectangular’: No tapering (unity) - ‘hann’: Good frequency resolution, low leakage - ‘hamming’: Similar to Hann, slightly different sidelobes - ‘blackman’: Very low sidelobes, wider main lobe - ‘kaiser’: Parameterized trade-off between resolution and leakage
- pytcl.mathematical_functions.transforms.stft.window_bandwidth(window, length)[source]
Compute the equivalent noise bandwidth of a window.
The equivalent noise bandwidth (ENBW) is the width of an ideal rectangular filter that would pass the same amount of white noise power.
- Parameters:
- Returns:
enbw – Equivalent noise bandwidth in bins.
- Return type:
Examples
>>> enbw = window_bandwidth('hann', 256) >>> 1.4 < enbw < 1.6 # Hann window ENBW is about 1.5 bins True
- pytcl.mathematical_functions.transforms.stft.stft(x, fs=1.0, window='hann', nperseg=256, noverlap=None, nfft=None, detrend=False, return_onesided=True, boundary='zeros', padded=True)[source]
Compute the Short-Time Fourier Transform.
- Parameters:
x (array_like) – Input time-domain signal.
fs (float, optional) – Sampling frequency in Hz. Default is 1.0.
window (str, tuple, or array_like, optional) – Window function. Default is ‘hann’.
nperseg (int, optional) – Length of each segment. Default is 256.
noverlap (int, optional) – Number of points to overlap between segments. Default is nperseg // 2.
nfft (int, optional) – Length of the FFT used. Default is nperseg.
detrend (str or bool, optional) – Detrending: ‘constant’, ‘linear’, or False. Default is False.
return_onesided (bool, optional) – If True, return only non-negative frequencies for real input. Default is True.
boundary (str or None, optional) – Boundary extension: ‘zeros’, ‘even’, ‘odd’, or None. Default is ‘zeros’.
padded (bool, optional) – Whether to pad the signal. Default is True.
- Returns:
result – Named tuple with frequencies, times, and STFT matrix.
- Return type:
Examples
>>> import numpy as np >>> fs = 1000 >>> t = np.arange(0, 1, 1/fs) >>> x = np.sin(2 * np.pi * 50 * t) # 50 Hz sine >>> result = stft(x, fs=fs, nperseg=128) >>> result.Zxx.shape # (n_freq, n_time) (65, 16)
Notes
The STFT provides a time-frequency representation where: - Time resolution = nperseg / fs - Frequency resolution = fs / nfft
There is a trade-off between time and frequency resolution (uncertainty principle): better time resolution requires shorter segments, which reduces frequency resolution, and vice versa.
- pytcl.mathematical_functions.transforms.stft.istft(Zxx, fs=1.0, window='hann', nperseg=None, noverlap=None, nfft=None, input_onesided=True, boundary=True)[source]
Compute the inverse Short-Time Fourier Transform.
- Parameters:
Zxx (array_like) – STFT matrix from stft function.
fs (float, optional) – Sampling frequency in Hz. Default is 1.0.
window (str, tuple, or array_like, optional) – Window function (should match the one used in stft). Default is ‘hann’.
nperseg (int, optional) – Length of each segment. Default is inferred from Zxx.
noverlap (int, optional) – Overlap between segments. Default is nperseg // 2.
nfft (int, optional) – FFT length. Default is inferred from Zxx.
input_onesided (bool, optional) – If True, interpret Zxx as one-sided. Default is True.
boundary (bool, optional) – Whether boundary extension was used. Default is True.
- Returns:
times (ndarray) – Time values in seconds.
x (ndarray) – Reconstructed time-domain signal.
- Return type:
tuple[ndarray[tuple[Any, …], dtype[floating]], ndarray[tuple[Any, …], dtype[floating]]]
Examples
>>> import numpy as np >>> fs = 1000 >>> t = np.arange(0, 1, 1/fs) >>> x = np.sin(2 * np.pi * 50 * t) >>> result = stft(x, fs=fs, nperseg=128) >>> t_rec, x_rec = istft(result.Zxx, fs=fs, nperseg=128) >>> np.allclose(x, x_rec[:len(x)], atol=1e-10) True
Notes
The inverse STFT uses the overlap-add method. For perfect reconstruction, the window function and overlap must satisfy the constant overlap-add (COLA) constraint.
- pytcl.mathematical_functions.transforms.stft.spectrogram(x, fs=1.0, window='hann', nperseg=256, noverlap=None, nfft=None, detrend='constant', scaling='density', mode='psd')[source]
Compute a spectrogram (power spectral density over time).
- Parameters:
x (array_like) – Input time-domain signal.
fs (float, optional) – Sampling frequency in Hz. Default is 1.0.
window (str, tuple, or array_like, optional) – Window function. Default is ‘hann’.
nperseg (int, optional) – Length of each segment. Default is 256.
noverlap (int, optional) – Overlap between segments. Default is nperseg // 8.
nfft (int, optional) – FFT length. Default is nperseg.
detrend (str or bool, optional) – Detrending: ‘constant’, ‘linear’, or False. Default is ‘constant’.
scaling ({'density', 'spectrum'}, optional) – ‘density’ for PSD (V^2/Hz), ‘spectrum’ for power (V^2). Default is ‘density’.
mode ({'psd', 'complex', 'magnitude', 'angle', 'phase'}, optional) – Return type. Default is ‘psd’.
- Returns:
result – Named tuple with frequencies, times, and power spectrogram.
- Return type:
Examples
>>> import numpy as np >>> fs = 1000 >>> t = np.arange(0, 2, 1/fs) >>> # Chirp from 50 to 200 Hz >>> x = np.sin(2 * np.pi * (50 + 75*t) * t) >>> result = spectrogram(x, fs=fs, nperseg=128) >>> result.power.shape # (n_freq, n_time) (65, 31)
Notes
The spectrogram is computed by taking the magnitude squared of the STFT. It shows how the spectral content of the signal evolves over time.
- pytcl.mathematical_functions.transforms.stft.reassigned_spectrogram(x, fs=1.0, window='hann', nperseg=256, noverlap=None, nfft=None)[source]
Compute reassigned spectrogram for improved time-frequency resolution.
The reassigned spectrogram sharpens the time-frequency representation by moving energy to the center of gravity of each analysis frame.
- Parameters:
x (array_like) – Input signal.
fs (float, optional) – Sampling frequency in Hz. Default is 1.0.
window (str, tuple, or array_like, optional) – Window function. Default is ‘hann’.
nperseg (int, optional) – Segment length. Default is 256.
noverlap (int, optional) – Overlap. Default is nperseg - 1.
nfft (int, optional) – FFT length. Default is nperseg.
- Returns:
frequencies (ndarray) – Frequency values in Hz.
times (ndarray) – Time values in seconds.
Sxx (ndarray) – Reassigned spectrogram power.
- Return type:
tuple[ndarray[tuple[Any, …], dtype[floating]], ndarray[tuple[Any, …], dtype[floating]], ndarray[tuple[Any, …], dtype[floating]]]
Notes
The reassignment method improves readability of the spectrogram by concentrating the spectral energy, making it easier to track frequency components. However, it requires more computation than a standard spectrogram.
- pytcl.mathematical_functions.transforms.stft.mel_spectrogram(x, fs, n_mels=128, fmin=0.0, fmax=None, window='hann', nperseg=2048, noverlap=None)[source]
Compute mel-scaled spectrogram.
The mel scale is a perceptual scale of pitches that approximates human auditory perception. Mel spectrograms are widely used in audio analysis and speech recognition.
- Parameters:
x (array_like) – Input audio signal.
fs (float) – Sampling frequency in Hz.
n_mels (int, optional) – Number of mel bands. Default is 128.
fmin (float, optional) – Minimum frequency in Hz. Default is 0.0.
fmax (float, optional) – Maximum frequency in Hz. Default is fs/2.
window (str, optional) – Window function. Default is ‘hann’.
nperseg (int, optional) – Segment length. Default is 2048.
noverlap (int, optional) – Overlap. Default is nperseg // 4.
- Returns:
mel_freqs (ndarray) – Mel frequency band centers in Hz.
times (ndarray) – Time values in seconds.
mel_spec (ndarray) – Mel spectrogram (n_mels, n_times).
- Return type:
tuple[ndarray[tuple[Any, …], dtype[floating]], ndarray[tuple[Any, …], dtype[floating]], ndarray[tuple[Any, …], dtype[floating]]]
Examples
>>> import numpy as np >>> fs = 22050 >>> x = np.random.randn(fs) # 1 second of noise >>> mel_freqs, times, mel_spec = mel_spectrogram(x, fs, n_mels=64) >>> mel_spec.shape[0] 64
Wavelet Transforms
Continuous and discrete wavelet transforms.
Wavelet transform utilities.
This module provides continuous and discrete wavelet transform functions, wavelet generation, and time-frequency analysis tools.
Functions
cwt: Continuous Wavelet Transform
dwt: Discrete Wavelet Transform (requires pywavelets)
idwt: Inverse Discrete Wavelet Transform
morlet_wavelet: Generate Morlet wavelet
ricker_wavelet: Generate Ricker (Mexican hat) wavelet
scales_to_frequencies: Convert wavelet scales to frequencies
References
Mallat, S. (2008). A Wavelet Tour of Signal Processing: The Sparse Way (3rd ed.). Academic Press.
Daubechies, I. (1992). Ten Lectures on Wavelets. SIAM.
- class pytcl.mathematical_functions.transforms.wavelets.CWTResult(coefficients, scales, frequencies)[source]
Bases:
NamedTupleResult of Continuous Wavelet Transform.
- coefficients
CWT coefficient matrix (complex), shape (n_scales, n_samples).
- Type:
ndarray
- scales
Scale values used.
- Type:
ndarray
- frequencies
Approximate frequencies corresponding to each scale.
- Type:
ndarray
- class pytcl.mathematical_functions.transforms.wavelets.DWTResult(cA, cD, levels, wavelet)[source]
Bases:
NamedTupleResult of Discrete Wavelet Transform.
- cA
Approximation coefficients at the coarsest level.
- Type:
ndarray
- pytcl.mathematical_functions.transforms.wavelets.morlet_wavelet(M, w=5.0, s=1.0, complete=True)[source]
Generate a Morlet wavelet.
The Morlet wavelet is a sinusoid windowed by a Gaussian, commonly used for time-frequency analysis.
- Parameters:
- Returns:
wavelet – Complex Morlet wavelet.
- Return type:
ndarray
Examples
>>> wav = morlet_wavelet(128, w=5.0) >>> len(wav) 128 >>> np.abs(wav[len(wav)//2]) > 0 # Peak in center True
Notes
- The Morlet wavelet is defined as:
psi(t) = exp(i*w*t) * exp(-t^2/2)
- With the complete correction:
psi(t) = (exp(i*w*t) - exp(-w^2/2)) * exp(-t^2/2)
- pytcl.mathematical_functions.transforms.wavelets.ricker_wavelet(points, a=1.0)[source]
Generate a Ricker wavelet (Mexican hat wavelet).
The Ricker wavelet is the negative normalized second derivative of a Gaussian function. It is real-valued and commonly used in seismology.
- Parameters:
- Returns:
wavelet – Ricker wavelet.
- Return type:
ndarray
Examples
>>> wav = ricker_wavelet(128, a=4.0) >>> len(wav) 128 >>> wav[len(wav)//2] # Peak at center 1.0
Notes
- The Ricker wavelet is defined as:
psi(t) = (1 - 2*(pi*f*t)^2) * exp(-(pi*f*t)^2)
where f = 1/(sqrt(2)*pi*a) is the central frequency.
- pytcl.mathematical_functions.transforms.wavelets.gaussian_wavelet(M, order=1, sigma=1.0)[source]
Generate a Gaussian derivative wavelet.
- Parameters:
- Returns:
wavelet – Gaussian derivative wavelet.
- Return type:
ndarray
Examples
>>> wav = gaussian_wavelet(128, order=1) >>> len(wav) 128
- pytcl.mathematical_functions.transforms.wavelets.cwt(signal, scales, wavelet='morlet', fs=1.0, method='fft')[source]
Compute the Continuous Wavelet Transform.
- Parameters:
signal (array_like) – Input signal.
scales (array_like) – Scale values to use.
wavelet (str or callable, optional) – Wavelet to use. Options: ‘morlet’, ‘ricker’, ‘gaussian1’, ‘gaussian2’, or a callable. Default is ‘morlet’.
fs (float, optional) – Sampling frequency in Hz. Default is 1.0.
method ({'fft', 'conv'}, optional) – Computation method. ‘fft’ is faster for long signals. Default is ‘fft’.
- Returns:
result – Named tuple with coefficients, scales, and frequencies.
- Return type:
Examples
>>> import numpy as np >>> fs = 1000 >>> t = np.arange(0, 1, 1/fs) >>> x = np.sin(2 * np.pi * 50 * t) >>> scales = np.arange(1, 128) >>> result = cwt(x, scales, wavelet='morlet', fs=fs) >>> result.coefficients.shape (127, 1000)
Notes
- The CWT is computed as:
W(a, b) = integral s(t) * (1/sqrt(a)) * psi*((t-b)/a) dt
where a is the scale, b is the translation, and psi is the wavelet.
- pytcl.mathematical_functions.transforms.wavelets.scales_to_frequencies(scales, wavelet='morlet', fs=1.0)[source]
Convert CWT scales to approximate frequencies.
- Parameters:
- Returns:
frequencies – Approximate frequencies in Hz.
- Return type:
ndarray
Examples
>>> scales = np.array([1, 2, 4, 8, 16]) >>> freqs = scales_to_frequencies(scales, wavelet='morlet', fs=1000) >>> len(freqs) 5 >>> freqs[0] > freqs[-1] # Smaller scale = higher frequency True
- pytcl.mathematical_functions.transforms.wavelets.frequencies_to_scales(frequencies, wavelet='morlet', fs=1.0)[source]
Convert desired frequencies to CWT scales.
- pytcl.mathematical_functions.transforms.wavelets.dwt(signal, wavelet='db4', level=None, mode='symmetric')[source]
Compute the Discrete Wavelet Transform.
The DWT decomposes a signal into approximation and detail coefficients at multiple resolution levels.
- Parameters:
- Returns:
result – Named tuple with approximation and detail coefficients.
- Return type:
Examples
>>> import numpy as np >>> x = np.random.randn(256) >>> result = dwt(x, wavelet='db4', level=4) >>> len(result.cD) # 4 levels of detail 4
Notes
Requires the pywavelets package. Install with: pip install pywavelets
Common wavelet families: - ‘haar’: Simplest wavelet - ‘dbN’: Daubechies wavelets (N=1..38) - ‘symN’: Symlets (N=2..20) - ‘coifN’: Coiflets (N=1..17) - ‘biorN.M’: Biorthogonal wavelets
- pytcl.mathematical_functions.transforms.wavelets.idwt(coeffs, mode='symmetric')[source]
Compute the inverse Discrete Wavelet Transform.
- Parameters:
- Returns:
signal – Reconstructed signal.
- Return type:
ndarray
Examples
>>> import numpy as np >>> x = np.random.randn(256) >>> result = dwt(x, wavelet='db4', level=4) >>> x_rec = idwt(result) >>> np.allclose(x, x_rec) True
- pytcl.mathematical_functions.transforms.wavelets.dwt_single_level(signal, wavelet='db4', mode='symmetric')[source]
Compute single-level DWT decomposition.
- pytcl.mathematical_functions.transforms.wavelets.idwt_single_level(cA, cD, wavelet='db4', mode='symmetric')[source]
Compute single-level inverse DWT.
- pytcl.mathematical_functions.transforms.wavelets.wpt(signal, wavelet='db4', level=None, mode='symmetric')[source]
Compute the Wavelet Packet Transform.
The WPT provides a more flexible time-frequency decomposition than DWT by also decomposing the detail coefficients.
- Parameters:
- Returns:
nodes – Dictionary mapping node paths to coefficients. Path format: ‘a’ for approximation, ‘d’ for detail. Example: ‘aad’ means approx->approx->detail.
- Return type:
Examples
>>> import numpy as np >>> x = np.random.randn(256) >>> nodes = wpt(x, wavelet='db4', level=2) >>> 'aa' in nodes # Level 2 approximation True >>> 'dd' in nodes # Level 2 detail of detail True
- pytcl.mathematical_functions.transforms.wavelets.available_wavelets()[source]
List available wavelet families for DWT.
- pytcl.mathematical_functions.transforms.wavelets.wavelet_info(wavelet)[source]
Get information about a wavelet.
- pytcl.mathematical_functions.transforms.wavelets.threshold_coefficients(coeffs, threshold='soft', value=None)[source]
Threshold DWT coefficients for denoising.
- Parameters:
- Returns:
result – Thresholded coefficients.
- Return type:
Examples
>>> import numpy as np >>> from pytcl.mathematical_functions.transforms import dwt, threshold_coefficients, idwt >>> # Create noisy signal >>> t = np.linspace(0, 1, 256) >>> signal = np.sin(2 * np.pi * 5 * t) >>> noise = 0.5 * np.random.randn(256) >>> noisy_signal = signal + noise >>> # Denoise using wavelet thresholding >>> coeffs = dwt(noisy_signal, wavelet='db4', level=3) >>> # Apply soft threshold (default automatic threshold value) >>> coeffs_denoised = threshold_coefficients(coeffs, threshold='soft') >>> # Reconstruct signal from thresholded coefficients >>> signal_denoised = idwt(coeffs_denoised) >>> len(signal_denoised) == len(noisy_signal) True
Notes
- When value is None, the universal threshold is computed as:
sigma * sqrt(2 * log(n))
where sigma is estimated from the finest detail coefficients and n is the total number of coefficients.