gaitsetpy.features.utils

  1import numpy as np
  2from scipy.stats import skew, kurtosis, entropy
  3from scipy.signal import welch, find_peaks
  4from scipy.fft import fft
  5from statsmodels.tsa.ar_model import AutoReg
  6
  7
  8def calculate_stride_times(signal, fs):
  9    """
 10    Calculate stride times from a signal using peak detection.
 11    Args:
 12        signal (np.array): Input signal.
 13        fs (int): Sampling frequency.
 14    Returns:
 15        avg_stride_time (float): Average stride time.
 16    """
 17    peaks, _ = find_peaks(signal)
 18    stride_times = np.diff(peaks) / fs
 19    avg_stride_time = np.mean(stride_times) if len(stride_times) > 0 else 0
 20    return avg_stride_time
 21
 22def calculate_zero_crossing_rate(signal):
 23    """
 24    Calculate the zero-crossing rate of a signal.
 25    Args:
 26        signal (np.array): Input signal.
 27    Returns:
 28        zcr (float): Zero-crossing rate.
 29    """
 30    n = len(signal)
 31    zcr = 1 / (n - 1) * sum(0.5 * abs(np.sign(signal[i + 1]) - np.sign(signal[i])) for i in range(n - 1))
 32    return zcr
 33
 34def calculate_power(signal, fs, band):
 35    """
 36    Calculate the power of a signal in a specific frequency band.
 37    Args:
 38        signal (np.array): Input signal.
 39        fs (int): Sampling frequency.
 40        band (tuple): Frequency band (low, high).
 41    Returns:
 42        band_power (float): Power in the specified frequency band.
 43    """
 44    # f, Pxx = welch(signal, fs=fs, nperseg=min(len(signal), 1024))
 45    f, Pxx = welch(signal, fs=fs, nperseg = min(len(signal), 192))  # Ensure nperseg ≤ length)
 46    band_power = np.trapz(Pxx[(f >= band[0]) & (f <= band[1])], f[(f >= band[0]) & (f <= band[1])])
 47    return band_power
 48
 49def calculate_freezing_index(signal, fs):
 50    """
 51    Calculate the freezing index of a signal.
 52    Args:
 53        signal (np.array): Input signal.
 54        fs (int): Sampling frequency.
 55    Returns:
 56        freezing_index (float): Freezing index.
 57    """
 58    power_3_8 = calculate_power(signal, fs, (3, 8))
 59    power_0_5_3 = calculate_power(signal, fs, (0.5, 3))
 60    freezing_index = power_3_8 / power_0_5_3 if power_0_5_3 != 0 else 0
 61    return freezing_index
 62
 63def calculate_standard_deviation(signal):
 64    """
 65    Calculate the standard deviation of a signal.
 66    Args:
 67        signal (np.array): Input signal.
 68    Returns:
 69        std_dev (float): Standard deviation.
 70    """
 71    return np.std(signal)
 72
 73def calculate_entropy(signal):
 74    """
 75    Calculate the entropy of a signal.
 76    Args:
 77        signal (np.array): Input signal.
 78    Returns:
 79        entropy_value (float): Entropy.
 80    """
 81    value, counts = np.unique(signal, return_counts=True)
 82    probabilities = counts / len(signal)
 83    return entropy(probabilities, base=2)
 84
 85def calculate_energy(signal):
 86    """
 87    Calculate the energy of a signal.
 88    Args:
 89        signal (np.array): Input signal.
 90    Returns:
 91        energy (float): Energy.
 92    """
 93    return np.sum(signal ** 2)
 94
 95def calculate_variance(signal):
 96    """
 97    Calculate the variance of a signal.
 98    Args:
 99        signal (np.array): Input signal.
100    Returns:
101        variance (float): Variance.
102    """
103    return np.var(signal)
104
105def calculate_kurtosis(signal):
106    """
107    Calculate the kurtosis of a signal.
108    Args:
109        signal (np.array): Input signal.
110    Returns:
111        kurtosis_value (float): Kurtosis.
112    """
113    try:
114        return kurtosis(signal, fisher=False)
115    except Exception as e:
116        print(f"An error occurred in feature 'kurtosis': {e}")
117        return 0
118
119def calculate_step_time(signal, fs):
120    """
121    Calculate step times from a signal using peak detection.
122    Args:
123        signal (np.array): Input signal.
124        fs (int): Sampling frequency.
125    Returns:
126        step_times (np.array): Array of step times.
127    """
128    peaks, _ = find_peaks(signal)
129    step_times = np.diff(peaks) / fs
130    return step_times
131
132def calculate_mean(signal):
133    """Calculate the mean of the signal."""
134    return np.mean(signal)
135
136def calculate_max(signal):
137    """Calculate the maximum value of the signal."""
138    return np.max(signal)
139
140def calculate_min(signal):
141    """Calculate the minimum value of the signal."""
142    return np.min(signal)
143
144def calculate_median(signal):
145    """Calculate the median of the signal."""
146    return np.median(signal)
147
148def calculate_skewness(signal):
149    """Calculate the skewness of the signal."""
150    try:
151        return skew(signal)
152    except Exception as e:
153        print(f"An error occurred in skewness: {e}")
154        return 0
155
156def calculate_root_mean_square(signal):
157    """Calculate the root mean square of the signal."""
158    return np.sqrt(np.mean(np.square(signal)))
159
160def calculate_range(signal):
161    """Calculate the range of the signal."""
162    return np.max(signal) - np.min(signal)
163
164def calculate_correlation(signal1, signal2):
165    """Calculate the correlation between two signals."""
166    return np.corrcoef(signal1, signal2)[0, 1]
167
168def calculate_dominant_frequency(signal, fs):
169    """Calculate the dominant frequency of the signal."""
170    try:
171        fft_values = np.abs(fft(signal))
172        freqs = np.fft.fftfreq(len(signal), 1 / fs)
173        dominant_freq = freqs[np.argmax(fft_values)]
174        return dominant_freq
175    except Exception as e:
176        print(f"An error occurred: {e}")
177        return 0
178
179def calculate_peak_height(signal):
180    """Calculate the peak height of the signal."""
181    peaks, _ = find_peaks(signal)
182    return np.max(signal[peaks]) if len(peaks) > 0 else 0
183
184def calculate_interquartile_range(signal):
185    """Calculate the interquartile range of the signal."""
186    try:
187        q75, q25 = np.percentile(signal, [75, 25])
188        return q75 - q25
189    except Exception as e:
190        print(f"An error occurred in feature 'interquartile_range': {e}")
191        return 0
192
193def calculate_mode(signal):
194    """Calculate the mode of the signal."""
195    values, counts = np.unique(signal, return_counts=True)
196    return values[np.argmax(counts)]
197
198def calculate_cadence(signal, fs):
199    """Calculate the cadence (steps per minute) of the signal."""
200    peaks, _ = find_peaks(signal)
201    step_count = len(peaks)
202    duration = len(signal) / fs
203    return (step_count / duration) * 60
204
205def calculate_mean_absolute_value(signal):
206    """Calculate the mean absolute value of the signal."""
207    return np.mean(np.abs(signal))
208
209def calculate_median_absolute_deviation(signal):
210    """Calculate the median absolute deviation of the signal."""
211    return np.median(np.abs(signal - np.median(signal)))
212
213def calculate_peak_frequency(signal, fs):
214    """Calculate the peak frequency of the signal."""
215    try:
216        f, Pxx = welch(signal, fs=fs, nperseg=min(len(signal), 192))  # Ensure nperseg ≤ length
217        return f[np.argmax(Pxx)]
218    except Exception as e:
219        print(f"An error occurred in feature 'peak_frequency': {e}")
220        return 0
221
222def calculate_peak_width(signal, fs):
223    """Calculate the peak width of the signal."""
224    peaks, _ = find_peaks(signal)
225    if len(peaks) == 0:
226        return 0
227    peak_heights = signal[peaks]
228    half_max = np.max(peak_heights) / 2
229    widths = np.diff(np.where(signal > half_max)[0])
230    return np.mean(widths) / fs if len(widths) > 0 else 0
231
232def calculate_power_spectral_entropy(signal, fs):
233    """Calculate the power spectral entropy of the signal."""
234    try:
235        f, Pxx = welch(signal, fs=fs, nperseg=min(len(signal), 192))  # Ensure nperseg ≤ length
236        Pxx_norm = Pxx / np.sum(Pxx)
237        return -np.sum(Pxx_norm * np.log2(Pxx_norm + np.finfo(float).eps))
238    except Exception as e:
239        print(f"An error occurred in feature 'power spectral entropy': {e}")
240        return 0
241
242def calculate_principal_harmonic_frequency(signal, fs):
243    """Calculate the principal harmonic frequency of the signal."""
244    try:
245        fft_values = np.abs(fft(signal))
246        freqs = np.fft.fftfreq(len(signal), 1 / fs)
247        return freqs[np.argmax(fft_values)]
248    except Exception as e:
249        print(f"An error occurred in feature 'principal_harmonic_frequency': {e}")
250        return 0
251
252def calculate_auto_regression_coefficients(signal, order=3):
253    """Calculate the auto-regression coefficients of the signal."""
254    try:
255        model = AutoReg(signal, lags=order)
256        results = model.fit()
257        return results.params
258    except Exception as e:
259        print(f"An error occurred in feature 'auto_regression_coefficients': {e}")
260        return 0
def calculate_stride_times(signal, fs):
 9def calculate_stride_times(signal, fs):
10    """
11    Calculate stride times from a signal using peak detection.
12    Args:
13        signal (np.array): Input signal.
14        fs (int): Sampling frequency.
15    Returns:
16        avg_stride_time (float): Average stride time.
17    """
18    peaks, _ = find_peaks(signal)
19    stride_times = np.diff(peaks) / fs
20    avg_stride_time = np.mean(stride_times) if len(stride_times) > 0 else 0
21    return avg_stride_time

Calculate stride times from a signal using peak detection. Args: signal (np.array): Input signal. fs (int): Sampling frequency. Returns: avg_stride_time (float): Average stride time.

def calculate_zero_crossing_rate(signal):
23def calculate_zero_crossing_rate(signal):
24    """
25    Calculate the zero-crossing rate of a signal.
26    Args:
27        signal (np.array): Input signal.
28    Returns:
29        zcr (float): Zero-crossing rate.
30    """
31    n = len(signal)
32    zcr = 1 / (n - 1) * sum(0.5 * abs(np.sign(signal[i + 1]) - np.sign(signal[i])) for i in range(n - 1))
33    return zcr

Calculate the zero-crossing rate of a signal. Args: signal (np.array): Input signal. Returns: zcr (float): Zero-crossing rate.

def calculate_power(signal, fs, band):
35def calculate_power(signal, fs, band):
36    """
37    Calculate the power of a signal in a specific frequency band.
38    Args:
39        signal (np.array): Input signal.
40        fs (int): Sampling frequency.
41        band (tuple): Frequency band (low, high).
42    Returns:
43        band_power (float): Power in the specified frequency band.
44    """
45    # f, Pxx = welch(signal, fs=fs, nperseg=min(len(signal), 1024))
46    f, Pxx = welch(signal, fs=fs, nperseg = min(len(signal), 192))  # Ensure nperseg ≤ length)
47    band_power = np.trapz(Pxx[(f >= band[0]) & (f <= band[1])], f[(f >= band[0]) & (f <= band[1])])
48    return band_power

Calculate the power of a signal in a specific frequency band. Args: signal (np.array): Input signal. fs (int): Sampling frequency. band (tuple): Frequency band (low, high). Returns: band_power (float): Power in the specified frequency band.

def calculate_freezing_index(signal, fs):
50def calculate_freezing_index(signal, fs):
51    """
52    Calculate the freezing index of a signal.
53    Args:
54        signal (np.array): Input signal.
55        fs (int): Sampling frequency.
56    Returns:
57        freezing_index (float): Freezing index.
58    """
59    power_3_8 = calculate_power(signal, fs, (3, 8))
60    power_0_5_3 = calculate_power(signal, fs, (0.5, 3))
61    freezing_index = power_3_8 / power_0_5_3 if power_0_5_3 != 0 else 0
62    return freezing_index

Calculate the freezing index of a signal. Args: signal (np.array): Input signal. fs (int): Sampling frequency. Returns: freezing_index (float): Freezing index.

def calculate_standard_deviation(signal):
64def calculate_standard_deviation(signal):
65    """
66    Calculate the standard deviation of a signal.
67    Args:
68        signal (np.array): Input signal.
69    Returns:
70        std_dev (float): Standard deviation.
71    """
72    return np.std(signal)

Calculate the standard deviation of a signal. Args: signal (np.array): Input signal. Returns: std_dev (float): Standard deviation.

def calculate_entropy(signal):
74def calculate_entropy(signal):
75    """
76    Calculate the entropy of a signal.
77    Args:
78        signal (np.array): Input signal.
79    Returns:
80        entropy_value (float): Entropy.
81    """
82    value, counts = np.unique(signal, return_counts=True)
83    probabilities = counts / len(signal)
84    return entropy(probabilities, base=2)

Calculate the entropy of a signal. Args: signal (np.array): Input signal. Returns: entropy_value (float): Entropy.

def calculate_energy(signal):
86def calculate_energy(signal):
87    """
88    Calculate the energy of a signal.
89    Args:
90        signal (np.array): Input signal.
91    Returns:
92        energy (float): Energy.
93    """
94    return np.sum(signal ** 2)

Calculate the energy of a signal. Args: signal (np.array): Input signal. Returns: energy (float): Energy.

def calculate_variance(signal):
 96def calculate_variance(signal):
 97    """
 98    Calculate the variance of a signal.
 99    Args:
100        signal (np.array): Input signal.
101    Returns:
102        variance (float): Variance.
103    """
104    return np.var(signal)

Calculate the variance of a signal. Args: signal (np.array): Input signal. Returns: variance (float): Variance.

def calculate_kurtosis(signal):
106def calculate_kurtosis(signal):
107    """
108    Calculate the kurtosis of a signal.
109    Args:
110        signal (np.array): Input signal.
111    Returns:
112        kurtosis_value (float): Kurtosis.
113    """
114    try:
115        return kurtosis(signal, fisher=False)
116    except Exception as e:
117        print(f"An error occurred in feature 'kurtosis': {e}")
118        return 0

Calculate the kurtosis of a signal. Args: signal (np.array): Input signal. Returns: kurtosis_value (float): Kurtosis.

def calculate_step_time(signal, fs):
120def calculate_step_time(signal, fs):
121    """
122    Calculate step times from a signal using peak detection.
123    Args:
124        signal (np.array): Input signal.
125        fs (int): Sampling frequency.
126    Returns:
127        step_times (np.array): Array of step times.
128    """
129    peaks, _ = find_peaks(signal)
130    step_times = np.diff(peaks) / fs
131    return step_times

Calculate step times from a signal using peak detection. Args: signal (np.array): Input signal. fs (int): Sampling frequency. Returns: step_times (np.array): Array of step times.

def calculate_mean(signal):
133def calculate_mean(signal):
134    """Calculate the mean of the signal."""
135    return np.mean(signal)

Calculate the mean of the signal.

def calculate_max(signal):
137def calculate_max(signal):
138    """Calculate the maximum value of the signal."""
139    return np.max(signal)

Calculate the maximum value of the signal.

def calculate_min(signal):
141def calculate_min(signal):
142    """Calculate the minimum value of the signal."""
143    return np.min(signal)

Calculate the minimum value of the signal.

def calculate_median(signal):
145def calculate_median(signal):
146    """Calculate the median of the signal."""
147    return np.median(signal)

Calculate the median of the signal.

def calculate_skewness(signal):
149def calculate_skewness(signal):
150    """Calculate the skewness of the signal."""
151    try:
152        return skew(signal)
153    except Exception as e:
154        print(f"An error occurred in skewness: {e}")
155        return 0

Calculate the skewness of the signal.

def calculate_root_mean_square(signal):
157def calculate_root_mean_square(signal):
158    """Calculate the root mean square of the signal."""
159    return np.sqrt(np.mean(np.square(signal)))

Calculate the root mean square of the signal.

def calculate_range(signal):
161def calculate_range(signal):
162    """Calculate the range of the signal."""
163    return np.max(signal) - np.min(signal)

Calculate the range of the signal.

def calculate_correlation(signal1, signal2):
165def calculate_correlation(signal1, signal2):
166    """Calculate the correlation between two signals."""
167    return np.corrcoef(signal1, signal2)[0, 1]

Calculate the correlation between two signals.

def calculate_dominant_frequency(signal, fs):
169def calculate_dominant_frequency(signal, fs):
170    """Calculate the dominant frequency of the signal."""
171    try:
172        fft_values = np.abs(fft(signal))
173        freqs = np.fft.fftfreq(len(signal), 1 / fs)
174        dominant_freq = freqs[np.argmax(fft_values)]
175        return dominant_freq
176    except Exception as e:
177        print(f"An error occurred: {e}")
178        return 0

Calculate the dominant frequency of the signal.

def calculate_peak_height(signal):
180def calculate_peak_height(signal):
181    """Calculate the peak height of the signal."""
182    peaks, _ = find_peaks(signal)
183    return np.max(signal[peaks]) if len(peaks) > 0 else 0

Calculate the peak height of the signal.

def calculate_interquartile_range(signal):
185def calculate_interquartile_range(signal):
186    """Calculate the interquartile range of the signal."""
187    try:
188        q75, q25 = np.percentile(signal, [75, 25])
189        return q75 - q25
190    except Exception as e:
191        print(f"An error occurred in feature 'interquartile_range': {e}")
192        return 0

Calculate the interquartile range of the signal.

def calculate_mode(signal):
194def calculate_mode(signal):
195    """Calculate the mode of the signal."""
196    values, counts = np.unique(signal, return_counts=True)
197    return values[np.argmax(counts)]

Calculate the mode of the signal.

def calculate_cadence(signal, fs):
199def calculate_cadence(signal, fs):
200    """Calculate the cadence (steps per minute) of the signal."""
201    peaks, _ = find_peaks(signal)
202    step_count = len(peaks)
203    duration = len(signal) / fs
204    return (step_count / duration) * 60

Calculate the cadence (steps per minute) of the signal.

def calculate_mean_absolute_value(signal):
206def calculate_mean_absolute_value(signal):
207    """Calculate the mean absolute value of the signal."""
208    return np.mean(np.abs(signal))

Calculate the mean absolute value of the signal.

def calculate_median_absolute_deviation(signal):
210def calculate_median_absolute_deviation(signal):
211    """Calculate the median absolute deviation of the signal."""
212    return np.median(np.abs(signal - np.median(signal)))

Calculate the median absolute deviation of the signal.

def calculate_peak_frequency(signal, fs):
214def calculate_peak_frequency(signal, fs):
215    """Calculate the peak frequency of the signal."""
216    try:
217        f, Pxx = welch(signal, fs=fs, nperseg=min(len(signal), 192))  # Ensure nperseg ≤ length
218        return f[np.argmax(Pxx)]
219    except Exception as e:
220        print(f"An error occurred in feature 'peak_frequency': {e}")
221        return 0

Calculate the peak frequency of the signal.

def calculate_peak_width(signal, fs):
223def calculate_peak_width(signal, fs):
224    """Calculate the peak width of the signal."""
225    peaks, _ = find_peaks(signal)
226    if len(peaks) == 0:
227        return 0
228    peak_heights = signal[peaks]
229    half_max = np.max(peak_heights) / 2
230    widths = np.diff(np.where(signal > half_max)[0])
231    return np.mean(widths) / fs if len(widths) > 0 else 0

Calculate the peak width of the signal.

def calculate_power_spectral_entropy(signal, fs):
233def calculate_power_spectral_entropy(signal, fs):
234    """Calculate the power spectral entropy of the signal."""
235    try:
236        f, Pxx = welch(signal, fs=fs, nperseg=min(len(signal), 192))  # Ensure nperseg ≤ length
237        Pxx_norm = Pxx / np.sum(Pxx)
238        return -np.sum(Pxx_norm * np.log2(Pxx_norm + np.finfo(float).eps))
239    except Exception as e:
240        print(f"An error occurred in feature 'power spectral entropy': {e}")
241        return 0

Calculate the power spectral entropy of the signal.

def calculate_principal_harmonic_frequency(signal, fs):
243def calculate_principal_harmonic_frequency(signal, fs):
244    """Calculate the principal harmonic frequency of the signal."""
245    try:
246        fft_values = np.abs(fft(signal))
247        freqs = np.fft.fftfreq(len(signal), 1 / fs)
248        return freqs[np.argmax(fft_values)]
249    except Exception as e:
250        print(f"An error occurred in feature 'principal_harmonic_frequency': {e}")
251        return 0

Calculate the principal harmonic frequency of the signal.

def calculate_auto_regression_coefficients(signal, order=3):
253def calculate_auto_regression_coefficients(signal, order=3):
254    """Calculate the auto-regression coefficients of the signal."""
255    try:
256        model = AutoReg(signal, lags=order)
257        results = model.fit()
258        return results.params
259    except Exception as e:
260        print(f"An error occurred in feature 'auto_regression_coefficients': {e}")
261        return 0

Calculate the auto-regression coefficients of the signal.