update
This commit is contained in:
parent
49189c3f48
commit
6b66a2f3da
3 changed files with 506 additions and 1 deletions
|
@ -1 +1 @@
|
||||||
__version__ = '0.1.0'
|
__version__ = '0.1.1'
|
||||||
|
|
504
mysignal/phasefreq.py
Normal file
504
mysignal/phasefreq.py
Normal file
|
@ -0,0 +1,504 @@
|
||||||
|
import warnings
|
||||||
|
import numpy as np
|
||||||
|
import pandas as pd
|
||||||
|
import pywt
|
||||||
|
|
||||||
|
from scipy.fft import fft, fftfreq
|
||||||
|
from scipy.signal import find_peaks, hilbert, butter, filtfilt, correlate
|
||||||
|
from scipy.stats import linregress
|
||||||
|
from scipy.optimize import curve_fit
|
||||||
|
|
||||||
|
|
||||||
|
def filter_signal_by_modes(time, signal, num_modes=1, bandwidth_factor=0.1):
|
||||||
|
"""
|
||||||
|
Filtre un signal pour extraire ses composantes fréquentielles dominantes.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
time (array-like): Array contenant les données temporelles.
|
||||||
|
signal (array-like): Array contenant les données du signal.
|
||||||
|
num_modes (int): Nombre de modes fréquentiels à extraire.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple: (filtered_signals, frequencies, time_filtered)
|
||||||
|
filtered_signals: Liste des signaux filtrés pour chaque mode
|
||||||
|
frequencies: Fréquences correspondantes à chaque mode
|
||||||
|
time_filtered: Temps après filtrage (même que l'entrée)
|
||||||
|
"""
|
||||||
|
# Convertir en arrays numpy
|
||||||
|
time = np.array(time)
|
||||||
|
signal = np.array(signal)
|
||||||
|
|
||||||
|
# Calculer la période d'échantillonnage et la fréquence
|
||||||
|
dt = np.mean(np.diff(time))
|
||||||
|
fs = 1 / dt
|
||||||
|
|
||||||
|
# Supprimer la composante DC
|
||||||
|
signal_clean = signal - np.mean(signal)
|
||||||
|
|
||||||
|
# Calculer la FFT
|
||||||
|
n = len(time)
|
||||||
|
fft_signal = fft(signal_clean)
|
||||||
|
freqs = fftfreq(n, dt)
|
||||||
|
|
||||||
|
# Prendre seulement les fréquences positives
|
||||||
|
positive_mask = freqs > 0
|
||||||
|
freqs_pos = freqs[positive_mask]
|
||||||
|
fft_pos = fft_signal[positive_mask]
|
||||||
|
|
||||||
|
# Trouver les pics dans le spectre
|
||||||
|
magnitude = np.abs(fft_pos)
|
||||||
|
peaks, _ = find_peaks(magnitude, height=0.1*np.max(magnitude))
|
||||||
|
peak_freqs = freqs_pos[peaks]
|
||||||
|
peak_mags = magnitude[peaks]
|
||||||
|
|
||||||
|
# Trier les pics par magnitude et sélectionner les num_modes plus importants
|
||||||
|
idx = np.argsort(peak_mags)[-num_modes:]
|
||||||
|
dominant_freqs = peak_freqs[idx]
|
||||||
|
|
||||||
|
# Trier les fréquences par ordre croissant
|
||||||
|
dominant_freqs.sort()
|
||||||
|
|
||||||
|
# Initialiser la liste des signaux filtrés
|
||||||
|
filtered_signals = []
|
||||||
|
|
||||||
|
# Pour chaque fréquence dominante, appliquer un filtre passe-bande
|
||||||
|
for freq in dominant_freqs:
|
||||||
|
# Définir la bande passante (10% de la fréquence centrale de chaque côté)
|
||||||
|
bandwidth = bandwidth_factor * freq
|
||||||
|
lowcut = freq - bandwidth
|
||||||
|
highcut = freq + bandwidth
|
||||||
|
|
||||||
|
# Éviter les fréquences négatives ou supérieures à la fréquence de Nyquist
|
||||||
|
nyq = 0.5 * fs
|
||||||
|
if lowcut <= 0:
|
||||||
|
lowcut = 0.01
|
||||||
|
if highcut >= nyq:
|
||||||
|
highcut = nyq - 0.01
|
||||||
|
|
||||||
|
# Créer le filtre Butterworth
|
||||||
|
low = lowcut / nyq
|
||||||
|
high = highcut / nyq
|
||||||
|
b, a = butter(4, [low, high], btype='band')
|
||||||
|
|
||||||
|
# Appliquer le filtre (filtfilt pour éviter le déphasage)
|
||||||
|
filtered_signal = filtfilt(b, a, signal_clean)
|
||||||
|
filtered_signals.append(filtered_signal)
|
||||||
|
|
||||||
|
# Le temps reste le même après filtrage
|
||||||
|
time_filtered = time
|
||||||
|
|
||||||
|
return filtered_signals, dominant_freqs, time_filtered
|
||||||
|
|
||||||
|
|
||||||
|
def analyze_signal_Hilbert(time, e_signal, s_signal):
|
||||||
|
"""
|
||||||
|
Analyzes the dominant frequencies, phase shift, time shift, and periods between two signals e_signal(t) and s_signal(t) from a DataFrame.
|
||||||
|
Uses Hilbert transform method for phase shift calculation (single mode only).
|
||||||
|
"""
|
||||||
|
# Extract signals and time
|
||||||
|
#time = df[time_column].values
|
||||||
|
#e_signal = df[e_signal_column].values
|
||||||
|
#s_signal = df[s_signal_column].values
|
||||||
|
|
||||||
|
# Calculate sampling period and rate
|
||||||
|
dt = np.mean(np.diff(time))
|
||||||
|
fs = 1 / dt
|
||||||
|
|
||||||
|
# Remove mean to eliminate DC component
|
||||||
|
e_signal_clean = e_signal - np.mean(e_signal)
|
||||||
|
s_signal_clean = s_signal - np.mean(s_signal)
|
||||||
|
|
||||||
|
# Compute FFT
|
||||||
|
n = len(time)
|
||||||
|
e_fft = fft(e_signal_clean)
|
||||||
|
s_fft = fft(s_signal_clean)
|
||||||
|
freqs = fftfreq(n, dt)
|
||||||
|
|
||||||
|
# Get positive frequencies only
|
||||||
|
positive_mask = freqs > 0
|
||||||
|
freqs_pos = freqs[positive_mask]
|
||||||
|
e_fft_pos = e_fft[positive_mask]
|
||||||
|
s_fft_pos = s_fft[positive_mask]
|
||||||
|
|
||||||
|
# Find dominant frequencies using peak detection
|
||||||
|
e_magnitude = np.abs(e_fft_pos)
|
||||||
|
s_magnitude = np.abs(s_fft_pos)
|
||||||
|
|
||||||
|
# Find peaks for e signal
|
||||||
|
e_peaks, _ = find_peaks(e_magnitude, height=0.1*np.max(e_magnitude))
|
||||||
|
e_peak_freqs = freqs_pos[e_peaks]
|
||||||
|
e_peak_mags = e_magnitude[e_peaks]
|
||||||
|
|
||||||
|
# Find peaks for s signal
|
||||||
|
s_peaks, _ = find_peaks(s_magnitude, height=0.1*np.max(s_magnitude))
|
||||||
|
s_peak_freqs = freqs_pos[s_peaks]
|
||||||
|
s_peak_mags = s_magnitude[s_peaks]
|
||||||
|
|
||||||
|
# Sort peaks by magnitude and select the top one
|
||||||
|
e_idx = np.argsort(e_peak_mags)[-1]
|
||||||
|
s_idx = np.argsort(s_peak_mags)[-1]
|
||||||
|
|
||||||
|
freq_e = e_peak_freqs[e_idx]
|
||||||
|
freq_s = s_peak_freqs[s_idx]
|
||||||
|
|
||||||
|
# Check if frequencies match within 1%
|
||||||
|
if np.abs(freq_e - freq_s) / ((freq_e + freq_s)/2) > 0.01:
|
||||||
|
raise ValueError("Frequency difference exceeds 1%. Phase shift cannot be determined.")
|
||||||
|
|
||||||
|
# Calculate mean frequency for phase shift calculation
|
||||||
|
mean_freq = (freq_e + freq_s) / 2
|
||||||
|
|
||||||
|
# Create a bandpass filter around the mean frequency
|
||||||
|
nyq = 0.5 * fs
|
||||||
|
low = (mean_freq - 0.1 * mean_freq) / nyq
|
||||||
|
high = (mean_freq + 0.1 * mean_freq) / nyq
|
||||||
|
|
||||||
|
if low <= 0:
|
||||||
|
low = 0.01
|
||||||
|
if high >= 1:
|
||||||
|
high = 0.99
|
||||||
|
|
||||||
|
b, a = butter(4, [low, high], btype='band')
|
||||||
|
|
||||||
|
# Filter both signals
|
||||||
|
e_filtered = filtfilt(b, a, e_signal_clean)
|
||||||
|
s_filtered = filtfilt(b, a, s_signal_clean)
|
||||||
|
|
||||||
|
# Apply Hilbert transform to filtered signals
|
||||||
|
e_analytic_filtered = hilbert(e_filtered)
|
||||||
|
s_analytic_filtered = hilbert(s_filtered)
|
||||||
|
|
||||||
|
# Extract phase
|
||||||
|
e_phase_filtered = np.unwrap(np.angle(e_analytic_filtered))
|
||||||
|
s_phase_filtered = np.unwrap(np.angle(s_analytic_filtered))
|
||||||
|
|
||||||
|
# Calculate phase difference
|
||||||
|
phase_diff = s_phase_filtered - e_phase_filtered
|
||||||
|
|
||||||
|
# Average phase difference over the stable part of the signal
|
||||||
|
n_stable = len(phase_diff) // 4
|
||||||
|
stable_phase_diff = phase_diff[n_stable:-n_stable]
|
||||||
|
|
||||||
|
# Calculate mean phase difference
|
||||||
|
mean_phase_diff = np.mean(stable_phase_diff)
|
||||||
|
|
||||||
|
# Normalize to [-π, π]
|
||||||
|
mean_phase_diff = np.arctan2(np.sin(mean_phase_diff), np.cos(mean_phase_diff))
|
||||||
|
|
||||||
|
# Convert to degrees
|
||||||
|
phase_diff_deg = np.degrees(mean_phase_diff)
|
||||||
|
|
||||||
|
# Calculate time shift
|
||||||
|
time_shift = mean_phase_diff / (2 * np.pi * mean_freq)
|
||||||
|
|
||||||
|
# Calculate periods
|
||||||
|
period_e = 1 / freq_e
|
||||||
|
period_s = 1 / freq_s
|
||||||
|
|
||||||
|
print(f'phase = {mean_phase_diff}')
|
||||||
|
return (period_e, period_s, freq_e, freq_s,
|
||||||
|
mean_phase_diff, phase_diff_deg, time_shift)
|
||||||
|
|
||||||
|
def analyze_signal_sinfit(time, e_signal, s_signal):
|
||||||
|
"""
|
||||||
|
Analyzes the dominant frequencies, phase shift, time shift, and periods between two signals e_signal(t) and s_signal(t) from a DataFrame.
|
||||||
|
Uses curve fitting method for phase shift calculation (single mode only).
|
||||||
|
"""
|
||||||
|
# Extract signals and time
|
||||||
|
#time = df[time_column].values
|
||||||
|
#e_signal = df[e_signal_column].values
|
||||||
|
#s_signal = df[s_signal_column].values
|
||||||
|
|
||||||
|
# Calculate sampling period and rate
|
||||||
|
dt = np.mean(np.diff(time))
|
||||||
|
fs = 1 / dt
|
||||||
|
|
||||||
|
# Remove mean to eliminate DC component
|
||||||
|
e_signal_clean = e_signal - np.mean(e_signal)
|
||||||
|
s_signal_clean = s_signal - np.mean(s_signal)
|
||||||
|
|
||||||
|
# Compute FFT
|
||||||
|
n = len(time)
|
||||||
|
e_fft = fft(e_signal_clean)
|
||||||
|
s_fft = fft(s_signal_clean)
|
||||||
|
freqs = fftfreq(n, dt)
|
||||||
|
|
||||||
|
# Get positive frequencies only
|
||||||
|
positive_mask = freqs > 0
|
||||||
|
freqs_pos = freqs[positive_mask]
|
||||||
|
e_fft_pos = e_fft[positive_mask]
|
||||||
|
s_fft_pos = s_fft[positive_mask]
|
||||||
|
|
||||||
|
# Find dominant frequencies using peak detection
|
||||||
|
e_magnitude = np.abs(e_fft_pos)
|
||||||
|
s_magnitude = np.abs(s_fft_pos)
|
||||||
|
|
||||||
|
# Find peaks for e signal
|
||||||
|
e_peaks, _ = find_peaks(e_magnitude, height=0.1*np.max(e_magnitude))
|
||||||
|
e_peak_freqs = freqs_pos[e_peaks]
|
||||||
|
e_peak_mags = e_magnitude[e_peaks]
|
||||||
|
|
||||||
|
# Find peaks for s signal
|
||||||
|
s_peaks, _ = find_peaks(s_magnitude, height=0.1*np.max(s_magnitude))
|
||||||
|
s_peak_freqs = freqs_pos[s_peaks]
|
||||||
|
s_peak_mags = s_magnitude[s_peaks]
|
||||||
|
|
||||||
|
# Sort peaks by magnitude and select the top one
|
||||||
|
e_idx = np.argsort(e_peak_mags)[-1]
|
||||||
|
s_idx = np.argsort(s_peak_mags)[-1]
|
||||||
|
|
||||||
|
freq_e = e_peak_freqs[e_idx]
|
||||||
|
freq_s = s_peak_freqs[s_idx]
|
||||||
|
|
||||||
|
# Check if frequencies match within 1%
|
||||||
|
if np.abs(freq_e - freq_s) / ((freq_e + freq_s)/2) > 0.01:
|
||||||
|
raise ValueError("Frequency difference exceeds 1%. Phase shift cannot be determined.")
|
||||||
|
|
||||||
|
# Calculate mean frequency for phase shift calculation
|
||||||
|
mean_freq = (freq_e + freq_s) / 2
|
||||||
|
|
||||||
|
# Define sine function for fitting
|
||||||
|
def sine_func(t, A, phi, offset):
|
||||||
|
return A * np.sin(2 * np.pi * mean_freq * t + phi) + offset
|
||||||
|
|
||||||
|
# Fit sine wave to e signal
|
||||||
|
try:
|
||||||
|
popt_e, _ = curve_fit(sine_func, time, e_signal,
|
||||||
|
p0=[np.std(e_signal), 0, np.mean(e_signal)],
|
||||||
|
bounds=([0, -np.pi, -np.inf], [np.inf, np.pi, np.inf]))
|
||||||
|
except:
|
||||||
|
popt_e = [np.std(e_signal), 0, np.mean(e_signal)]
|
||||||
|
|
||||||
|
# Fit sine wave to s signal
|
||||||
|
try:
|
||||||
|
popt_s, _ = curve_fit(sine_func, time, s_signal,
|
||||||
|
p0=[np.std(s_signal), 0, np.mean(s_signal)],
|
||||||
|
bounds=([0, -np.pi, -np.inf], [np.inf, np.pi, np.inf]))
|
||||||
|
except:
|
||||||
|
popt_s = [np.std(s_signal), 0, np.mean(s_signal)]
|
||||||
|
|
||||||
|
# Calculate phase difference
|
||||||
|
phase_diff = popt_s[1] - popt_e[1]
|
||||||
|
|
||||||
|
# Normalize to [-π, π]
|
||||||
|
phase_diff = np.arctan2(np.sin(phase_diff), np.cos(phase_diff))
|
||||||
|
|
||||||
|
# Convert to degrees
|
||||||
|
phase_diff_deg = np.degrees(phase_diff)
|
||||||
|
|
||||||
|
# Calculate time shift
|
||||||
|
time_shift = phase_diff / (2 * np.pi * mean_freq)
|
||||||
|
|
||||||
|
# Calculate periods
|
||||||
|
period_e = 1 / freq_e
|
||||||
|
period_s = 1 / freq_s
|
||||||
|
|
||||||
|
print(f'phase = {phase_diff}')
|
||||||
|
return (period_e, period_s, freq_e, freq_s,
|
||||||
|
phase_diff, phase_diff_deg, time_shift)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def analyze_signal_cross_correlation(time, e_signal, s_signal):
|
||||||
|
"""
|
||||||
|
Analyzes signals using cross-correlation method for phase shift calculation (single mode only).
|
||||||
|
"""
|
||||||
|
# Extract signals and time
|
||||||
|
#time = df[time_column].values
|
||||||
|
#e_signal = df[e_signal_column].values
|
||||||
|
#s_signal = df[s_signal_column].values
|
||||||
|
|
||||||
|
# Calculate sampling period and rate
|
||||||
|
dt = np.mean(np.diff(time))
|
||||||
|
fs = 1 / dt
|
||||||
|
|
||||||
|
# Remove mean to eliminate DC component
|
||||||
|
e_signal_clean = e_signal - np.mean(e_signal)
|
||||||
|
s_signal_clean = s_signal - np.mean(s_signal)
|
||||||
|
|
||||||
|
# Compute FFT
|
||||||
|
n = len(time)
|
||||||
|
e_fft = fft(e_signal_clean)
|
||||||
|
s_fft = fft(s_signal_clean)
|
||||||
|
freqs = fftfreq(n, dt)
|
||||||
|
|
||||||
|
# Get positive frequencies only
|
||||||
|
positive_mask = freqs > 0
|
||||||
|
freqs_pos = freqs[positive_mask]
|
||||||
|
e_fft_pos = e_fft[positive_mask]
|
||||||
|
s_fft_pos = s_fft[positive_mask]
|
||||||
|
|
||||||
|
# Find dominant frequencies using peak detection
|
||||||
|
e_magnitude = np.abs(e_fft_pos)
|
||||||
|
s_magnitude = np.abs(s_fft_pos)
|
||||||
|
|
||||||
|
# Find peaks for e signal
|
||||||
|
e_peaks, _ = find_peaks(e_magnitude, height=0.1*np.max(e_magnitude))
|
||||||
|
e_peak_freqs = freqs_pos[e_peaks]
|
||||||
|
e_peak_mags = e_magnitude[e_peaks]
|
||||||
|
|
||||||
|
# Find peaks for s signal
|
||||||
|
s_peaks, _ = find_peaks(s_magnitude, height=0.1*np.max(s_magnitude))
|
||||||
|
s_peak_freqs = freqs_pos[s_peaks]
|
||||||
|
s_peak_mags = s_magnitude[s_peaks]
|
||||||
|
|
||||||
|
# Sort peaks by magnitude and select the top one
|
||||||
|
e_idx = np.argsort(e_peak_mags)[-1]
|
||||||
|
s_idx = np.argsort(s_peak_mags)[-1]
|
||||||
|
|
||||||
|
freq_e = e_peak_freqs[e_idx]
|
||||||
|
freq_s = s_peak_freqs[s_idx]
|
||||||
|
|
||||||
|
# Check if frequencies match within 1%
|
||||||
|
if np.abs(freq_e - freq_s) / ((freq_e + freq_s)/2) > 0.01:
|
||||||
|
raise ValueError("Frequency difference exceeds 1%. Phase shift cannot be determined.")
|
||||||
|
|
||||||
|
# Calculate mean frequency for phase shift calculation
|
||||||
|
mean_freq = (freq_e + freq_s) / 2
|
||||||
|
|
||||||
|
# Create a bandpass filter around the mean frequency
|
||||||
|
nyq = 0.5 * fs
|
||||||
|
low = (mean_freq - 0.1 * mean_freq) / nyq
|
||||||
|
high = (mean_freq + 0.1 * mean_freq) / nyq
|
||||||
|
|
||||||
|
if low <= 0:
|
||||||
|
low = 0.01
|
||||||
|
if high >= 1:
|
||||||
|
high = 0.99
|
||||||
|
|
||||||
|
b, a = butter(4, [low, high], btype='band')
|
||||||
|
|
||||||
|
# Filter both signals
|
||||||
|
e_filtered = filtfilt(b, a, e_signal_clean)
|
||||||
|
s_filtered = filtfilt(b, a, s_signal_clean)
|
||||||
|
|
||||||
|
# Compute cross-correlation
|
||||||
|
correlation = correlate(s_filtered, e_filtered, mode='full')
|
||||||
|
lags = np.arange(-len(e_filtered) + 1, len(e_filtered))
|
||||||
|
|
||||||
|
# Find the lag with maximum correlation
|
||||||
|
max_lag = lags[np.argmax(correlation)]
|
||||||
|
|
||||||
|
# Calculate time shift
|
||||||
|
time_shift = max_lag * dt
|
||||||
|
|
||||||
|
# Calculate phase shift
|
||||||
|
phase_diff = 2 * np.pi * mean_freq * time_shift
|
||||||
|
|
||||||
|
# Normalize to [-π, π]
|
||||||
|
phase_diff = np.arctan2(np.sin(phase_diff), np.cos(phase_diff))
|
||||||
|
|
||||||
|
# Convert to degrees
|
||||||
|
phase_diff_deg = np.degrees(phase_diff)
|
||||||
|
|
||||||
|
# Calculate periods
|
||||||
|
period_e = 1 / freq_e
|
||||||
|
period_s = 1 / freq_s
|
||||||
|
|
||||||
|
print(f'phase = {phase_diff}')
|
||||||
|
return (period_e, period_s, freq_e, freq_s,
|
||||||
|
phase_diff, phase_diff_deg, time_shift)
|
||||||
|
|
||||||
|
|
||||||
|
def analyze_signal_wavelet(time, e_signal, s_signal):
|
||||||
|
"""
|
||||||
|
Analyzes signals using wavelet transform for phase shift calculation (single mode only).
|
||||||
|
"""
|
||||||
|
# Extract signals and time
|
||||||
|
#time = df[time_column].values
|
||||||
|
#e_signal = df[e_signal_column].values
|
||||||
|
#s_signal = df[s_signal_column].values
|
||||||
|
|
||||||
|
# Calculate sampling period and rate
|
||||||
|
dt = np.mean(np.diff(time))
|
||||||
|
fs = 1 / dt
|
||||||
|
|
||||||
|
# Remove mean to eliminate DC component
|
||||||
|
e_signal_clean = e_signal - np.mean(e_signal)
|
||||||
|
s_signal_clean = s_signal - np.mean(s_signal)
|
||||||
|
|
||||||
|
# Compute FFT
|
||||||
|
n = len(time)
|
||||||
|
e_fft = fft(e_signal_clean)
|
||||||
|
s_fft = fft(s_signal_clean)
|
||||||
|
freqs = fftfreq(n, dt)
|
||||||
|
|
||||||
|
# Get positive frequencies only
|
||||||
|
positive_mask = freqs > 0
|
||||||
|
freqs_pos = freqs[positive_mask]
|
||||||
|
e_fft_pos = e_fft[positive_mask]
|
||||||
|
s_fft_pos = s_fft[positive_mask]
|
||||||
|
|
||||||
|
# Find dominant frequencies using peak detection
|
||||||
|
e_magnitude = np.abs(e_fft_pos)
|
||||||
|
s_magnitude = np.abs(s_fft_pos)
|
||||||
|
|
||||||
|
# Find peaks for e signal
|
||||||
|
e_peaks, _ = find_peaks(e_magnitude, height=0.1*np.max(e_magnitude))
|
||||||
|
e_peak_freqs = freqs_pos[e_peaks]
|
||||||
|
e_peak_mags = e_magnitude[e_peaks]
|
||||||
|
|
||||||
|
# Find peaks for s signal
|
||||||
|
s_peaks, _ = find_peaks(s_magnitude, height=0.1*np.max(s_magnitude))
|
||||||
|
s_peak_freqs = freqs_pos[s_peaks]
|
||||||
|
s_peak_mags = s_magnitude[s_peaks]
|
||||||
|
|
||||||
|
# Sort peaks by magnitude and select the top one
|
||||||
|
e_idx = np.argsort(e_peak_mags)[-1]
|
||||||
|
s_idx = np.argsort(s_peak_mags)[-1]
|
||||||
|
|
||||||
|
freq_e = e_peak_freqs[e_idx]
|
||||||
|
freq_s = s_peak_freqs[s_idx]
|
||||||
|
|
||||||
|
# Check if frequencies match within 1%
|
||||||
|
if np.abs(freq_e - freq_s) / ((freq_e + freq_s)/2) > 0.01:
|
||||||
|
raise ValueError("Frequency difference exceeds 1%. Phase shift cannot be determined.")
|
||||||
|
|
||||||
|
# Calculate mean frequency for phase shift calculation
|
||||||
|
mean_freq = (freq_e + freq_s) / 2
|
||||||
|
|
||||||
|
# Perform continuous wavelet transform
|
||||||
|
scales = np.arange(1, 128)
|
||||||
|
coefficients_e, frequencies_e = pywt.cwt(e_signal_clean, scales, 'morl', sampling_period=dt)
|
||||||
|
coefficients_s, frequencies_s = pywt.cwt(s_signal_clean, scales, 'morl', sampling_period=dt)
|
||||||
|
|
||||||
|
# Find the scale index closest to the mean frequency
|
||||||
|
scale_idx = np.argmin(np.abs(frequencies_e - mean_freq))
|
||||||
|
|
||||||
|
# Extract the wavelet coefficients at this scale
|
||||||
|
coeffs_e = coefficients_e[scale_idx, :]
|
||||||
|
coeffs_s = coefficients_s[scale_idx, :]
|
||||||
|
|
||||||
|
# Calculate the instantaneous phase using the Hilbert transform
|
||||||
|
analytic_e = hilbert(coeffs_e)
|
||||||
|
analytic_s = hilbert(coeffs_s)
|
||||||
|
|
||||||
|
phase_e = np.unwrap(np.angle(analytic_e))
|
||||||
|
phase_s = np.unwrap(np.angle(analytic_s))
|
||||||
|
|
||||||
|
# Calculate phase difference
|
||||||
|
phase_diff = phase_s - phase_e
|
||||||
|
|
||||||
|
# Average phase difference over the stable part of the signal
|
||||||
|
n_stable = len(phase_diff) // 4
|
||||||
|
stable_phase_diff = phase_diff[n_stable:-n_stable]
|
||||||
|
|
||||||
|
# Calculate mean phase difference
|
||||||
|
mean_phase_diff = np.mean(stable_phase_diff)
|
||||||
|
|
||||||
|
# Normalize to [-π, π]
|
||||||
|
mean_phase_diff = np.arctan2(np.sin(mean_phase_diff), np.cos(mean_phase_diff))
|
||||||
|
|
||||||
|
# Convert to degrees
|
||||||
|
phase_diff_deg = np.degrees(mean_phase_diff)
|
||||||
|
|
||||||
|
# Calculate time shift
|
||||||
|
time_shift = mean_phase_diff / (2 * np.pi * mean_freq)
|
||||||
|
|
||||||
|
# Calculate periods
|
||||||
|
period_e = 1 / freq_e
|
||||||
|
period_s = 1 / freq_s
|
||||||
|
|
||||||
|
print(f'phase = {mean_phase_diff}')
|
||||||
|
return (period_e, period_s, freq_e, freq_s,
|
||||||
|
mean_phase_diff, phase_diff_deg, time_shift)
|
|
@ -1,3 +1,4 @@
|
||||||
numpy
|
numpy
|
||||||
scipy
|
scipy
|
||||||
pandas
|
pandas
|
||||||
|
PyWavelets
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue