Skip to content

Commit ed8abde

Browse files
smoiacelprov
andcommitted
enh: implement power related metrics and smoothness
Co-authored-by: celprov <[email protected]>
1 parent 904fabd commit ed8abde

File tree

1 file changed

+134
-0
lines changed

1 file changed

+134
-0
lines changed

physioqc/metrics/multimodal.py

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
"""These functions compute various non-modality dependent signal processing metrics."""
22
import numpy as np
33
import peakdet as pk
4+
from scipy import signal
5+
from scipy.misc import derivative
46

57
from .utils import physio_or_numpy
68

@@ -230,3 +232,135 @@ def peak_amplitude(ph: pk.Physio):
230232
peak_amplitude = peak_amp - trough_amp
231233

232234
return peak_amplitude
235+
236+
237+
def power_spectrum(data):
238+
"""
239+
Compute the power spectrum of the signal.
240+
241+
Parameters
242+
----------
243+
args : data
244+
a peakdet Physio object
245+
246+
Returns
247+
-------
248+
tuple :obj: tuple
249+
A tuple containing as the first element the frequencies and the second element
250+
the power spectrum
251+
"""
252+
freqs, psd = signal.welch(data.data, data.fs)
253+
254+
return freqs, psd
255+
256+
257+
def energy(data, lowf=None, highf=None):
258+
"""
259+
Calculate the energy in a certain frequency band.
260+
261+
Parameters
262+
----------
263+
args : data
264+
a peakdet Physio object
265+
args : lowf
266+
float that corresponds to the lower frequency band limit
267+
args : highf
268+
float that corresponds to the higher frequency band limit
269+
270+
Returns
271+
-------
272+
Float :obj:`numpy.ndarray`
273+
Energy in the defined frequency band
274+
"""
275+
freqs, psd = power_spectrum(data)
276+
277+
# Energy is defined as the square of the power spectral density
278+
energy_density = np.square(psd)
279+
280+
if lowf is None or highf is None:
281+
# If frequencies are not precised, compute the total power
282+
idx_band = np.ones(psd.shape)
283+
else:
284+
# Define frequency band
285+
idx_band = np.logical_and(freqs >= lowf, freqs <= highf)
286+
287+
energy = np.sum(energy_density[idx_band])
288+
289+
return energy
290+
291+
292+
def fALFF(data, lowf, highf):
293+
"""
294+
Calculate the fractional amplitude of low-frequency fluctuations (fALFF).
295+
296+
fALLF corresponds to the ratio of the energy in a frequency band over the
297+
total energy.
298+
299+
Parameters
300+
----------
301+
args : data
302+
a peakdet Physio object
303+
args : lowf
304+
float that corresponds to the lower frequency band limit
305+
args : highf
306+
float that corresponds to the higher frequency band limit
307+
308+
Returns
309+
-------
310+
Float :obj:`numpy.ndarray`
311+
fALFF
312+
"""
313+
# Extract energy in the frequency band
314+
band_energy = energy(data.data, lowf=lowf, highf=highf)
315+
316+
# Extract total energy
317+
total_energy = energy(data.data)
318+
319+
# Compute the relative energy
320+
rel_energy = band_energy / total_energy
321+
322+
return rel_energy
323+
324+
325+
def freq_energy(data, thr):
326+
"""
327+
Compute the minimum frequency with energy higher than the threshold.
328+
329+
Parameters
330+
----------
331+
args : data
332+
a peakdet Physio object
333+
args : thr
334+
Power threshold
335+
336+
Returns
337+
-------
338+
Float :obj:`numpy.ndarray`
339+
Minimum frequency with power higher than the threshold
340+
"""
341+
energy_nd = energy(data.data)
342+
freq = np.argmax(energy_nd > thr)
343+
344+
return freq
345+
346+
347+
def smoothness(data):
348+
"""
349+
Compute smoothness as the second derivative of the signal.
350+
351+
Parameters
352+
----------
353+
args : data
354+
a peakdet Physio object
355+
356+
Returns
357+
-------
358+
Float :obj:`numpy.ndarray`
359+
Smoothness
360+
"""
361+
time = np.arange(0, len(data.data) / data.fs, 1 / data.fs)
362+
dx2 = np.empty(len(time))
363+
for t in time:
364+
dx2[t] = derivative(data.data, t, n=2)
365+
366+
return smoothness

0 commit comments

Comments
 (0)