|
Synchronising Android and PLUX sensors |
Tags | other☁android☁opensignals mobile☁bitalino |
The OpenSignals mobile application allows to acquire data from internal Android phone sensors and PLUX sensors at the same time. In order to put these into a proper context, the signals acquired from all these sensors need to be synchronised.
In this Jupyter notebook we will show you the essential steps in order to achieve this. First, we will be doing some minor data manipulation. This is then followed by having a look at the data we want to synchronise. Finally, all signals will be synchronised and written into one file.
The Android data used in this notebook was recorded using a
Samsung Galaxy A40
with a set sampling rate of
100 Hz
. We recorded data from the
accelerometer
,
GPS
,
linear accelerometer
, and
rotation vector
sensors. Prior to starting this notebook, we already did a synchronisation of the Android sensors. All sensors were resampled to
100 Hz
using a padding of type "same" and an interpolation using the "previous" type. If you want to find out how this can be done, please have a look at our
Synchronising data from multiple Android sensor files into one file
notebook.
The other data was acquired using a new, fresh out of the box, BITalino with a sampling rate of 100 Hz . We recorded data from the accelerometer sensor. Since the BITalino was not altered before acquiring data, only the z-axis of the accelerometer was available. In case you choose to make an acquisition with your PLUX device with a sampling rate of 1000 Hz, you should resample your Android signals to the same sampling rate.
To synchronise both device we took the same approach presented in the
notebook
on synchronisation of two PLUX devices using the accelerometers. At the beginning of our recording we produced a clearly distinctive event on both accelerometers by moving the devices along their z-axes. The z-axis of the Android phone is perpendicular to the screen.
In case this is your first time working with Android sensors, we highly recommend reading the
Introduction to Android sensors
notebook with general information on Android sensors.
1 - Package imports
First, let"s import biosignalsnotebooks package and some other packages. All functionalities that we need are within these packages.# biosignalsnotebooks package
import biosignalsnotebooks as bsnb
# numpy packaged
from numpy import loadtxt
# package for using operating system dependent functionality
import os
# needed in order to extract information from the header in a convenient way
import json
2 - Unit conversion of the BITalino signals
If you want to have a file in which all values are physical quantities, then it makes sense to convert the RAW values acquired with the BITalino . We are also going to change the axis indicating the number of samples to a real time axis. This is done, so that in the final synchronised file, both the BITalino and the Android sensors use time axis. However, this step can also be skipped if you are not in need of that. We will convert the values and subsequently save them to a new file. For value conversion we can make use of the raw_to_phy(...)The function takes the following inputs:
But first, we need to load the raw signal file, open it, and extract all needed information from the header.
2.1 - Get metadata through the read of file header
# set file path
path = '../../images/other/android_bitalino_sync/opensignals_98D351FD8E78_2020-07-29_19-51-58.txt'
# get the header of the file
with open(path, encoding='latin-1') as opened_file:
# read the information from the header lines (omitting the begin and end tags of the header)
header = opened_file.readlines()[1][2:] # omit "# " at the beginning of the sensor information
# convert the header to a dictionary (for easier access of the information that we need)
header = json.loads(header)
2.2 - Access/store relevant metadata about the sensor, device and acquisition
# get the key first key of the dictionary (all information can be accessed using that key)
dict_key = list(header.keys())[0]
# get the values for unit conversion
device = header[dict_key]['device']
resolution = header[dict_key]['resolution'][0]
# get the sampling rate of the device
sampling_rate = header[dict_key]['sampling rate']
# set the sensor name and the option
sensor_name = 'ACC'
option = 'm/s^2'
2.3 - Load BITalino data from file
# get the data from the file (as an numpy array)
data = loadtxt(path)
2.4 - Generate a time-axis and convert RAW values to acceleration physical units
# convert the sampling axis to a time axis
data[:, 0] = bsnb.generate_time(data[:, -1], sampling_rate)
# convert the data of the ACC channel (in our case the ACC data is the last column in the file. This can be accessed using -1)
# in order to make things simple we are directly overwriting that channel in the data array
data[:, -1] = bsnb.raw_to_phy(sensor_name, device, data[:, -1], resolution, option)
2.5 - Creation of a new file with the converted time and signal values
# set file name for the file in which the converted data is going to be saved
file_name = 'bitalino_converted.txt'
# get the current directory
curr_path = os.path.abspath(os.getcwd())
# crete full file path
save_path = os.path.join(curr_path, file_name)
# convert header to string
header_string = "# OpenSignals Text File Format\n# " + json.dumps(header) + '\n# EndOfHeader\n'
# open a new file at the path location
sync_file = open(save_path, 'w')
# write the header to the file
sync_file.write(header_string)
# write the data to the file. The values in each line are written tab separated
for row in data:
sync_file.write('\t'.join(str(value) for value in row) + '\t\n')
# close the file
sync_file.close()
3 - Taking a look at the channels used for synchronisation
Before we start synchronising both files, we will take a look at both accelerometer channels that we are going to use for synchronisation. The z-axis of the accelerometer are the fifth ("CH5") and the second channel ("CH2") for the BITalino and the Android sensor files, respectively.As we can see in the plot below, both channels are only slightly shifted in relation to each other. This shift may however change from recording to recording, because of the Android system"s sampling procedure. In case you are wondering: The Android accelerometer sensor measures the acceleration including the force of gravity, thus the data is shifted along the y-axis of the plot.
# set file path
path = '../../images/other/android_bitalino_sync/'
# set full file paths
# for the BITalino we reuse the path where we saved the file
bitalino_file = save_path
android_file = path + 'android_sensor_sync.txt'
# load the data
bitalino_data = bsnb.load(bitalino_file, get_header=False)
android_data = bsnb.load(android_file, get_header=False)
# plot data
bitalino_time = loadtxt(bitalino_file)[:, 0]
android_time = loadtxt(android_file)[:, 0]
# plot the data of both files
bsnb.plot([bitalino_time, android_time], [bitalino_data['CH5'], android_data['CH2']], legend_label=["bitalino CH5", "android CH2"], y_axis_label=["Accelerometer", "Accelerometer"], x_axis_label="Time (s)")
4 - Create the synchronised file
Now, that we have everything set up, we can perform the synchronisation of the two files. This can be achieved by calling the generate_sync_txt_file(...)The function takes the following inputs:
# put list in file
input_paths = [bitalino_file, android_file]
# set path, including new file name
new_path = os.path.join(curr_path, 'android_bitalino_sync.txt')
# synchronize
bsnb.generate_sync_txt_file(input_paths, channels=('CH5', 'CH2'), new_path=new_path)
In this Jupyter notebook we learned how to synchronise data acquired from PLUX and Android sensor at he same time using the biosignalsnotebooks package.
We hope that you have enjoyed this guide
.
biosignalsnotebooks
is an environment in continuous expansion, so don"t stop your journey and learn more with the remaining
Notebooks
.