Skip to content

Commit

Permalink
implemented suggestions, code efficiency will be improved later
Browse files Browse the repository at this point in the history
  • Loading branch information
nienketimmermans committed Nov 15, 2024
1 parent 75541b8 commit 5014347
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 36 deletions.
8 changes: 4 additions & 4 deletions docs/notebooks/tremor/tremor_analysis.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
},
{
"cell_type": "code",
"execution_count": 1,
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -22,7 +22,7 @@
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -43,7 +43,7 @@
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -60,7 +60,7 @@
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
Expand Down
48 changes: 23 additions & 25 deletions src/paradigma/tremor/feature_extraction.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ def compute_welch_periodogram(
window_type: str = 'hann',
sampling_frequency: int = 100,
segment_length_s: float = 3,
overlap: float = 0.8,
overlap_fraction: float = 0.8,
spectral_resolution: float = 0.25
)-> tuple:
"""Estimate power spectral density of the gyroscope signal using Welch's method.
Expand All @@ -23,7 +23,7 @@ def compute_welch_periodogram(
The sampling frequency of the signal (default: 100)
segment_length_s: float
The length of each segment in seconds (default: 3)
overlap: float
overlap_fraction: float
The overlap between segments as fraction (default: 0.8)
spectral_resolution: float
The spectral resolution of the PSD in Hz (default: 0.25)
Expand All @@ -35,12 +35,12 @@ def compute_welch_periodogram(
"""

segment_length_n = sampling_frequency*segment_length_s
overlap_n = segment_length_n*overlap
overlap_n = segment_length_n*overlap_fraction
window = signal.get_window(window_type, segment_length_n,fftbins=False)
nfft = sampling_frequency/spectral_resolution

f, Pxx = signal.welch(values,sampling_frequency,window,segment_length_n,
overlap_n,nfft,detrend=False,scaling='density')
f, Pxx = signal.welch(x=values, fs=sampling_frequency, window=window, nperseg=segment_length_n,
noverlap=overlap_n, nfft=nfft, detrend=False, scaling='density')

return f, Pxx

Expand All @@ -49,7 +49,7 @@ def signal_to_PSD(
window_type: str = 'hann',
sampling_frequency: int = 100,
segment_length_s: float = 3,
overlap: float = 0.8,
overlap_fraction: float = 0.8,
spectral_resolution: float = 0.25
) -> tuple:
"""Estimate the power spectral density (Welch's method) of a signal per window.
Expand All @@ -64,7 +64,7 @@ def signal_to_PSD(
The sampling frequency of the signal (default: 100)
segment_length_s: float
The length of each segment in seconds (default: 3)
overlap: float
overlap_fraction: float
The overlap between segments as fraction (default: 0.8)
spectral_resolution: float
The spectral resolution of the PSD in Hz (default: 0.25)
Expand All @@ -82,7 +82,7 @@ def signal_to_PSD(
window_type=window_type,
sampling_frequency=sampling_frequency,
segment_length_s = segment_length_s,
overlap = overlap,
overlap_fraction = overlap_fraction,
spectral_resolution = spectral_resolution)
l_values_total.append(l_values)
l_freqs_total.append(l_freqs)
Expand All @@ -94,7 +94,7 @@ def compute_spectrogram(
window_type: str = 'hann',
sampling_frequency: int = 100,
segment_length_s: float = 2,
overlap: float = 0.8,
overlap_fraction: float = 0.8,
)-> tuple:

"""Compute the spectrogram (using short time fourier transform) of the gyroscope signal
Expand All @@ -109,7 +109,7 @@ def compute_spectrogram(
The sampling frequency of the signal (default: 100)
segment_length_s: float
The length of each segment in seconds (default: 2)
overlap: float
overlap_fraction: float
The overlap between segments as fraction (default: 0.8)
Returns
Expand All @@ -119,20 +119,20 @@ def compute_spectrogram(
"""

segment_length_n = sampling_frequency*segment_length_s
overlap_n = segment_length_n*overlap
overlap_n = segment_length_n*overlap_fraction
window = signal.get_window(window_type,segment_length_n)

f, t, S1 = signal.stft(values, fs=sampling_frequency, window=window, nperseg=segment_length_n,
f, t, S1 = signal.stft(x=values, fs=sampling_frequency, window=window, nperseg=segment_length_n,
noverlap=overlap_n,boundary=None)
S = np.abs(S1)*sampling_frequency
return S

return np.abs(S1)*sampling_frequency

def signal_to_spectrogram(
sensor_col: pd.Series,
window_type: str = 'hann',
sampling_frequency: int = 100,
segment_length_s: float = 2,
overlap: float = 0.8,
overlap_fraction: float = 0.8,
) -> list:

"""Compute the spectrogram (using short time fourier transform) of a signal per window.
Expand All @@ -147,7 +147,7 @@ def signal_to_spectrogram(
The sampling frequency of the signal (default: 100)
segment_length_s: float
The length of each segment in seconds (default: 2)
overlap: float
overlap_fraction: float
The overlap between segments as fraction (default: 0.8)
Returns
Expand All @@ -162,21 +162,19 @@ def signal_to_spectrogram(
window_type=window_type,
sampling_frequency=sampling_frequency,
segment_length_s = segment_length_s,
overlap = overlap
overlap_fraction = overlap_fraction
)
spectrogram.append(spectrogram_values)

return spectrogram

def melscale(x):
"Maps values of x to the melscale"
y = 64.875 * np.log10(1 + x/17.5)
return y
return 64.875 * np.log10(1 + x / 17.5)

def inverse_melscale(x):
"Inverse of the melscale"
y = 17.5 * (10**(x/64.875) - 1)
return y
return 17.5 * (10 ** (x / 64.875) - 1)

def generate_mel_frequency_cepstral_coefficients(
spectrogram: pd.Series,
Expand Down Expand Up @@ -372,20 +370,20 @@ def extract_spectral_domain_features(config, df_windowed):
sampling_frequency = config.sampling_frequency,
window_type = config.window_type,
segment_length_s = config.segment_length_s_psd,
overlap = config.overlap,
overlap_fraction = config.overlap_fraction,
spectral_resolution = config.spectral_resolution_psd
)
df_windowed[f'{col}_spectrogram'] = signal_to_spectrogram(
sensor_col = df_windowed[col],
sampling_frequency = config.sampling_frequency,
window_type = config.window_type,
segment_length_s = config.segment_length_s_mfcc,
overlap = config.overlap
overlap_fraction = config.overlap_fraction
)

# compute the total PSD and spectrogram (summed across the 3 gyroscope axes)
df_windowed['total_PSD'] = df_windowed.apply(lambda x: sum(x[y+'_PSD'] for y in config.l_gyroscope_cols), axis=1) # sum PSD over the axes
df_windowed['total_spectrogram'] = df_windowed.apply(lambda x: sum(x[y+'_spectrogram'] for y in config.l_gyroscope_cols), axis=1) # sum spectrogram over the axes
df_windowed['total_PSD'] = df_windowed[[f"{y}_PSD" for y in config.l_gyroscope_cols]].sum(axis=1)
df_windowed['total_spectrogram'] = df_windowed[[f"{y}_spectrogram"for y in config.l_gyroscope_cols]].sum(axis=1)

# compute the cepstral coefficients
mfcc_cols = generate_mel_frequency_cepstral_coefficients(
Expand Down
5 changes: 1 addition & 4 deletions src/paradigma/tremor/tremor_analysis.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import numpy as np
import tsdf
import pandas as pd
from pathlib import Path
from typing import Union
from sklearn.linear_model import LogisticRegression

import tsdf

from paradigma.constants import DataColumns
from paradigma.tremor.tremor_analysis_config import TremorFeatureExtractionConfig
from paradigma.tremor.feature_extraction import extract_spectral_domain_features
Expand All @@ -29,7 +27,6 @@ def extract_tremor_features_io(input_path: Union[str, Path], output_path: Union[
df = tsdf.load_dataframe_from_binaries([metadata_time, metadata_samples], tsdf.constants.ConcatenationType.columns)

# Extract tremor features

df_windowed = extract_tremor_features(df, config)

# Store data
Expand Down
6 changes: 3 additions & 3 deletions src/paradigma/tremor/tremor_analysis_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,15 @@ def __init__(self) -> None:
super().__init__()

self.set_sensor("gyroscope")
self.sampling_frequency: int=100
self.sampling_frequency: int = 100
self.window_length_s: float = 4
self.window_step_size_s: float = 4
self.single_value_cols: List[str] = None
self.list_value_cols: List[str] = (self.l_gyroscope_cols)
self.list_value_cols: List[str] = self.l_gyroscope_cols

# power spectral density
self.window_type = 'hann'
self.overlap: float = 0.8
self.overlap_fraction: float = 0.8
self.segment_length_s_psd: float = 3
self.spectral_resolution_psd: float = 0.25
self.fmin_peak: float = 1
Expand Down

0 comments on commit 5014347

Please sign in to comment.