From f336d439bde53c2ed87a2d08f4ac372baef82b2c Mon Sep 17 00:00:00 2001 From: Peter Kok Date: Tue, 20 Aug 2024 18:18:37 +0200 Subject: [PATCH 1/7] Expose functions at top-level and reorganize imports to avoid cyclic imports --- docs/notebooks/gait/gait_analysis.ipynb | 5 +-- src/paradigma/__init__.py | 34 ++++++++++++++++- src/paradigma/gait_analysis.py | 5 ++- src/paradigma/gait_analysis_config.py | 26 ++++++------- src/paradigma/heart_rate_analysis.py | 10 ++--- src/paradigma/imu_preprocessing.py | 51 ++++++++++++------------- src/paradigma/preprocessing_config.py | 18 ++++----- 7 files changed, 88 insertions(+), 61 deletions(-) diff --git a/docs/notebooks/gait/gait_analysis.ipynb b/docs/notebooks/gait/gait_analysis.ipynb index 290c57c..7797c52 100644 --- a/docs/notebooks/gait/gait_analysis.ipynb +++ b/docs/notebooks/gait/gait_analysis.ipynb @@ -18,10 +18,7 @@ "%autoreload 2\n", "\n", "import os\n", - "from paradigma.preprocessing_config import IMUPreprocessingConfig\n", - "from paradigma.gait_analysis import *\n", - "from paradigma.gait_analysis_config import *\n", - "from paradigma.imu_preprocessing import *" + "from paradigma import *" ] }, { diff --git a/src/paradigma/__init__.py b/src/paradigma/__init__.py index b068342..b75eddc 100644 --- a/src/paradigma/__init__.py +++ b/src/paradigma/__init__.py @@ -3,6 +3,36 @@ __version__ = version("paradigma") -from .imu_preprocessing import * +from .constants import DataColumns, TimeUnit, UNIX_TICKS_MS -__all__ = ["PreprocessingPipelineConfig"] +from .preprocessing_config import IMUPreprocessingConfig, PPGPreprocessingConfig +from .imu_preprocessing import preprocess_imu_data, transform_time_array, resample_data, butterworth_filter + +from .gait_analysis_config import GaitFeatureExtractionConfig, GaitDetectionConfig, \ + ArmSwingFeatureExtractionConfig, ArmSwingDetectionConfig, ArmSwingQuantificationConfig +from .gait_analysis import extract_gait_features, detect_gait, extract_arm_swing_features, \ + detect_arm_swing, quantify_arm_swing, aggregate_weekly_arm_swing + + +__all__ = [ + "DataColumns", + "TimeUnit", + "UNIX_TICKS_MS", + "IMUPreprocessingConfig", + "PPGPreprocessingConfig", + "preprocess_imu_data", + "transform_time_array", + "resample_data", + "butterworth_filter", + "GaitFeatureExtractionConfig", + "GaitDetectionConfig", + "ArmSwingFeatureExtractionConfig", + "ArmSwingDetectionConfig", + "ArmSwingQuantificationConfig", + "extract_gait_features", + "detect_gait", + "extract_arm_swing_features", + "detect_arm_swing", + "quantify_arm_swing", + "aggregate_weekly_arm_swing", +] diff --git a/src/paradigma/gait_analysis.py b/src/paradigma/gait_analysis.py index 8c9e6ea..c24bf19 100644 --- a/src/paradigma/gait_analysis.py +++ b/src/paradigma/gait_analysis.py @@ -2,6 +2,7 @@ import tsdf +import paradigma from paradigma.gait_analysis_config import * from paradigma.feature_extraction import * from paradigma.quantification import * @@ -189,8 +190,8 @@ def extract_arm_swing_features(input_path: str, output_path: str, config: ArmSwi # direction of the swing of the arm df[config.velocity_colname] = pca_transform_gyroscope( df=df, - y_gyro_colname=DataColumns.GYROSCOPE_Y, - z_gyro_colname=DataColumns.GYROSCOPE_Z, + y_gyro_colname=paradigma.DataColumns.GYROSCOPE_Y, + z_gyro_colname=paradigma.DataColumns.GYROSCOPE_Z, pred_gait_colname=config.pred_gait_colname ) diff --git a/src/paradigma/gait_analysis_config.py b/src/paradigma/gait_analysis_config.py index dffc84e..afb3a5d 100644 --- a/src/paradigma/gait_analysis_config.py +++ b/src/paradigma/gait_analysis_config.py @@ -1,5 +1,5 @@ from typing import Dict, List -from paradigma import DataColumns +import paradigma class GaitFeatureExtractionConfig: @@ -30,9 +30,9 @@ def __init__(self) -> None: self.time_colname = 'time' self.l_accelerometer_cols: List[str] = [ - DataColumns.ACCELEROMETER_X, - DataColumns.ACCELEROMETER_Y, - DataColumns.ACCELEROMETER_Z + paradigma.DataColumns.ACCELEROMETER_X, + paradigma.DataColumns.ACCELEROMETER_Y, + paradigma.DataColumns.ACCELEROMETER_Z ] self.l_gravity_cols: List[str] = [f'grav_{x}' for x in self.l_accelerometer_cols] @@ -94,7 +94,7 @@ def __init__(self) -> None: self.time_filename = 'gait_time.bin' self.values_filename = 'gait_values.bin' - self.l_accel_cols = [DataColumns.ACCELEROMETER_X, DataColumns.ACCELEROMETER_Y, DataColumns.ACCELEROMETER_Z] + self.l_accel_cols = [paradigma.DataColumns.ACCELEROMETER_X, paradigma.DataColumns.ACCELEROMETER_Y, paradigma.DataColumns.ACCELEROMETER_Z] self.time_colname = 'time' @@ -139,15 +139,15 @@ def initialize_column_names(self, time_colname='time', pred_gait_colname='pred_g self.segment_nr_colname = segment_nr_colname self.l_accelerometer_cols: List[str] = [ - DataColumns.ACCELEROMETER_X, - DataColumns.ACCELEROMETER_Y, - DataColumns.ACCELEROMETER_Z + paradigma.DataColumns.ACCELEROMETER_X, + paradigma.DataColumns.ACCELEROMETER_Y, + paradigma.DataColumns.ACCELEROMETER_Z ] self.l_gyroscope_cols: List[str] = [ - DataColumns.GYROSCOPE_X, - DataColumns.GYROSCOPE_Y, - DataColumns.GYROSCOPE_Z + paradigma.DataColumns.GYROSCOPE_X, + paradigma.DataColumns.GYROSCOPE_Y, + paradigma.DataColumns.GYROSCOPE_Z ] self.l_gravity_cols: List[str] = [f'grav_{x}' for x in self.l_accelerometer_cols] @@ -224,8 +224,8 @@ def __init__(self) -> None: self.time_filename = 'arm_swing_time.bin' self.values_filename = 'arm_swing_values.bin' - self.l_accel_cols = [DataColumns.ACCELEROMETER_X, DataColumns.ACCELEROMETER_Y, DataColumns.ACCELEROMETER_Z] - self.l_gyro_cols = [DataColumns.GYROSCOPE_X, DataColumns.GYROSCOPE_Y, DataColumns.GYROSCOPE_Z] + self.l_accel_cols = [paradigma.DataColumns.ACCELEROMETER_X, paradigma.DataColumns.ACCELEROMETER_Y, paradigma.DataColumns.ACCELEROMETER_Z] + self.l_gyro_cols = [paradigma.DataColumns.GYROSCOPE_X, paradigma.DataColumns.GYROSCOPE_Y, paradigma.DataColumns.GYROSCOPE_Z] class ArmSwingQuantificationConfig: diff --git a/src/paradigma/heart_rate_analysis.py b/src/paradigma/heart_rate_analysis.py index ba3ab3a..9a084f0 100644 --- a/src/paradigma/heart_rate_analysis.py +++ b/src/paradigma/heart_rate_analysis.py @@ -7,22 +7,22 @@ import tsdf import tsdf.constants +import paradigma from paradigma.heart_rate_analysis_config import HeartRateFeatureExtractionConfig from paradigma.heart_rate_util import extract_ppg_features, calculate_power_ratio, read_PPG_quality_classifier from paradigma.util import read_metadata, write_data, get_end_iso8601 -from paradigma.constants import DataColumns, UNIX_TICKS_MS def extract_signal_quality_features(input_path: str, classifier_path: str, output_path: str, config: HeartRateFeatureExtractionConfig) -> None: # load data metadata_time_ppg, metadata_samples_ppg = read_metadata(input_path, "PPG_meta.json", "PPG_time.bin", "PPG_samples.bin") df_ppg = tsdf.load_dataframe_from_binaries([metadata_time_ppg, metadata_samples_ppg], tsdf.constants.ConcatenationType.columns) - arr_ppg = df_ppg[DataColumns.PPG].to_numpy() - relative_time_ppg = df_ppg[DataColumns.TIME].to_numpy() + arr_ppg = df_ppg[paradigma.DataColumns.PPG].to_numpy() + relative_time_ppg = df_ppg[paradigma.DataColumns.TIME].to_numpy() metadata_time_acc, metadata_samples_acc = read_metadata(input_path, "accelerometer_meta.json", "accelerometer_time.bin", "accelerometer_samples.bin") df_acc = tsdf.load_dataframe_from_binaries([metadata_time_acc, metadata_samples_acc], tsdf.constants.ConcatenationType.columns) - arr_acc = df_acc[[DataColumns.ACCELEROMETER_X, DataColumns.ACCELEROMETER_Y, DataColumns.ACCELEROMETER_Z]].to_numpy() + arr_acc = df_acc[[paradigma.DataColumns.ACCELEROMETER_X, paradigma.DataColumns.ACCELEROMETER_Y, paradigma.DataColumns.ACCELEROMETER_Z]].to_numpy() sampling_frequency_ppg = config.sampling_frequency_ppg sampling_frequency_imu = config.sampling_frequency_imu @@ -96,7 +96,7 @@ def extract_signal_quality_features(input_path: str, classifier_path: str, outpu feature_acc.append(calculate_power_ratio(f1, PSD_imu, f2, PSD_ppg)) # Calculate the power ratio of the accelerometer signal in the PPG frequency range # time channel - t_unix_feat_total.append((relative_time_ppg[i] + ppg_start_time) * UNIX_TICKS_MS) # Save in absolute unix time ms + t_unix_feat_total.append((relative_time_ppg[i] + ppg_start_time) * paradigma.UNIX_TICKS_MS) # Save in absolute unix time ms acc_idx += samples_shift_acc # update IMU_idx # Convert lists to numpy arrays diff --git a/src/paradigma/imu_preprocessing.py b/src/paradigma/imu_preprocessing.py index dc88de6..0bb8c76 100644 --- a/src/paradigma/imu_preprocessing.py +++ b/src/paradigma/imu_preprocessing.py @@ -5,12 +5,11 @@ from scipy.interpolate import CubicSpline import tsdf -from paradigma.constants import DataColumns, TimeUnit +import paradigma from paradigma.util import write_data, read_metadata -from paradigma.preprocessing_config import IMUPreprocessingConfig -def preprocess_imu_data(input_path: str, output_path: str, config: IMUPreprocessingConfig) -> None: +def preprocess_imu_data(input_path: str, output_path: str, config: paradigma.preprocessing_config.IMUPreprocessingConfig) -> None: # Load data metadata_time, metadata_samples = read_metadata(input_path, config.meta_filename, config.time_filename, config.values_filename) @@ -24,20 +23,20 @@ def preprocess_imu_data(input_path: str, output_path: str, config: IMUPreprocess df[config.time_colname] = transform_time_array( time_array=df[config.time_colname], scale_factor=1000, - input_unit_type = TimeUnit.difference_ms, - output_unit_type = TimeUnit.relative_ms) + input_unit_type = paradigma.TimeUnit.difference_ms, + output_unit_type = paradigma.TimeUnit.relative_ms) df = resample_data( df=df, time_column=config.time_colname, - time_unit_type=TimeUnit.relative_ms, + time_unit_type=paradigma.TimeUnit.relative_ms, unscaled_column_names = list(config.d_channels_imu.keys()), scale_factors=metadata_samples.scale_factors, resampling_frequency=config.sampling_frequency) if config.side_watch == 'left': - df[DataColumns.ACCELEROMETER_X] *= -1 + df[paradigma.DataColumns.ACCELEROMETER_X] *= -1 for col in config.d_channels_accelerometer.keys(): @@ -73,8 +72,8 @@ def preprocess_imu_data(input_path: str, output_path: str, config: IMUPreprocess def transform_time_array( time_array: np.ndarray, scale_factor: float, - input_unit_type: TimeUnit, - output_unit_type: TimeUnit, + input_unit_type: paradigma.TimeUnit, + output_unit_type: paradigma.TimeUnit, start_time: float = 0.0, ) -> np.ndarray: """ @@ -86,10 +85,10 @@ def transform_time_array( The time array in milliseconds to transform. scale_factor : float The scale factor to apply to the time array. - input_unit_type : TimeUnit - The time unit type of the input time array. Raw PPP data was in `TimeUnit.difference_ms`. - output_unit_type : TimeUnit - The time unit type of the output time array. The processing is often done in `TimeUnit.relative_ms`. + input_unit_type : paradigma.TimeUnit + The time unit type of the input time array. Raw PPP data was in `paradigma.TimeUnit.difference_ms`. + output_unit_type : paradigma.TimeUnit + The time unit type of the output time array. The processing is often done in `paradigma.TimeUnit.relative_ms`. start_time : float, optional The start time of the time array in UNIX milliseconds (default is 0.0) @@ -98,28 +97,28 @@ def transform_time_array( time_array The transformed time array in milliseconds, with the specified time unit type. """ - # Scale time array and transform to relative time (`TimeUnit.relative_ms`) - if input_unit_type == TimeUnit.difference_ms: + # Scale time array and transform to relative time (`paradigma.TimeUnit.relative_ms`) + if input_unit_type == paradigma.TimeUnit.difference_ms: # Convert a series of differences into cumulative sum to reconstruct original time series. time_array = np.cumsum(np.double(time_array)) / scale_factor - elif input_unit_type == TimeUnit.absolute_ms: + elif input_unit_type == paradigma.TimeUnit.absolute_ms: # Set the start time if not provided. if np.isclose(start_time, 0.0, rtol=1e-09, atol=1e-09): start_time = time_array[0] # Convert absolute time stamps into a time series relative to start_time. time_array = (time_array - start_time) / scale_factor - elif input_unit_type == TimeUnit.relative_ms: + elif input_unit_type == paradigma.TimeUnit.relative_ms: # Scale the relative time series as per the scale_factor. time_array = time_array / scale_factor - # Transform the time array from `TimeUnit.relative_ms` to the specified time unit type - if output_unit_type == TimeUnit.absolute_ms: + # Transform the time array from `paradigma.TimeUnit.relative_ms` to the specified time unit type + if output_unit_type == paradigma.TimeUnit.absolute_ms: # Converts time array to absolute time by adding the start time to each element. time_array = time_array + start_time - elif output_unit_type == TimeUnit.difference_ms: + elif output_unit_type == paradigma.TimeUnit.difference_ms: # Creates a new array starting with 0, followed by the differences between consecutive elements. time_array = np.diff(np.insert(time_array, 0, start_time)) - elif output_unit_type == TimeUnit.relative_ms: + elif output_unit_type == paradigma.TimeUnit.relative_ms: # The array is already in relative format, do nothing. pass return time_array @@ -127,8 +126,8 @@ def transform_time_array( def resample_data( df: pd.DataFrame, - time_column : DataColumns, - time_unit_type: TimeUnit, + time_column : paradigma.DataColumns, + time_unit_type: paradigma.TimeUnit, unscaled_column_names: list, resampling_frequency: int, scale_factors: list = [], @@ -142,8 +141,8 @@ def resample_data( The data to resample. time_column : str The name of the time column. - time_unit_type : TimeUnit - The time unit type of the time array. The method currently works only for `TimeUnit.relative_ms`. + time_unit_type : paradigma.TimeUnit + The time unit type of the time array. The method currently works only for `paradigma.TimeUnit.relative_ms`. unscaled_column_names : list The names of the columns to resample. resampling_frequency : int @@ -159,7 +158,7 @@ def resample_data( The resampled data. """ # We need a start_time if the time is in absolute time format - if time_unit_type == TimeUnit.absolute_ms and start_time == 0.0: + if time_unit_type == paradigma.TimeUnit.absolute_ms and start_time == 0.0: raise ValueError("start_time is required for absolute time format") # get time and values diff --git a/src/paradigma/preprocessing_config.py b/src/paradigma/preprocessing_config.py index 86d2abf..a452455 100644 --- a/src/paradigma/preprocessing_config.py +++ b/src/paradigma/preprocessing_config.py @@ -1,4 +1,4 @@ -from paradigma.constants import DataColumns +import paradigma class BasePreprocessingConfig: @@ -12,7 +12,7 @@ def __init__(self) -> None: self.acceleration_units = 'm/s^2' self.rotation_units = 'deg/s' - self.time_colname = DataColumns.TIME + self.time_colname = paradigma.DataColumns.TIME # participant information self.side_watch = 'right' @@ -37,14 +37,14 @@ def __init__(self) -> None: self.rotation_units = 'deg/s' self.d_channels_accelerometer = { - DataColumns.ACCELEROMETER_X: self.acceleration_units, - DataColumns.ACCELEROMETER_Y: self.acceleration_units, - DataColumns.ACCELEROMETER_Z: self.acceleration_units, + paradigma.DataColumns.ACCELEROMETER_X: self.acceleration_units, + paradigma.DataColumns.ACCELEROMETER_Y: self.acceleration_units, + paradigma.DataColumns.ACCELEROMETER_Z: self.acceleration_units, } self.d_channels_gyroscope = { - DataColumns.GYROSCOPE_X: self.rotation_units, - DataColumns.GYROSCOPE_Y: self.rotation_units, - DataColumns.GYROSCOPE_Z: self.rotation_units, + paradigma.DataColumns.GYROSCOPE_X: self.rotation_units, + paradigma.DataColumns.GYROSCOPE_Y: self.rotation_units, + paradigma.DataColumns.GYROSCOPE_Z: self.rotation_units, } self.d_channels_imu = {**self.d_channels_accelerometer, **self.d_channels_gyroscope} @@ -58,7 +58,7 @@ def __init__(self) -> None: self.time_filename = 'PPG_time.bin' self.d_channels_ppg = { - DataColumns.PPG: 'none' + paradigma.DataColumns.PPG: 'none' } self.sampling_frequency = 30 From 63f0622bd3514c6d341b96c29dabab61f895fdcf Mon Sep 17 00:00:00 2001 From: Peter Kok Date: Tue, 20 Aug 2024 18:26:50 +0200 Subject: [PATCH 2/7] Minor docs fix --- src/paradigma/imu_preprocessing.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/paradigma/imu_preprocessing.py b/src/paradigma/imu_preprocessing.py index 0bb8c76..76e8da1 100644 --- a/src/paradigma/imu_preprocessing.py +++ b/src/paradigma/imu_preprocessing.py @@ -135,6 +135,7 @@ def resample_data( ) -> pd.DataFrame: """ Resamples the IMU data to the resampling frequency. The data is scaled before resampling. + Parameters ---------- df : pd.DataFrame From 9323f38df3995b976f25ccfe9c911e401f61e9fd Mon Sep 17 00:00:00 2001 From: Peter Kok Date: Tue, 20 Aug 2024 18:29:25 +0200 Subject: [PATCH 3/7] Bump version --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 06757ce..4fff1dc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "paradigma" -version = "0.1.0" +version = "0.2.0" description = "Paradigma - a toolbox for Digital Biomarkers for Parkinson's Disease" authors = [ "Peter Kok ", "Vedran Kasalica ", From dbccf024df8483c855fc46d9db04fbef9d768a93 Mon Sep 17 00:00:00 2001 From: Peter Kok Date: Wed, 21 Aug 2024 17:05:07 +0200 Subject: [PATCH 4/7] Revert "Expose functions at top-level and reorganize imports" This reverts commit f336d439bde53c2ed87a2d08f4ac372baef82b2c. --- docs/notebooks/gait/gait_analysis.ipynb | 5 ++- src/paradigma/__init__.py | 34 +---------------- src/paradigma/gait_analysis.py | 5 +-- src/paradigma/gait_analysis_config.py | 26 ++++++------- src/paradigma/heart_rate_analysis.py | 10 ++--- src/paradigma/imu_preprocessing.py | 51 +++++++++++++------------ src/paradigma/preprocessing_config.py | 18 ++++----- 7 files changed, 61 insertions(+), 88 deletions(-) diff --git a/docs/notebooks/gait/gait_analysis.ipynb b/docs/notebooks/gait/gait_analysis.ipynb index 7797c52..290c57c 100644 --- a/docs/notebooks/gait/gait_analysis.ipynb +++ b/docs/notebooks/gait/gait_analysis.ipynb @@ -18,7 +18,10 @@ "%autoreload 2\n", "\n", "import os\n", - "from paradigma import *" + "from paradigma.preprocessing_config import IMUPreprocessingConfig\n", + "from paradigma.gait_analysis import *\n", + "from paradigma.gait_analysis_config import *\n", + "from paradigma.imu_preprocessing import *" ] }, { diff --git a/src/paradigma/__init__.py b/src/paradigma/__init__.py index b75eddc..b068342 100644 --- a/src/paradigma/__init__.py +++ b/src/paradigma/__init__.py @@ -3,36 +3,6 @@ __version__ = version("paradigma") -from .constants import DataColumns, TimeUnit, UNIX_TICKS_MS +from .imu_preprocessing import * -from .preprocessing_config import IMUPreprocessingConfig, PPGPreprocessingConfig -from .imu_preprocessing import preprocess_imu_data, transform_time_array, resample_data, butterworth_filter - -from .gait_analysis_config import GaitFeatureExtractionConfig, GaitDetectionConfig, \ - ArmSwingFeatureExtractionConfig, ArmSwingDetectionConfig, ArmSwingQuantificationConfig -from .gait_analysis import extract_gait_features, detect_gait, extract_arm_swing_features, \ - detect_arm_swing, quantify_arm_swing, aggregate_weekly_arm_swing - - -__all__ = [ - "DataColumns", - "TimeUnit", - "UNIX_TICKS_MS", - "IMUPreprocessingConfig", - "PPGPreprocessingConfig", - "preprocess_imu_data", - "transform_time_array", - "resample_data", - "butterworth_filter", - "GaitFeatureExtractionConfig", - "GaitDetectionConfig", - "ArmSwingFeatureExtractionConfig", - "ArmSwingDetectionConfig", - "ArmSwingQuantificationConfig", - "extract_gait_features", - "detect_gait", - "extract_arm_swing_features", - "detect_arm_swing", - "quantify_arm_swing", - "aggregate_weekly_arm_swing", -] +__all__ = ["PreprocessingPipelineConfig"] diff --git a/src/paradigma/gait_analysis.py b/src/paradigma/gait_analysis.py index c24bf19..8c9e6ea 100644 --- a/src/paradigma/gait_analysis.py +++ b/src/paradigma/gait_analysis.py @@ -2,7 +2,6 @@ import tsdf -import paradigma from paradigma.gait_analysis_config import * from paradigma.feature_extraction import * from paradigma.quantification import * @@ -190,8 +189,8 @@ def extract_arm_swing_features(input_path: str, output_path: str, config: ArmSwi # direction of the swing of the arm df[config.velocity_colname] = pca_transform_gyroscope( df=df, - y_gyro_colname=paradigma.DataColumns.GYROSCOPE_Y, - z_gyro_colname=paradigma.DataColumns.GYROSCOPE_Z, + y_gyro_colname=DataColumns.GYROSCOPE_Y, + z_gyro_colname=DataColumns.GYROSCOPE_Z, pred_gait_colname=config.pred_gait_colname ) diff --git a/src/paradigma/gait_analysis_config.py b/src/paradigma/gait_analysis_config.py index afb3a5d..dffc84e 100644 --- a/src/paradigma/gait_analysis_config.py +++ b/src/paradigma/gait_analysis_config.py @@ -1,5 +1,5 @@ from typing import Dict, List -import paradigma +from paradigma import DataColumns class GaitFeatureExtractionConfig: @@ -30,9 +30,9 @@ def __init__(self) -> None: self.time_colname = 'time' self.l_accelerometer_cols: List[str] = [ - paradigma.DataColumns.ACCELEROMETER_X, - paradigma.DataColumns.ACCELEROMETER_Y, - paradigma.DataColumns.ACCELEROMETER_Z + DataColumns.ACCELEROMETER_X, + DataColumns.ACCELEROMETER_Y, + DataColumns.ACCELEROMETER_Z ] self.l_gravity_cols: List[str] = [f'grav_{x}' for x in self.l_accelerometer_cols] @@ -94,7 +94,7 @@ def __init__(self) -> None: self.time_filename = 'gait_time.bin' self.values_filename = 'gait_values.bin' - self.l_accel_cols = [paradigma.DataColumns.ACCELEROMETER_X, paradigma.DataColumns.ACCELEROMETER_Y, paradigma.DataColumns.ACCELEROMETER_Z] + self.l_accel_cols = [DataColumns.ACCELEROMETER_X, DataColumns.ACCELEROMETER_Y, DataColumns.ACCELEROMETER_Z] self.time_colname = 'time' @@ -139,15 +139,15 @@ def initialize_column_names(self, time_colname='time', pred_gait_colname='pred_g self.segment_nr_colname = segment_nr_colname self.l_accelerometer_cols: List[str] = [ - paradigma.DataColumns.ACCELEROMETER_X, - paradigma.DataColumns.ACCELEROMETER_Y, - paradigma.DataColumns.ACCELEROMETER_Z + DataColumns.ACCELEROMETER_X, + DataColumns.ACCELEROMETER_Y, + DataColumns.ACCELEROMETER_Z ] self.l_gyroscope_cols: List[str] = [ - paradigma.DataColumns.GYROSCOPE_X, - paradigma.DataColumns.GYROSCOPE_Y, - paradigma.DataColumns.GYROSCOPE_Z + DataColumns.GYROSCOPE_X, + DataColumns.GYROSCOPE_Y, + DataColumns.GYROSCOPE_Z ] self.l_gravity_cols: List[str] = [f'grav_{x}' for x in self.l_accelerometer_cols] @@ -224,8 +224,8 @@ def __init__(self) -> None: self.time_filename = 'arm_swing_time.bin' self.values_filename = 'arm_swing_values.bin' - self.l_accel_cols = [paradigma.DataColumns.ACCELEROMETER_X, paradigma.DataColumns.ACCELEROMETER_Y, paradigma.DataColumns.ACCELEROMETER_Z] - self.l_gyro_cols = [paradigma.DataColumns.GYROSCOPE_X, paradigma.DataColumns.GYROSCOPE_Y, paradigma.DataColumns.GYROSCOPE_Z] + self.l_accel_cols = [DataColumns.ACCELEROMETER_X, DataColumns.ACCELEROMETER_Y, DataColumns.ACCELEROMETER_Z] + self.l_gyro_cols = [DataColumns.GYROSCOPE_X, DataColumns.GYROSCOPE_Y, DataColumns.GYROSCOPE_Z] class ArmSwingQuantificationConfig: diff --git a/src/paradigma/heart_rate_analysis.py b/src/paradigma/heart_rate_analysis.py index 9a084f0..ba3ab3a 100644 --- a/src/paradigma/heart_rate_analysis.py +++ b/src/paradigma/heart_rate_analysis.py @@ -7,22 +7,22 @@ import tsdf import tsdf.constants -import paradigma from paradigma.heart_rate_analysis_config import HeartRateFeatureExtractionConfig from paradigma.heart_rate_util import extract_ppg_features, calculate_power_ratio, read_PPG_quality_classifier from paradigma.util import read_metadata, write_data, get_end_iso8601 +from paradigma.constants import DataColumns, UNIX_TICKS_MS def extract_signal_quality_features(input_path: str, classifier_path: str, output_path: str, config: HeartRateFeatureExtractionConfig) -> None: # load data metadata_time_ppg, metadata_samples_ppg = read_metadata(input_path, "PPG_meta.json", "PPG_time.bin", "PPG_samples.bin") df_ppg = tsdf.load_dataframe_from_binaries([metadata_time_ppg, metadata_samples_ppg], tsdf.constants.ConcatenationType.columns) - arr_ppg = df_ppg[paradigma.DataColumns.PPG].to_numpy() - relative_time_ppg = df_ppg[paradigma.DataColumns.TIME].to_numpy() + arr_ppg = df_ppg[DataColumns.PPG].to_numpy() + relative_time_ppg = df_ppg[DataColumns.TIME].to_numpy() metadata_time_acc, metadata_samples_acc = read_metadata(input_path, "accelerometer_meta.json", "accelerometer_time.bin", "accelerometer_samples.bin") df_acc = tsdf.load_dataframe_from_binaries([metadata_time_acc, metadata_samples_acc], tsdf.constants.ConcatenationType.columns) - arr_acc = df_acc[[paradigma.DataColumns.ACCELEROMETER_X, paradigma.DataColumns.ACCELEROMETER_Y, paradigma.DataColumns.ACCELEROMETER_Z]].to_numpy() + arr_acc = df_acc[[DataColumns.ACCELEROMETER_X, DataColumns.ACCELEROMETER_Y, DataColumns.ACCELEROMETER_Z]].to_numpy() sampling_frequency_ppg = config.sampling_frequency_ppg sampling_frequency_imu = config.sampling_frequency_imu @@ -96,7 +96,7 @@ def extract_signal_quality_features(input_path: str, classifier_path: str, outpu feature_acc.append(calculate_power_ratio(f1, PSD_imu, f2, PSD_ppg)) # Calculate the power ratio of the accelerometer signal in the PPG frequency range # time channel - t_unix_feat_total.append((relative_time_ppg[i] + ppg_start_time) * paradigma.UNIX_TICKS_MS) # Save in absolute unix time ms + t_unix_feat_total.append((relative_time_ppg[i] + ppg_start_time) * UNIX_TICKS_MS) # Save in absolute unix time ms acc_idx += samples_shift_acc # update IMU_idx # Convert lists to numpy arrays diff --git a/src/paradigma/imu_preprocessing.py b/src/paradigma/imu_preprocessing.py index 76e8da1..a1c2293 100644 --- a/src/paradigma/imu_preprocessing.py +++ b/src/paradigma/imu_preprocessing.py @@ -5,11 +5,12 @@ from scipy.interpolate import CubicSpline import tsdf -import paradigma +from paradigma.constants import DataColumns, TimeUnit from paradigma.util import write_data, read_metadata +from paradigma.preprocessing_config import IMUPreprocessingConfig -def preprocess_imu_data(input_path: str, output_path: str, config: paradigma.preprocessing_config.IMUPreprocessingConfig) -> None: +def preprocess_imu_data(input_path: str, output_path: str, config: IMUPreprocessingConfig) -> None: # Load data metadata_time, metadata_samples = read_metadata(input_path, config.meta_filename, config.time_filename, config.values_filename) @@ -23,20 +24,20 @@ def preprocess_imu_data(input_path: str, output_path: str, config: paradigma.pre df[config.time_colname] = transform_time_array( time_array=df[config.time_colname], scale_factor=1000, - input_unit_type = paradigma.TimeUnit.difference_ms, - output_unit_type = paradigma.TimeUnit.relative_ms) + input_unit_type = TimeUnit.difference_ms, + output_unit_type = TimeUnit.relative_ms) df = resample_data( df=df, time_column=config.time_colname, - time_unit_type=paradigma.TimeUnit.relative_ms, + time_unit_type=TimeUnit.relative_ms, unscaled_column_names = list(config.d_channels_imu.keys()), scale_factors=metadata_samples.scale_factors, resampling_frequency=config.sampling_frequency) if config.side_watch == 'left': - df[paradigma.DataColumns.ACCELEROMETER_X] *= -1 + df[DataColumns.ACCELEROMETER_X] *= -1 for col in config.d_channels_accelerometer.keys(): @@ -72,8 +73,8 @@ def preprocess_imu_data(input_path: str, output_path: str, config: paradigma.pre def transform_time_array( time_array: np.ndarray, scale_factor: float, - input_unit_type: paradigma.TimeUnit, - output_unit_type: paradigma.TimeUnit, + input_unit_type: TimeUnit, + output_unit_type: TimeUnit, start_time: float = 0.0, ) -> np.ndarray: """ @@ -85,10 +86,10 @@ def transform_time_array( The time array in milliseconds to transform. scale_factor : float The scale factor to apply to the time array. - input_unit_type : paradigma.TimeUnit - The time unit type of the input time array. Raw PPP data was in `paradigma.TimeUnit.difference_ms`. - output_unit_type : paradigma.TimeUnit - The time unit type of the output time array. The processing is often done in `paradigma.TimeUnit.relative_ms`. + input_unit_type : TimeUnit + The time unit type of the input time array. Raw PPP data was in `TimeUnit.difference_ms`. + output_unit_type : TimeUnit + The time unit type of the output time array. The processing is often done in `TimeUnit.relative_ms`. start_time : float, optional The start time of the time array in UNIX milliseconds (default is 0.0) @@ -97,28 +98,28 @@ def transform_time_array( time_array The transformed time array in milliseconds, with the specified time unit type. """ - # Scale time array and transform to relative time (`paradigma.TimeUnit.relative_ms`) - if input_unit_type == paradigma.TimeUnit.difference_ms: + # Scale time array and transform to relative time (`TimeUnit.relative_ms`) + if input_unit_type == TimeUnit.difference_ms: # Convert a series of differences into cumulative sum to reconstruct original time series. time_array = np.cumsum(np.double(time_array)) / scale_factor - elif input_unit_type == paradigma.TimeUnit.absolute_ms: + elif input_unit_type == TimeUnit.absolute_ms: # Set the start time if not provided. if np.isclose(start_time, 0.0, rtol=1e-09, atol=1e-09): start_time = time_array[0] # Convert absolute time stamps into a time series relative to start_time. time_array = (time_array - start_time) / scale_factor - elif input_unit_type == paradigma.TimeUnit.relative_ms: + elif input_unit_type == TimeUnit.relative_ms: # Scale the relative time series as per the scale_factor. time_array = time_array / scale_factor - # Transform the time array from `paradigma.TimeUnit.relative_ms` to the specified time unit type - if output_unit_type == paradigma.TimeUnit.absolute_ms: + # Transform the time array from `TimeUnit.relative_ms` to the specified time unit type + if output_unit_type == TimeUnit.absolute_ms: # Converts time array to absolute time by adding the start time to each element. time_array = time_array + start_time - elif output_unit_type == paradigma.TimeUnit.difference_ms: + elif output_unit_type == TimeUnit.difference_ms: # Creates a new array starting with 0, followed by the differences between consecutive elements. time_array = np.diff(np.insert(time_array, 0, start_time)) - elif output_unit_type == paradigma.TimeUnit.relative_ms: + elif output_unit_type == TimeUnit.relative_ms: # The array is already in relative format, do nothing. pass return time_array @@ -126,8 +127,8 @@ def transform_time_array( def resample_data( df: pd.DataFrame, - time_column : paradigma.DataColumns, - time_unit_type: paradigma.TimeUnit, + time_column : DataColumns, + time_unit_type: TimeUnit, unscaled_column_names: list, resampling_frequency: int, scale_factors: list = [], @@ -142,8 +143,8 @@ def resample_data( The data to resample. time_column : str The name of the time column. - time_unit_type : paradigma.TimeUnit - The time unit type of the time array. The method currently works only for `paradigma.TimeUnit.relative_ms`. + time_unit_type : TimeUnit + The time unit type of the time array. The method currently works only for `TimeUnit.relative_ms`. unscaled_column_names : list The names of the columns to resample. resampling_frequency : int @@ -159,7 +160,7 @@ def resample_data( The resampled data. """ # We need a start_time if the time is in absolute time format - if time_unit_type == paradigma.TimeUnit.absolute_ms and start_time == 0.0: + if time_unit_type == TimeUnit.absolute_ms and start_time == 0.0: raise ValueError("start_time is required for absolute time format") # get time and values diff --git a/src/paradigma/preprocessing_config.py b/src/paradigma/preprocessing_config.py index a452455..86d2abf 100644 --- a/src/paradigma/preprocessing_config.py +++ b/src/paradigma/preprocessing_config.py @@ -1,4 +1,4 @@ -import paradigma +from paradigma.constants import DataColumns class BasePreprocessingConfig: @@ -12,7 +12,7 @@ def __init__(self) -> None: self.acceleration_units = 'm/s^2' self.rotation_units = 'deg/s' - self.time_colname = paradigma.DataColumns.TIME + self.time_colname = DataColumns.TIME # participant information self.side_watch = 'right' @@ -37,14 +37,14 @@ def __init__(self) -> None: self.rotation_units = 'deg/s' self.d_channels_accelerometer = { - paradigma.DataColumns.ACCELEROMETER_X: self.acceleration_units, - paradigma.DataColumns.ACCELEROMETER_Y: self.acceleration_units, - paradigma.DataColumns.ACCELEROMETER_Z: self.acceleration_units, + DataColumns.ACCELEROMETER_X: self.acceleration_units, + DataColumns.ACCELEROMETER_Y: self.acceleration_units, + DataColumns.ACCELEROMETER_Z: self.acceleration_units, } self.d_channels_gyroscope = { - paradigma.DataColumns.GYROSCOPE_X: self.rotation_units, - paradigma.DataColumns.GYROSCOPE_Y: self.rotation_units, - paradigma.DataColumns.GYROSCOPE_Z: self.rotation_units, + DataColumns.GYROSCOPE_X: self.rotation_units, + DataColumns.GYROSCOPE_Y: self.rotation_units, + DataColumns.GYROSCOPE_Z: self.rotation_units, } self.d_channels_imu = {**self.d_channels_accelerometer, **self.d_channels_gyroscope} @@ -58,7 +58,7 @@ def __init__(self) -> None: self.time_filename = 'PPG_time.bin' self.d_channels_ppg = { - paradigma.DataColumns.PPG: 'none' + DataColumns.PPG: 'none' } self.sampling_frequency = 30 From 0c244cbeac9b69f5b6fa9c22e331c857fce8979e Mon Sep 17 00:00:00 2001 From: Peter Kok Date: Thu, 22 Aug 2024 16:11:54 +0200 Subject: [PATCH 5/7] Reorganize imports --- docs/notebooks/gait/gait_analysis.ipynb | 6 +- docs/notebooks/ppg/1-2-3_signal_quality.ipynb | 12 +-- src/paradigma/__init__.py | 4 +- src/paradigma/feature_extraction.py | 79 +++++++++++++++- src/paradigma/gait_analysis.py | 90 +++---------------- src/paradigma/gait_analysis_config.py | 3 +- src/paradigma/heart_rate_analysis.py | 1 - src/paradigma/ppg_preprocessing.py | 2 +- 8 files changed, 101 insertions(+), 96 deletions(-) diff --git a/docs/notebooks/gait/gait_analysis.ipynb b/docs/notebooks/gait/gait_analysis.ipynb index 290c57c..7cd4880 100644 --- a/docs/notebooks/gait/gait_analysis.ipynb +++ b/docs/notebooks/gait/gait_analysis.ipynb @@ -19,9 +19,9 @@ "\n", "import os\n", "from paradigma.preprocessing_config import IMUPreprocessingConfig\n", - "from paradigma.gait_analysis import *\n", - "from paradigma.gait_analysis_config import *\n", - "from paradigma.imu_preprocessing import *" + "from paradigma.gait_analysis import extract_gait_features, detect_gait, extract_arm_swing_features, detect_arm_swing, quantify_arm_swing\n", + "from paradigma.gait_analysis_config import GaitFeatureExtractionConfig, GaitDetectionConfig, ArmSwingFeatureExtractionConfig, ArmSwingDetectionConfig, ArmSwingQuantificationConfig\n", + "from paradigma.imu_preprocessing import preprocess_imu_data" ] }, { diff --git a/docs/notebooks/ppg/1-2-3_signal_quality.ipynb b/docs/notebooks/ppg/1-2-3_signal_quality.ipynb index 90b8151..4519dd8 100644 --- a/docs/notebooks/ppg/1-2-3_signal_quality.ipynb +++ b/docs/notebooks/ppg/1-2-3_signal_quality.ipynb @@ -43,8 +43,8 @@ "\n", "import tsdf\n", "import paradigma\n", - "from paradigma import DataColumns\n", - "from paradigma.ppg_preprocessing import tsdf_scan_meta, synchronization, extract_overlapping_segments\n", + "from paradigma.constants import DataColumns\n", + "from paradigma.ppg_preprocessing import extract_meta_from_tsdf_files, synchronization, extract_overlapping_segments\n", "from paradigma.util import parse_iso8601_to_datetime" ] }, @@ -116,8 +116,8 @@ "metadata": {}, "outputs": [], "source": [ - "meta_ppg = tsdf_scan_meta(input_path_ppg)\n", - "meta_imu = tsdf_scan_meta(input_path_imu)" + "meta_ppg = extract_meta_from_tsdf_files(input_path_ppg)\n", + "meta_imu = extract_meta_from_tsdf_files(input_path_imu)" ] }, { @@ -445,7 +445,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 12, "metadata": {}, "outputs": [], "source": [ @@ -482,7 +482,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "metadata": {}, "outputs": [], "source": [ diff --git a/src/paradigma/__init__.py b/src/paradigma/__init__.py index b068342..1404276 100644 --- a/src/paradigma/__init__.py +++ b/src/paradigma/__init__.py @@ -3,6 +3,4 @@ __version__ = version("paradigma") -from .imu_preprocessing import * - -__all__ = ["PreprocessingPipelineConfig"] +__all__ = [] diff --git a/src/paradigma/feature_extraction.py b/src/paradigma/feature_extraction.py index b1a9d06..9fc7a1c 100644 --- a/src/paradigma/feature_extraction.py +++ b/src/paradigma/feature_extraction.py @@ -3,7 +3,6 @@ from sklearn.decomposition import PCA from scipy import signal, fft - from scipy.integrate import cumulative_trapezoid from scipy.signal import find_peaks @@ -600,4 +599,80 @@ def extract_peak_angular_velocity( # compute the backward peak angular velocity, defined by the maximum positive angular velocity between the two peaks df.loc[index, 'backward_peak_ang_vel'].append(np.abs(max(row[velocity_colname][l_extrema_indices[j]:l_extrema_indices[j+1]]))) - return \ No newline at end of file + return + + +def extract_temporal_domain_features(config, df_windowed, l_gravity_stats=['mean', 'std']): + # compute the mean and standard deviation of the gravity component of the acceleration signal for each axis + for col in config.l_gravity_cols: + for stat in l_gravity_stats: + df_windowed[f'{col}_{stat}'] = generate_statistics( + sensor_col=df_windowed[col], + statistic=stat + ) + + # compute the standard deviation of the Euclidean norm of the three axes + df_windowed['std_norm_acc'] = generate_std_norm( + df=df_windowed, + cols=config.l_accelerometer_cols + ) + + return df_windowed + + +def extract_spectral_domain_features(config, df_windowed, sensor, l_sensor_colnames): + + for col in l_sensor_colnames: + + # transform the temporal signal to the spectral domain using the fast fourier transform + df_windowed[f'{col}_freqs'], df_windowed[f'{col}_fft'] = signal_to_ffts( + sensor_col=df_windowed[col], + window_type=config.window_type, + sampling_frequency=config.sampling_frequency + ) + + # compute the power in distinct frequency bandwidths + for bandwidth, frequencies in config.d_frequency_bandwidths.items(): + df_windowed[col+'_'+bandwidth] = df_windowed.apply(lambda x: compute_power_in_bandwidth( + sensor_col=x[col], + fmin=frequencies[0], + fmax=frequencies[1], + sampling_frequency=config.sampling_frequency, + window_type=config.window_type, + ), axis=1 + ) + + # compute the dominant frequency, i.e., the frequency with the highest power + df_windowed[col+'_dominant_frequency'] = df_windowed.apply(lambda x: get_dominant_frequency( + signal_ffts=x[col+'_fft'], + signal_freqs=x[col+'_freqs'], + fmin=config.spectrum_low_frequency, + fmax=config.spectrum_high_frequency + ), axis=1 + ) + + # compute the power summed over the individual axes to obtain the total power per frequency bandwidth + for bandwidth in config.d_frequency_bandwidths.keys(): + df_windowed['total_'+bandwidth] = df_windowed.apply(lambda x: sum(x[y+'_'+bandwidth] for y in l_sensor_colnames), axis=1) + + # compute the power summed over the individual frequency bandwidths to obtain the total power + df_windowed['total_power'] = compute_power( + df=df_windowed, + fft_cols=[f'{col}_fft' for col in l_sensor_colnames]) + + # compute the cepstral coefficients of the total power signal + cc_cols = generate_cepstral_coefficients( + total_power_col=df_windowed['total_power'], + window_length_s=config.window_length_s, + sampling_frequency=config.sampling_frequency, + low_frequency=config.spectrum_low_frequency, + high_frequency=config.spectrum_high_frequency, + n_filters=config.n_dct_filters_cc, + n_coefficients=config.n_coefficients_cc + ) + + df_windowed = pd.concat([df_windowed, cc_cols], axis=1) + + df_windowed = df_windowed.rename(columns={f'cc_{cc_nr}': f'cc_{cc_nr}_{sensor}' for cc_nr in range(1,config.n_coefficients_cc+1)}).rename(columns={'window_start': 'time'}) + + return df_windowed diff --git a/src/paradigma/gait_analysis.py b/src/paradigma/gait_analysis.py index 8c9e6ea..0bae20a 100644 --- a/src/paradigma/gait_analysis.py +++ b/src/paradigma/gait_analysis.py @@ -1,88 +1,20 @@ import os +import numpy as np +import pandas as pd import tsdf -from paradigma.gait_analysis_config import * -from paradigma.feature_extraction import * -from paradigma.quantification import * -from paradigma.windowing import * +from paradigma.constants import DataColumns +from paradigma.gait_analysis_config import GaitFeatureExtractionConfig, GaitDetectionConfig, \ + ArmSwingFeatureExtractionConfig, ArmSwingDetectionConfig, ArmSwingQuantificationConfig +from paradigma.feature_extraction import extract_temporal_domain_features, \ + extract_spectral_domain_features, pca_transform_gyroscope, compute_angle, \ + remove_moving_average_angle, extract_angle_extremes, extract_range_of_motion, \ + extract_peak_angular_velocity, signal_to_ffts, get_dominant_frequency, compute_perc_power +from paradigma.quantification import aggregate_segments +from paradigma.windowing import tabulate_windows, create_segments, discard_segments from paradigma.util import get_end_iso8601, write_data, read_metadata -def extract_temporal_domain_features(config, df_windowed, l_gravity_stats=['mean', 'std']): - # compute the mean and standard deviation of the gravity component of the acceleration signal for each axis - for col in config.l_gravity_cols: - for stat in l_gravity_stats: - df_windowed[f'{col}_{stat}'] = generate_statistics( - sensor_col=df_windowed[col], - statistic=stat - ) - - # compute the standard deviation of the Euclidean norm of the three axes - df_windowed['std_norm_acc'] = generate_std_norm( - df=df_windowed, - cols=config.l_accelerometer_cols - ) - - return df_windowed - - -def extract_spectral_domain_features(config, df_windowed, sensor, l_sensor_colnames): - - for col in l_sensor_colnames: - - # transform the temporal signal to the spectral domain using the fast fourier transform - df_windowed[f'{col}_freqs'], df_windowed[f'{col}_fft'] = signal_to_ffts( - sensor_col=df_windowed[col], - window_type=config.window_type, - sampling_frequency=config.sampling_frequency - ) - - # compute the power in distinct frequency bandwidths - for bandwidth, frequencies in config.d_frequency_bandwidths.items(): - df_windowed[col+'_'+bandwidth] = df_windowed.apply(lambda x: compute_power_in_bandwidth( - sensor_col=x[col], - fmin=frequencies[0], - fmax=frequencies[1], - sampling_frequency=config.sampling_frequency, - window_type=config.window_type, - ), axis=1 - ) - - # compute the dominant frequency, i.e., the frequency with the highest power - df_windowed[col+'_dominant_frequency'] = df_windowed.apply(lambda x: get_dominant_frequency( - signal_ffts=x[col+'_fft'], - signal_freqs=x[col+'_freqs'], - fmin=config.spectrum_low_frequency, - fmax=config.spectrum_high_frequency - ), axis=1 - ) - - # compute the power summed over the individual axes to obtain the total power per frequency bandwidth - for bandwidth in config.d_frequency_bandwidths.keys(): - df_windowed['total_'+bandwidth] = df_windowed.apply(lambda x: sum(x[y+'_'+bandwidth] for y in l_sensor_colnames), axis=1) - - # compute the power summed over the individual frequency bandwidths to obtain the total power - df_windowed['total_power'] = compute_power( - df=df_windowed, - fft_cols=[f'{col}_fft' for col in l_sensor_colnames]) - - # compute the cepstral coefficients of the total power signal - cc_cols = generate_cepstral_coefficients( - total_power_col=df_windowed['total_power'], - window_length_s=config.window_length_s, - sampling_frequency=config.sampling_frequency, - low_frequency=config.spectrum_low_frequency, - high_frequency=config.spectrum_high_frequency, - n_filters=config.n_dct_filters_cc, - n_coefficients=config.n_coefficients_cc - ) - - df_windowed = pd.concat([df_windowed, cc_cols], axis=1) - - df_windowed = df_windowed.rename(columns={f'cc_{cc_nr}': f'cc_{cc_nr}_{sensor}' for cc_nr in range(1,config.n_coefficients_cc+1)}).rename(columns={'window_start': 'time'}) - - return df_windowed - def extract_gait_features(input_path: str, output_path: str, config: GaitFeatureExtractionConfig) -> None: # load data diff --git a/src/paradigma/gait_analysis_config.py b/src/paradigma/gait_analysis_config.py index dffc84e..f9061e4 100644 --- a/src/paradigma/gait_analysis_config.py +++ b/src/paradigma/gait_analysis_config.py @@ -1,5 +1,6 @@ from typing import Dict, List -from paradigma import DataColumns + +from paradigma.constants import DataColumns class GaitFeatureExtractionConfig: diff --git a/src/paradigma/heart_rate_analysis.py b/src/paradigma/heart_rate_analysis.py index ba3ab3a..18b866f 100644 --- a/src/paradigma/heart_rate_analysis.py +++ b/src/paradigma/heart_rate_analysis.py @@ -1,7 +1,6 @@ from typing import List import numpy as np from scipy.signal import welch -from scipy.signal.windows import hann from sklearn.preprocessing import StandardScaler from dateutil import parser diff --git a/src/paradigma/ppg_preprocessing.py b/src/paradigma/ppg_preprocessing.py index 6ae2c9c..c9e8162 100644 --- a/src/paradigma/ppg_preprocessing.py +++ b/src/paradigma/ppg_preprocessing.py @@ -171,7 +171,7 @@ def extract_meta_from_tsdf_files(tsdf_data_dir : str) -> List[dict]: Examples -------- - >>> tsdf_scan_meta('/path/to/tsdf_data') + >>> extract_meta_from_tsdf_files('/path/to/tsdf_data') [{'start_iso8601': '2021-06-27T16:52:20Z', 'end_iso8601': '2021-06-27T17:52:20Z'}, ...] """ metas = [] From cb2adcb392a9af550f48724638ff8228dbbe8464 Mon Sep 17 00:00:00 2001 From: Peter Kok Date: Thu, 22 Aug 2024 16:12:12 +0200 Subject: [PATCH 6/7] Minor docs fixes --- docs/conf.py | 2 +- docs/index.md | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index e28a07f..94df5b2 100755 --- a/docs/conf.py +++ b/docs/conf.py @@ -28,7 +28,7 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] +exclude_patterns = ["build", "Thumbs.db", ".DS_Store"] # -- Options for HTML output ------------------------------------------------- diff --git a/docs/index.md b/docs/index.md index 260e544..babd3d1 100755 --- a/docs/index.md +++ b/docs/index.md @@ -1,13 +1,6 @@ ```{include} ../README.md ``` -```{toctree} -:maxdepth: 2 -:caption: TSDF schema -tsdf_paradigma_schemas.md -tsdf_paradigma_channels_and_units.md -``` - ```{toctree} :maxdepth: 2 :caption: Example notebooks @@ -21,6 +14,13 @@ notebooks/ppg/ppg_analysis.ipynb autoapi/index ``` +```{toctree} +:maxdepth: 2 +:caption: TSDF schema +tsdf_paradigma_schemas.md +tsdf_paradigma_channels_and_units.md +``` + ```{toctree} :maxdepth: 2 :caption: Development From 927d8275c9ffa46af3d5b83af249abaeef2a9b6f Mon Sep 17 00:00:00 2001 From: Peter Kok Date: Thu, 22 Aug 2024 17:05:35 +0200 Subject: [PATCH 7/7] Sphinx auto-api config to not include imported members --- docs/conf.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/conf.py b/docs/conf.py index 94df5b2..cbb23c0 100755 --- a/docs/conf.py +++ b/docs/conf.py @@ -23,8 +23,15 @@ "sphinx.ext.napoleon", "sphinx.ext.viewcode", ] + autoapi_dirs = ["../src"] +# Include the following entities in the API documentation, this explicitly excludes 'imported-members', +# as we don't want to clutter the documentation with all the imported members. +# https://sphinx-autoapi.readthedocs.io/en/latest/reference/config.html#confval-autoapi_options +autoapi_options = ['members', 'undoc-members', 'private-members', 'show-inheritance', + 'show-module-summary', 'special-members'] + # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path.