diff --git a/.gitignore b/.gitignore index ea40922..f29f730 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ python-3.10 .DS_Store *.dmg python-3.11 +build diff --git a/python/env/requirements.txt b/python/env/requirements.txt index fcc9c37..add6095 100644 --- a/python/env/requirements.txt +++ b/python/env/requirements.txt @@ -1,8 +1,8 @@ pypiwin32==223; sys_platform == 'win32' -PySide6==6.6.0 -cython==3.0.5 -numpy==1.26.2 +PySide6==6.7.0 +cython==3.0.10 +numpy==1.26.4 scipy==1.11.4 -sqlalchemy==2.0.23 -alembic==1.12.1 +sqlalchemy==2.0.29 +alembic==1.13.1 pyinstaller==5.13.2 diff --git a/python/libopenimu/importers/AppleWatchImporter.py b/python/libopenimu/importers/AppleWatchImporter.py index b643f8c..d99fddb 100644 --- a/python/libopenimu/importers/AppleWatchImporter.py +++ b/python/libopenimu/importers/AppleWatchImporter.py @@ -5,6 +5,7 @@ @date 30/05/2018 """ +import logging from libopenimu.importers.BaseImporter import BaseImporter from libopenimu.models.sensor_types import SensorType @@ -54,6 +55,7 @@ class AppleWatchImporter(BaseImporter): HEADINGS_ID = 16 RAW_MAGNETO_ID = 17 TREMOR_ID = 18 + DYSKINETIC_ID = 19 def __init__(self, manager: DBManager, participant: Participant): super().__init__(manager, participant) @@ -549,7 +551,7 @@ def import_sensoria_to_database(self, settings, sample_rate, sensoria: dict): sensoria_acc_channels.append(self.add_channel_to_db(sensoria_acc_sensor, Units.GRAVITY_G, DataFormat.FLOAT32, 'Accelerometer_Z')) - sensoria_gyro_sensor = self.add_sensor_to_db(SensorType.GYROMETER, 'Gyrometer', 'Sensoria', 'Foot', + sensoria_gyro_sensor = self.add_sensor_to_db(SensorType.GYROMETER, 'Gyroscope', 'Sensoria', 'Foot', sample_rate, 1, settings) sensoria_gyro_channels = list() sensoria_gyro_channels.append(self.add_channel_to_db(sensoria_gyro_sensor, Units.DEG_PER_SEC, @@ -707,12 +709,12 @@ def import_beacons_to_database(self, settings, sample_rate, beacons: dict): count += 1 self.update_progress.emit(50 + np.floor(count / len(beacons) / 2 * 100)) - def import_motion_to_database(self, settings, sampling_rate, motion: dict): + def import_motion_to_database(self, settings, sampling_rate, motion: dict, version: int): # DL Oct. 16 2018, New import to database # Create channels and sensors accelerometer_sensor = self.add_sensor_to_db(SensorType.ACCELEROMETER, 'Accelerometer', - 'AppleWatch','Wrist', sampling_rate, 1, settings) + 'AppleWatch', 'Wrist', sampling_rate, 1, settings) accelerometer_channels = list() @@ -727,8 +729,8 @@ def import_motion_to_database(self, settings, sampling_rate, motion: dict): DataFormat.FLOAT32, 'Accelerometer_Z')) # Create sensor - gyro_sensor = self.add_sensor_to_db(SensorType.GYROMETER, 'Gyro','AppleWatch','Wrist', - sampling_rate, 1, settings) + gyro_sensor = self.add_sensor_to_db(SensorType.GYROMETER, 'Gyroscope', 'AppleWatch', + 'Wrist', sampling_rate, 1, settings) gyro_channels = list() @@ -751,6 +753,18 @@ def import_motion_to_database(self, settings, sampling_rate, motion: dict): orientation_channels.append(self.add_channel_to_db(orientation_sensor, Units.NONE, DataFormat.FLOAT32, 'q2')) orientation_channels.append(self.add_channel_to_db(orientation_sensor, Units.NONE, DataFormat.FLOAT32, 'q3')) + mag_channels = list() + magneto_sensor = None + if version >= 3: # Also includes magnetometer values + # Create sensor + magneto_sensor = self.add_sensor_to_db(SensorType.MAGNETOMETER, 'Magnetometer', 'AppleWatch', + 'Wrist', sampling_rate, 1, settings) + + # Create channels + mag_channels.append(self.add_channel_to_db(magneto_sensor, Units.UTESLA, DataFormat.FLOAT32, 'Mag_X')) + mag_channels.append(self.add_channel_to_db(magneto_sensor, Units.UTESLA, DataFormat.FLOAT32, 'Mag_Y')) + mag_channels.append(self.add_channel_to_db(magneto_sensor, Units.UTESLA, DataFormat.FLOAT32, 'Mag_Z')) + # Data is already hour-aligned iterate through hours count = 0 for timestamp in motion: @@ -794,10 +808,18 @@ def import_motion_to_database(self, settings, sampling_rate, motion: dict): self.add_sensor_data_to_db(recordset, gyro_sensor, gyro_channel, sensor_timestamps, valuesarray[:, i + 6]) + # Magneto + current_offset = 9 + if magneto_sensor: + for i, mag_channel in enumerate(mag_channels): + self.add_sensor_data_to_db(recordset, magneto_sensor, mag_channel, sensor_timestamps, + valuesarray[:, i + current_offset]) + current_offset = 12 + # Attitude for i, channel in enumerate(orientation_channels): self.add_sensor_data_to_db(recordset, orientation_sensor, channel, sensor_timestamps, - valuesarray[:, i + 9]) + valuesarray[:, i + current_offset]) count += 1 self.update_progress.emit(50 + np.floor(count / len(motion) / 2 * 100)) @@ -1050,6 +1072,56 @@ def import_tremor_to_database(self, settings, tremor: dict): count += 1 self.update_progress.emit(50 + np.floor(count / len(tremor) / 2 * 100)) + def import_dyskinetic_to_database(self, settings, dysk: dict): + # Create channels and sensors + dysk_sensor = self.add_sensor_to_db(SensorType.BIOMETRICS, 'Dyskinetic Mvt', 'AppleWatch', 'Wrist', 0, 1, + settings) + + dysk_channels = list() + dysk_channels.append(self.add_channel_to_db(dysk_sensor, Units.MILLISECONDS, DataFormat.UINT64, + 'Start Timestamp')) + + dysk_channels.append(self.add_channel_to_db(dysk_sensor, Units.MILLISECONDS, DataFormat.UINT64, + 'End Timestamp')) + + dysk_channels.append(self.add_channel_to_db(dysk_sensor, Units.PERCENTAGE, DataFormat.FLOAT32, 'Likeliness')) + + # Data is already hour-aligned iterate through hours + count = 0 + for timestamp in dysk: + # Filter invalid timestamp if needed + if timestamp.year < 2000: + continue + + # Calculate recordset + recordset = self.get_recordset(timestamp.timestamp(), session_name=self.session_name) + + # Add data to database + + # Create time array as float64 + timesarray = np.asarray(dysk[timestamp]['times'], dtype=np.float64) + + if len(timesarray) == 0: + self.last_error = "Aucune données temporelles." + return + + valuesarray = np.asarray(dysk[timestamp]['values'], dtype=np.float32) + + # Create sensor timestamps first + sensor_timestamps = self.create_sensor_timestamps(timesarray, recordset) + + for i, channel in enumerate(dysk_channels): + # Start and end timestamp are larger than float32 - a cast is required (channel 0 and 1) + if i <= 1: + current_timestamp = np.uint64(valuesarray[:, i*2:i*2+1]) + self.add_sensor_data_to_db(recordset, dysk_sensor, channel, sensor_timestamps, current_timestamp) + else: + self.add_sensor_data_to_db(recordset, dysk_sensor, channel, sensor_timestamps, + valuesarray[:, i + 3]) + + count += 1 + self.update_progress.emit(50 + np.floor(count / len(dysk) / 2 * 100)) + def import_question_to_database(self, settings, question: dict): # Create base sensor(s) questions_sensor = self.add_sensor_to_db(SensorType.QUESTIONS, 'Prompts', 'AppleWatch', @@ -1136,7 +1208,7 @@ def import_to_database(self, results): sampling_rate = res['motion']['sampling_rate'] if res['motion']['timestamps']: self.import_motion_to_database(res['motion']['settings'], sampling_rate, - res['motion']['timestamps']) + res['motion']['timestamps'], res['motion']['version']) if res.__contains__('battery'): sampling_rate = res['battery']['sampling_rate'] @@ -1286,7 +1358,7 @@ def read_data_file(self, file, debug=False): # if version == 1: Nothing more to do - if version == 2: + if version >= 2: [json_data_size] = struct.unpack(" - 1.1.0 + 1.1.1 diff --git a/python/resources/ui/StreamWindow.ui b/python/resources/ui/StreamWindow.ui index 5ebe434..b8fc295 100644 --- a/python/resources/ui/StreamWindow.ui +++ b/python/resources/ui/StreamWindow.ui @@ -535,6 +535,9 @@ true + + false + Progress diff --git a/setup/create_dmg.sh b/setup/create_dmg.sh index bff7947..7b1db48 100755 --- a/setup/create_dmg.sh +++ b/setup/create_dmg.sh @@ -9,7 +9,7 @@ rm -r ${SCRIPT_PATH}/../python/dist/dmg/* cp -R "${SCRIPT_PATH}/../python/dist/OpenIMU.app" "${SCRIPT_PATH}/../python/dist/dmg" # If the DMG already exists, delete it. test -f "${SCRIPT_PATH}/../python/dist/OpenIMU.dmg" && rm "${SCRIPT_PATH}/../python/dist/OpenIMU.dmg" -/usr/local/bin/create-dmg \ +create-dmg \ --volname "OpenIMU" \ --volicon "${SCRIPT_PATH}/../python/resources/icons/OpenIMU.icns" \ --window-pos 200 120 \ diff --git a/setup/setup_windows.iss b/setup/setup_windows.iss index 486d770..8112078 100644 --- a/setup/setup_windows.iss +++ b/setup/setup_windows.iss @@ -2,7 +2,7 @@ ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! #define MyAppName "OpenIMU" -#define MyAppVersion "1.1.0" +#define MyAppVersion "1.1.1" #define MyAppPublisher "INTER - CdRV - 3IT - USherbrooke" #define MyAppURL "https://github.com/introlab/OpenIMU" #define MyAppExeName "OpenIMU.exe"