paradigma 0.3.1__py3-none-any.whl → 0.4.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. paradigma/assets/gait_detection_clf_package.pkl +0 -0
  2. paradigma/assets/gait_filtering_clf_package.pkl +0 -0
  3. paradigma/assets/ppg_quality_clf_package.pkl +0 -0
  4. paradigma/assets/tremor_detection_clf_package.pkl +0 -0
  5. paradigma/classification.py +115 -0
  6. paradigma/config.py +314 -0
  7. paradigma/constants.py +48 -7
  8. paradigma/feature_extraction.py +811 -547
  9. paradigma/pipelines/__init__.py +0 -0
  10. paradigma/pipelines/gait_pipeline.py +727 -0
  11. paradigma/pipelines/heart_rate_pipeline.py +426 -0
  12. paradigma/pipelines/heart_rate_utils.py +780 -0
  13. paradigma/pipelines/tremor_pipeline.py +299 -0
  14. paradigma/preprocessing.py +363 -0
  15. paradigma/segmenting.py +396 -0
  16. paradigma/testing.py +416 -0
  17. paradigma/util.py +393 -16
  18. {paradigma-0.3.1.dist-info → paradigma-0.4.0.dist-info}/METADATA +58 -14
  19. paradigma-0.4.0.dist-info/RECORD +22 -0
  20. {paradigma-0.3.1.dist-info → paradigma-0.4.0.dist-info}/WHEEL +1 -1
  21. paradigma/gait_analysis.py +0 -415
  22. paradigma/gait_analysis_config.py +0 -266
  23. paradigma/heart_rate_analysis.py +0 -127
  24. paradigma/heart_rate_analysis_config.py +0 -9
  25. paradigma/heart_rate_util.py +0 -173
  26. paradigma/imu_preprocessing.py +0 -232
  27. paradigma/ppg/classifier/LR_PPG_quality.pkl +0 -0
  28. paradigma/ppg/classifier/LR_model.mat +0 -0
  29. paradigma/ppg/feat_extraction/acc_feature.m +0 -20
  30. paradigma/ppg/feat_extraction/peakdet.m +0 -64
  31. paradigma/ppg/feat_extraction/ppg_features.m +0 -53
  32. paradigma/ppg/glob_functions/extract_hr_segments.m +0 -37
  33. paradigma/ppg/glob_functions/extract_overlapping_segments.m +0 -23
  34. paradigma/ppg/glob_functions/jsonlab/AUTHORS.txt +0 -41
  35. paradigma/ppg/glob_functions/jsonlab/ChangeLog.txt +0 -74
  36. paradigma/ppg/glob_functions/jsonlab/LICENSE_BSD.txt +0 -25
  37. paradigma/ppg/glob_functions/jsonlab/LICENSE_GPLv3.txt +0 -699
  38. paradigma/ppg/glob_functions/jsonlab/README.txt +0 -394
  39. paradigma/ppg/glob_functions/jsonlab/examples/.svn/entries +0 -368
  40. paradigma/ppg/glob_functions/jsonlab/examples/.svn/text-base/demo_jsonlab_basic.m.svn-base +0 -180
  41. paradigma/ppg/glob_functions/jsonlab/examples/.svn/text-base/demo_ubjson_basic.m.svn-base +0 -180
  42. paradigma/ppg/glob_functions/jsonlab/examples/.svn/text-base/example1.json.svn-base +0 -23
  43. paradigma/ppg/glob_functions/jsonlab/examples/.svn/text-base/example2.json.svn-base +0 -22
  44. paradigma/ppg/glob_functions/jsonlab/examples/.svn/text-base/example3.json.svn-base +0 -11
  45. paradigma/ppg/glob_functions/jsonlab/examples/.svn/text-base/example4.json.svn-base +0 -34
  46. paradigma/ppg/glob_functions/jsonlab/examples/.svn/text-base/jsonlab_basictest.matlab.svn-base +0 -662
  47. paradigma/ppg/glob_functions/jsonlab/examples/.svn/text-base/jsonlab_selftest.m.svn-base +0 -27
  48. paradigma/ppg/glob_functions/jsonlab/examples/.svn/text-base/jsonlab_selftest.matlab.svn-base +0 -144
  49. paradigma/ppg/glob_functions/jsonlab/examples/.svn/text-base/jsonlab_speedtest.m.svn-base +0 -21
  50. paradigma/ppg/glob_functions/jsonlab/examples/demo_jsonlab_basic.m +0 -180
  51. paradigma/ppg/glob_functions/jsonlab/examples/demo_ubjson_basic.m +0 -180
  52. paradigma/ppg/glob_functions/jsonlab/examples/example1.json +0 -23
  53. paradigma/ppg/glob_functions/jsonlab/examples/example2.json +0 -22
  54. paradigma/ppg/glob_functions/jsonlab/examples/example3.json +0 -11
  55. paradigma/ppg/glob_functions/jsonlab/examples/example4.json +0 -34
  56. paradigma/ppg/glob_functions/jsonlab/examples/jsonlab_basictest.matlab +0 -662
  57. paradigma/ppg/glob_functions/jsonlab/examples/jsonlab_selftest.m +0 -27
  58. paradigma/ppg/glob_functions/jsonlab/examples/jsonlab_selftest.matlab +0 -144
  59. paradigma/ppg/glob_functions/jsonlab/examples/jsonlab_speedtest.m +0 -21
  60. paradigma/ppg/glob_functions/jsonlab/jsonopt.m +0 -32
  61. paradigma/ppg/glob_functions/jsonlab/loadjson.m +0 -566
  62. paradigma/ppg/glob_functions/jsonlab/loadubjson.m +0 -528
  63. paradigma/ppg/glob_functions/jsonlab/mergestruct.m +0 -33
  64. paradigma/ppg/glob_functions/jsonlab/savejson.m +0 -475
  65. paradigma/ppg/glob_functions/jsonlab/saveubjson.m +0 -504
  66. paradigma/ppg/glob_functions/jsonlab/varargin2struct.m +0 -40
  67. paradigma/ppg/glob_functions/sample_prob_final.m +0 -49
  68. paradigma/ppg/glob_functions/synchronization.m +0 -76
  69. paradigma/ppg/glob_functions/tsdf_scan_meta.m +0 -22
  70. paradigma/ppg/hr_functions/Long_TFD_JOT.m +0 -37
  71. paradigma/ppg/hr_functions/PPG_TFD_HR.m +0 -59
  72. paradigma/ppg/hr_functions/TFD toolbox JOT/.gitignore +0 -4
  73. paradigma/ppg/hr_functions/TFD toolbox JOT/CHANGELOG.md +0 -23
  74. paradigma/ppg/hr_functions/TFD toolbox JOT/LICENCE.md +0 -27
  75. paradigma/ppg/hr_functions/TFD toolbox JOT/README.md +0 -251
  76. paradigma/ppg/hr_functions/TFD toolbox JOT/README.pdf +0 -0
  77. paradigma/ppg/hr_functions/TFD toolbox JOT/common/gen_Doppler_kern.m +0 -142
  78. paradigma/ppg/hr_functions/TFD toolbox JOT/common/gen_Doppler_lag_kern.m +0 -314
  79. paradigma/ppg/hr_functions/TFD toolbox JOT/common/gen_lag_kern.m +0 -123
  80. paradigma/ppg/hr_functions/TFD toolbox JOT/dec_tfd.m +0 -154
  81. paradigma/ppg/hr_functions/TFD toolbox JOT/decimated_TFDs/dec_di_gdtfd.m +0 -194
  82. paradigma/ppg/hr_functions/TFD toolbox JOT/decimated_TFDs/dec_li_gdtfd.m +0 -200
  83. paradigma/ppg/hr_functions/TFD toolbox JOT/decimated_TFDs/dec_nonsep_gdtfd.m +0 -229
  84. paradigma/ppg/hr_functions/TFD toolbox JOT/decimated_TFDs/dec_sep_gdtfd.m +0 -241
  85. paradigma/ppg/hr_functions/TFD toolbox JOT/full_TFDs/di_gdtfd.m +0 -157
  86. paradigma/ppg/hr_functions/TFD toolbox JOT/full_TFDs/li_gdtfd.m +0 -190
  87. paradigma/ppg/hr_functions/TFD toolbox JOT/full_TFDs/nonsep_gdtfd.m +0 -196
  88. paradigma/ppg/hr_functions/TFD toolbox JOT/full_TFDs/sep_gdtfd.m +0 -199
  89. paradigma/ppg/hr_functions/TFD toolbox JOT/full_tfd.m +0 -144
  90. paradigma/ppg/hr_functions/TFD toolbox JOT/load_curdir.m +0 -13
  91. paradigma/ppg/hr_functions/TFD toolbox JOT/pics/decimated_TFDs_examples.png +0 -0
  92. paradigma/ppg/hr_functions/TFD toolbox JOT/pics/full_TFDs_examples.png +0 -0
  93. paradigma/ppg/hr_functions/TFD toolbox JOT/utils/check_dec_params_seq.m +0 -79
  94. paradigma/ppg/hr_functions/TFD toolbox JOT/utils/dispEE.m +0 -9
  95. paradigma/ppg/hr_functions/TFD toolbox JOT/utils/dispVars.m +0 -26
  96. paradigma/ppg/hr_functions/TFD toolbox JOT/utils/disp_bytes.m +0 -25
  97. paradigma/ppg/hr_functions/TFD toolbox JOT/utils/fold_vector_full.m +0 -40
  98. paradigma/ppg/hr_functions/TFD toolbox JOT/utils/fold_vector_half.m +0 -34
  99. paradigma/ppg/hr_functions/TFD toolbox JOT/utils/gen_LFM.m +0 -29
  100. paradigma/ppg/hr_functions/TFD toolbox JOT/utils/get_analytic_signal.m +0 -76
  101. paradigma/ppg/hr_functions/TFD toolbox JOT/utils/get_window.m +0 -176
  102. paradigma/ppg/hr_functions/TFD toolbox JOT/utils/isreal_fn.m +0 -11
  103. paradigma/ppg/hr_functions/TFD toolbox JOT/utils/padWin.m +0 -97
  104. paradigma/ppg/hr_functions/TFD toolbox JOT/utils/vtfd.m +0 -149
  105. paradigma/ppg/preprocessing/preprocessing_imu.m +0 -15
  106. paradigma/ppg/preprocessing/preprocessing_ppg.m +0 -13
  107. paradigma/ppg_preprocessing.py +0 -313
  108. paradigma/preprocessing_config.py +0 -69
  109. paradigma/quantification.py +0 -58
  110. paradigma/tremor/TremorFeaturesAndClassification.m +0 -345
  111. paradigma/tremor/feat_extraction/DerivativesExtract.m +0 -22
  112. paradigma/tremor/feat_extraction/ExtractBandSignalsRMS.m +0 -72
  113. paradigma/tremor/feat_extraction/MFCCExtract.m +0 -100
  114. paradigma/tremor/feat_extraction/PSDBandPower.m +0 -52
  115. paradigma/tremor/feat_extraction/PSDEst.m +0 -63
  116. paradigma/tremor/feat_extraction/PSDExtrAxis.m +0 -88
  117. paradigma/tremor/feat_extraction/PSDExtrOpt.m +0 -95
  118. paradigma/tremor/preprocessing/InterpData.m +0 -32
  119. paradigma/tremor/weekly_aggregates/WeeklyAggregates.m +0 -295
  120. paradigma/windowing.py +0 -219
  121. paradigma-0.3.1.dist-info/RECORD +0 -108
  122. {paradigma-0.3.1.dist-info → paradigma-0.4.0.dist-info}/LICENSE +0 -0
@@ -1,313 +0,0 @@
1
- import os
2
- import json
3
- import numpy as np
4
- import pandas as pd
5
- from pathlib import Path
6
- from typing import List, Union
7
- from datetime import datetime, timedelta
8
-
9
- import tsdf
10
- from paradigma.constants import DataUnits, TimeUnit, DataColumns
11
- from paradigma.preprocessing_config import PPGPreprocessingConfig, IMUPreprocessingConfig
12
- from paradigma.util import parse_iso8601_to_datetime, write_data
13
- import paradigma.imu_preprocessing
14
-
15
-
16
- def scan_and_sync_segments(input_path_ppg, input_path_imu):
17
-
18
- # Scan for available TSDF metadata files
19
- meta_ppg = extract_meta_from_tsdf_files(input_path_ppg)
20
- meta_imu = extract_meta_from_tsdf_files(input_path_imu)
21
-
22
- # Synchronize PPG and IMU data segments
23
- segments_ppg, segments_imu = synchronization(meta_ppg, meta_imu) # Define `synchronization`
24
-
25
- assert len(segments_ppg) == len(segments_imu), 'Number of PPG and IMU segments do not match.'
26
-
27
- # Load metadata for every synced segment pair
28
- metadatas_ppg = [tsdf.load_metadata_from_path(meta_ppg[index]['tsdf_meta_fullpath']) for index in segments_ppg]
29
- metadatas_imu = [tsdf.load_metadata_from_path(meta_imu[index]['tsdf_meta_fullpath']) for index in segments_imu]
30
-
31
- return metadatas_ppg, metadatas_imu
32
-
33
-
34
- def preprocess_ppg_data(tsdf_meta_ppg: tsdf.TSDFMetadata, tsdf_meta_imu: tsdf.TSDFMetadata, output_path: Union[str, Path], ppg_config: PPGPreprocessingConfig, imu_config: IMUPreprocessingConfig):
35
-
36
- # Load PPG data
37
- metadata_time_ppg = tsdf_meta_ppg[ppg_config.time_filename]
38
- metadata_samples_ppg = tsdf_meta_ppg[ppg_config.values_filename]
39
- df_ppg = tsdf.load_dataframe_from_binaries([metadata_time_ppg, metadata_samples_ppg], tsdf.constants.ConcatenationType.columns)
40
-
41
- # Load IMU data
42
- metadata_time_imu = tsdf_meta_imu[imu_config.time_filename]
43
- metadata_samples_imu = tsdf_meta_imu[imu_config.values_filename]
44
- df_imu = tsdf.load_dataframe_from_binaries([metadata_time_imu, metadata_samples_imu], tsdf.constants.ConcatenationType.columns)
45
-
46
- # Drop the gyroscope columns from the IMU data
47
- cols_to_drop = df_imu.filter(regex='^rotation_').columns
48
- df_imu.drop(cols_to_drop, axis=1, inplace=True)
49
- df_imu = df_imu.rename(columns={f'acceleration_{a}': f'accelerometer_{a}' for a in ['x', 'y', 'z']})
50
-
51
- # Transform the time arrays to absolute milliseconds
52
- start_time_ppg = parse_iso8601_to_datetime(metadata_time_ppg.start_iso8601).timestamp()
53
- df_imu[DataColumns.TIME] = paradigma.imu_preprocessing.transform_time_array(
54
- time_array=df_imu[DataColumns.TIME],
55
- scale_factor=1000,
56
- input_unit_type = TimeUnit.DIFFERENCE_MS,
57
- output_unit_type = TimeUnit.ABSOLUTE_MS,
58
- start_time = start_time_ppg)
59
-
60
- start_time_imu = parse_iso8601_to_datetime(metadata_time_imu.start_iso8601).timestamp()
61
- df_ppg[DataColumns.TIME] = paradigma.imu_preprocessing.transform_time_array(
62
- time_array=df_ppg[DataColumns.TIME],
63
- scale_factor=1000,
64
- input_unit_type = TimeUnit.DIFFERENCE_MS,
65
- output_unit_type = TimeUnit.ABSOLUTE_MS,
66
- start_time = start_time_imu)
67
-
68
- # Extract overlapping segments
69
- print("Shape of the original data:", df_ppg.shape, df_imu.shape)
70
- df_ppg_overlapping, df_imu_overlapping = extract_overlapping_segments(df_ppg, df_imu)
71
- print("Shape of the overlapping segments:", df_ppg_overlapping.shape, df_imu_overlapping.shape)
72
-
73
- # The following method is failing
74
- df_imu_proc = paradigma.imu_preprocessing.resample_data(
75
- df=df_imu_overlapping,
76
- time_column=DataColumns.TIME,
77
- time_unit_type=TimeUnit.ABSOLUTE_MS,
78
- unscaled_column_names = list(imu_config.d_channels_accelerometer.keys()),
79
- resampling_frequency=imu_config.sampling_frequency,
80
- scale_factors=metadata_samples_imu.scale_factors[0:3],
81
- start_time=start_time_imu)
82
-
83
- # metadata_samples_ppg.scale_factors - the data specifies 1, but it is not an obligatory tsdf field, maybe it should be optional parameter in `resample_data`
84
- df_ppg_proc = paradigma.imu_preprocessing.resample_data(
85
- df=df_ppg_overlapping,
86
- time_column=DataColumns.TIME,
87
- time_unit_type=TimeUnit.ABSOLUTE_MS,
88
- unscaled_column_names = list(ppg_config.d_channels_ppg.keys()),
89
- scale_factors=metadata_samples_imu.scale_factors,
90
- resampling_frequency=ppg_config.sampling_frequency,
91
- start_time = start_time_imu
92
- )
93
-
94
- # apply Butterworth filter to accelerometer data
95
- for col in imu_config.d_channels_accelerometer.keys():
96
-
97
- # change to correct units [g]
98
- if imu_config.acceleration_units == DataUnits.ACCELERATION:
99
- df_imu_proc[col] /= 9.81
100
-
101
- for result, side_pass in zip(['filt', 'grav'], ['hp', 'lp']):
102
- df_imu_proc[f'{result}_{col}'] = paradigma.imu_preprocessing.butterworth_filter(
103
- single_sensor_col=np.array(df_imu_proc[col]),
104
- order=imu_config.filter_order,
105
- cutoff_frequency=imu_config.lower_cutoff_frequency,
106
- passband=side_pass,
107
- sampling_frequency=imu_config.sampling_frequency,
108
- )
109
-
110
- df_imu_proc = df_imu_proc.drop(columns=[col])
111
- df_imu_proc = df_imu_proc.rename(columns={f'filt_{col}': col})
112
-
113
- for col in ppg_config.d_channels_ppg.keys():
114
- df_ppg_proc[f'filt_{col}'] = paradigma.imu_preprocessing.butterworth_filter(
115
- single_sensor_col=np.array(df_ppg_proc[col]),
116
- order=ppg_config.filter_order,
117
- cutoff_frequency=[ppg_config.lower_cutoff_frequency, ppg_config.upper_cutoff_frequency],
118
- passband='band',
119
- sampling_frequency=ppg_config.sampling_frequency,
120
- )
121
-
122
- df_ppg_proc = df_ppg_proc.drop(columns=[col])
123
- df_ppg_proc = df_ppg_proc.rename(columns={f'filt_{col}': col})
124
-
125
- df_imu_proc[DataColumns.TIME] = paradigma.imu_preprocessing.transform_time_array(
126
- time_array=df_imu_proc[DataColumns.TIME],
127
- scale_factor=1,
128
- input_unit_type=TimeUnit.ABSOLUTE_MS,
129
- output_unit_type=TimeUnit.RELATIVE_MS,
130
- start_time=start_time_ppg,
131
- )
132
-
133
- df_ppg_proc[DataColumns.TIME] = paradigma.imu_preprocessing.transform_time_array(
134
- time_array=df_ppg_proc[DataColumns.TIME],
135
- scale_factor=1,
136
- input_unit_type=TimeUnit.ABSOLUTE_MS,
137
- output_unit_type=TimeUnit.RELATIVE_MS,
138
- start_time=start_time_imu,
139
- )
140
-
141
- # Store data
142
- metadata_samples_imu.channels = list(imu_config.d_channels_accelerometer.keys())
143
- metadata_samples_imu.units = list(imu_config.d_channels_accelerometer.values())
144
- metadata_samples_imu.file_name = 'accelerometer_samples.bin'
145
- metadata_time_imu.units = [TimeUnit.ABSOLUTE_MS]
146
- metadata_time_imu.file_name = 'accelerometer_time.bin'
147
- write_data(metadata_time_imu, metadata_samples_imu, output_path, 'accelerometer_meta.json', df_imu_proc)
148
-
149
- metadata_samples_ppg.channels = list(ppg_config.d_channels_ppg.keys())
150
- metadata_samples_ppg.units = list(ppg_config.d_channels_ppg.values())
151
- metadata_samples_ppg.file_name = 'PPG_samples.bin'
152
- metadata_time_ppg.units = [TimeUnit.ABSOLUTE_MS]
153
- metadata_time_ppg.file_name = 'PPG_time.bin'
154
- write_data(metadata_time_ppg, metadata_samples_ppg, output_path, 'PPG_meta.json', df_ppg_proc)
155
-
156
-
157
- # TODO: ideally something like this should be possible directly in the tsdf library
158
- def extract_meta_from_tsdf_files(tsdf_data_dir : str) -> List[dict]:
159
- """
160
- For each given TSDF directory, transcribe TSDF metadata contents to a list of dictionaries.
161
-
162
- Parameters
163
- ----------
164
- tsdf_data_dir : str
165
- Path to the directory containing TSDF metadata files.
166
-
167
- Returns
168
- -------
169
- List[Dict]
170
- List of dictionaries with metadata from each JSON file in the directory.
171
-
172
- Examples
173
- --------
174
- >>> extract_meta_from_tsdf_files('/path/to/tsdf_data')
175
- [{'start_iso8601': '2021-06-27T16:52:20Z', 'end_iso8601': '2021-06-27T17:52:20Z'}, ...]
176
- """
177
- metas = []
178
-
179
- # Collect all metadata JSON files in the specified directory
180
- meta_list = list(Path(tsdf_data_dir).rglob('*_meta.json'))
181
- for meta_file in meta_list:
182
- with open(meta_file, 'r') as file:
183
- json_obj = json.load(file)
184
- meta_data = {
185
- 'tsdf_meta_fullpath': str(meta_file),
186
- 'subject_id': json_obj['subject_id'],
187
- 'start_iso8601': json_obj['start_iso8601'],
188
- 'end_iso8601': json_obj['end_iso8601']
189
- }
190
- metas.append(meta_data)
191
-
192
- return metas
193
-
194
-
195
- def synchronization(ppg_meta, imu_meta):
196
- """
197
- Synchronize PPG and IMU data segments based on their start and end times.
198
-
199
- Parameters
200
- ----------
201
- ppg_meta : list of dict
202
- List of dictionaries containing 'start_iso8601' and 'end_iso8601' keys for PPG data.
203
- imu_meta : list of dict
204
- List of dictionaries containing 'start_iso8601' and 'end_iso8601' keys for IMU data.
205
-
206
- Returns
207
- -------
208
- segment_ppg_total : list of int
209
- List of synchronized segment indices for PPG data.
210
- segment_imu_total : list of int
211
- List of synchronized segment indices for IMU data.
212
- """
213
- ppg_start_time = [parse_iso8601_to_datetime(t['start_iso8601']) for t in ppg_meta]
214
- imu_start_time = [parse_iso8601_to_datetime(t['start_iso8601']) for t in imu_meta]
215
- ppg_end_time = [parse_iso8601_to_datetime(t['end_iso8601']) for t in ppg_meta]
216
- imu_end_time = [parse_iso8601_to_datetime(t['end_iso8601']) for t in imu_meta]
217
-
218
- # Create a time vector covering the entire range
219
- time_vector_total = []
220
- current_time = min(min(ppg_start_time), min(imu_start_time))
221
- end_time = max(max(ppg_end_time), max(imu_end_time))
222
- while current_time <= end_time:
223
- time_vector_total.append(current_time)
224
- current_time += timedelta(seconds=1)
225
-
226
- time_vector_total = np.array(time_vector_total)
227
-
228
- # Initialize variables
229
- data_presence_ppg = np.zeros(len(time_vector_total), dtype=int)
230
- data_presence_ppg_idx = np.zeros(len(time_vector_total), dtype=int)
231
- data_presence_imu = np.zeros(len(time_vector_total), dtype=int)
232
- data_presence_imu_idx = np.zeros(len(time_vector_total), dtype=int)
233
-
234
- # Mark the segments of PPG data with 1
235
- for i, (start, end) in enumerate(zip(ppg_start_time, ppg_end_time)):
236
- indices = np.where((time_vector_total >= start) & (time_vector_total < end))[0]
237
- data_presence_ppg[indices] = 1
238
- data_presence_ppg_idx[indices] = i
239
-
240
- # Mark the segments of IMU data with 1
241
- for i, (start, end) in enumerate(zip(imu_start_time, imu_end_time)):
242
- indices = np.where((time_vector_total >= start) & (time_vector_total < end))[0]
243
- data_presence_imu[indices] = 1
244
- data_presence_imu_idx[indices] = i
245
-
246
- # Find the indices where both PPG and IMU data are present
247
- corr_indices = np.where((data_presence_ppg == 1) & (data_presence_imu == 1))[0]
248
-
249
- # Find the start and end indices of each segment
250
- corr_start_end = []
251
- if len(corr_indices) > 0:
252
- start_idx = corr_indices[0]
253
- for i in range(1, len(corr_indices)):
254
- if corr_indices[i] - corr_indices[i - 1] > 1:
255
- end_idx = corr_indices[i - 1]
256
- corr_start_end.append((start_idx, end_idx))
257
- start_idx = corr_indices[i]
258
- # Add the last segment
259
- corr_start_end.append((start_idx, corr_indices[-1]))
260
-
261
- # Extract the synchronized indices for each segment
262
- segment_ppg_total = []
263
- segment_imu_total = []
264
- for start_idx, end_idx in corr_start_end:
265
- segment_ppg = np.unique(data_presence_ppg_idx[start_idx:end_idx + 1])
266
- segment_imu = np.unique(data_presence_imu_idx[start_idx:end_idx + 1])
267
- if len(segment_ppg) > 1 and len(segment_imu) == 1:
268
- segment_ppg_total.extend(segment_ppg)
269
- segment_imu_total.extend([segment_imu[0]] * len(segment_ppg))
270
- elif len(segment_ppg) == 1 and len(segment_imu) > 1:
271
- segment_ppg_total.extend([segment_ppg[0]] * len(segment_imu))
272
- segment_imu_total.extend(segment_imu)
273
- elif len(segment_ppg) == len(segment_imu):
274
- segment_ppg_total.extend(segment_ppg)
275
- segment_imu_total.extend(segment_imu)
276
- else:
277
- continue
278
-
279
- return segment_ppg_total, segment_imu_total
280
-
281
- def extract_overlapping_segments(df_ppg, df_imu, time_column_ppg='time', time_column_imu='time'):
282
- """
283
- Extract DataFrames with overlapping data segments between IMU and PPG datasets based on their timestamps.
284
-
285
- Parameters:
286
- df_ppg (pd.DataFrame): DataFrame containing PPG data with a time column in UNIX milliseconds.
287
- df_imu (pd.DataFrame): DataFrame containing IMU data with a time column in UNIX milliseconds.
288
- time_column_ppg (str): Column name of the timestamp in the PPG DataFrame.
289
- time_column_imu (str): Column name of the timestamp in the IMU DataFrame.
290
-
291
- Returns:
292
- tuple: Tuple containing two DataFrames (df_ppg_overlapping, df_imu_overlapping) that contain only the data
293
- within the overlapping time segments.
294
- """
295
- # Convert UNIX milliseconds to seconds
296
- ppg_time = df_ppg[time_column_ppg] / 1000 # Convert milliseconds to seconds
297
- imu_time = df_imu[time_column_imu] / 1000 # Convert milliseconds to seconds
298
-
299
- # Determine the overlapping time interval
300
- start_time = max(ppg_time.iloc[0], imu_time.iloc[0])
301
- end_time = min(ppg_time.iloc[-1], imu_time.iloc[-1])
302
-
303
- # Extract indices for overlapping segments
304
- ppg_start_index = np.searchsorted(ppg_time, start_time, 'left')
305
- ppg_end_index = np.searchsorted(ppg_time, end_time, 'right') - 1
306
- imu_start_index = np.searchsorted(imu_time, start_time, 'left')
307
- imu_end_index = np.searchsorted(imu_time, end_time, 'right') - 1
308
-
309
- # Extract overlapping segments from DataFrames
310
- df_ppg_overlapping = df_ppg.iloc[ppg_start_index:ppg_end_index + 1]
311
- df_imu_overlapping = df_imu.iloc[imu_start_index:imu_end_index + 1]
312
-
313
- return df_ppg_overlapping, df_imu_overlapping
@@ -1,69 +0,0 @@
1
- from paradigma.constants import DataColumns, DataUnits
2
- from paradigma.gait_analysis_config import IMUConfig
3
-
4
- class BasePreprocessingConfig:
5
-
6
- def __init__(self) -> None:
7
-
8
- self.meta_filename = ''
9
- self.values_filename = ''
10
- self.time_filename = ''
11
-
12
- self.acceleration_units = DataUnits.ACCELERATION
13
- self.rotation_units = DataUnits.ROTATION
14
-
15
- self.time_colname = DataColumns.TIME
16
-
17
- # participant information
18
- self.side_watch = 'right'
19
-
20
- # filtering
21
- self.sampling_frequency = 100
22
- self.lower_cutoff_frequency = 0.2
23
- self.upper_cutoff_frequency = 3.5
24
- self.filter_order = 4
25
-
26
- def set_filenames(self, prefix: str) -> None:
27
- """Sets the filenames based on the prefix. This method is duplicated from `gaits_analysis_config.py`.
28
-
29
- Parameters
30
- ----------
31
- prefix : str
32
- The prefix for the filenames.
33
- """
34
- self.meta_filename = f"{prefix}_meta.json"
35
- self.time_filename = f"{prefix}_time.bin"
36
- self.values_filename = f"{prefix}_samples.bin"
37
-
38
- class IMUPreprocessingConfig(BasePreprocessingConfig):
39
-
40
- def __init__(self) -> None:
41
- super().__init__()
42
-
43
- self.set_filenames('IMU')
44
- self.acceleration_units = DataUnits.ACCELERATION
45
- self.rotation_units = DataUnits.ROTATION
46
-
47
- self.d_channels_accelerometer = {
48
- DataColumns.ACCELEROMETER_X: self.acceleration_units,
49
- DataColumns.ACCELEROMETER_Y: self.acceleration_units,
50
- DataColumns.ACCELEROMETER_Z: self.acceleration_units,
51
- }
52
- self.d_channels_gyroscope = {
53
- DataColumns.GYROSCOPE_X: self.rotation_units,
54
- DataColumns.GYROSCOPE_Y: self.rotation_units,
55
- DataColumns.GYROSCOPE_Z: self.rotation_units,
56
- }
57
- self.d_channels_imu = {**self.d_channels_accelerometer, **self.d_channels_gyroscope}
58
-
59
- class PPGPreprocessingConfig(BasePreprocessingConfig):
60
-
61
- def __init__(self) -> None:
62
- super().__init__()
63
-
64
- self.set_filenames('PPG')
65
- self.d_channels_ppg = {
66
- DataColumns.PPG: DataUnits.NONE
67
- }
68
-
69
- self.sampling_frequency = 30
@@ -1,58 +0,0 @@
1
- import pandas as pd
2
-
3
- def aggregate_segments(
4
- df: pd.DataFrame,
5
- time_colname: str,
6
- segment_nr_colname: str,
7
- window_step_size_s: float,
8
- l_metrics: list,
9
- l_aggregates: list,
10
- l_quantiles: list=[],
11
- )-> pd.DataFrame:
12
- """Extract arm swing aggregations from segments of a dataframe
13
-
14
- Parameters
15
- ----------
16
- df : pd.DataFrame
17
- Dataframe containing windowed arm swing features
18
- time_colname : str
19
- Name of the column containing the start time of the window
20
- segment_nr_colname : str
21
- Name of the column containing the segment number
22
- window_step_size_s : float
23
- Duration of each window in seconds
24
- l_metrics : list
25
- List of metrics to aggregate
26
- l_aggregates : list
27
- List of aggregation functions to apply to the metrics
28
- l_quantiles : list
29
- List of quantiles to calculate
30
-
31
- Returns
32
- -------
33
- pd.DataFrame
34
- Dataframe of segments containing aggregated arm swing features for each segment
35
- """
36
- l_df_agg = []
37
- for metric in l_metrics:
38
- df_agg = df.groupby(segment_nr_colname)[metric].agg(l_aggregates).reset_index().rename(columns={x: f'{metric}_{x}' for x in l_aggregates})
39
- df_qs = df.groupby(segment_nr_colname)[metric].quantile(l_quantiles).reset_index()
40
-
41
-
42
- for quantile in l_quantiles:
43
- df_agg[f"{metric}_quantile_{int(quantile*100)}"] = df_qs.loc[df_qs[f'level_1']==quantile, metric].reset_index(drop=True)
44
-
45
- l_df_agg.append(df_agg)
46
-
47
- for j in range(len(l_df_agg)):
48
- if j == 0:
49
- df_agg = l_df_agg[j]
50
- else:
51
- df_agg = pd.merge(left=df_agg, right=l_df_agg[j], how='left', on=segment_nr_colname)
52
-
53
- df_segments_stats = df.groupby(segment_nr_colname)[time_colname].agg(time='min', segment_duration_s='count')
54
- df_segments_stats['segment_duration_s'] *= window_step_size_s
55
-
56
- df_agg = pd.merge(left=df_agg, right=df_segments_stats, how='left', on=segment_nr_colname)
57
-
58
- return df_agg