|
Resampling of signals recorded with Android sensors |
Tags | other☁android☁opensignals mobile☁resampling |
The OpenSignals mobile application allows to acquire data from the sensors that are built into the hardware of an Android smartphone.
However, when recording data from Android sensors it has to be taken into account that the Android system does not allow recording data with a fixed sampling rate. The Android system rather acquires data based on so called "sensor events". When the system picks up on one of these events it will take a sample from the sensor. These events, however, may not occur at fixed time intervals and thus result in a non-equidistant sampling.
If you prefer to have a more detailed look on how Android acquires data from their sensors you can have a look at the
Android Developers guide on sensors
. (See the section on
"Monitoring Sensor Events"
.)
In order to obtain an equidistant sampling with a fixed rate, the signal has to be resampled with an appropriate interpolation method. We will show how this can be achieved in this
Jupyter Notebook
.
Please take note:
The information given in this
notebook
does
only apply
when you acquired data from
one sensor only
. In case you have recorded data from multiple sensors and you want to re-sample the data, there are other important steps that need to be considered. For this, please read our notebook on
Synchronising data from multiple Android sensor files into one file
. However, we would still encourage you to read through the current notebook in order to understand what effects re-sampling will have on your signals.
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, lets import some useful libraries that will be used for data processing purposes.# package in order to load .txt files
from numpy import loadtxt, zeros, diff, mean, arange, ceil
# package for signal interpolation
from scipy.interpolate import interp1d
2 - A look at the data as it is returned by the OpenSignals mobile app
Before we begin with the resampling, we will have a look at the data structure that is returned from an Android sensor by the OpenSignals mobile application . For this Jupyter Notebook a look at the accelerometer sensor is taken. However, the procedure is the same for any Android sensor type.In the cell below, the data is shown in its .txt file format. The file has the usual OpenSignals format, containing a header and then displaying the recorded data. From the "column" field in the header we can see that the last three columns are the x, y, and z channels of the accelerometer.
The first column indicates at what time the Android system recorded the sensor event. The time shown in this column is in the time-format that the Android system returns whenever it records a sensor event. It is the time elapsed , in nanoseconds, since the phone was booted.
The first steps that must be followed should contemplate the load of our data from file, generation of a common time-axis and selection of the relevant channels and time-windows to be analysed:
2.1 - Load data from file
# set file path (this file path needs to be set accoridng to where you saved the data)
file_path="../../images/other/android_signal_resampling/opensignals_ANDROID_ACCELEROMETER_2020-07-15_11-33-21.txt"
# load the data from the file
data = loadtxt(file_path)
2.2 - Generate a common time-axis
The time axis will be shifted so that the recording begins at zero. Additionally an unit conversion (from nanoseconds to seconds) also takes place.# get timestamp column
raw_time = data[:,0]
# get the start of the acquisition
acq_start = raw_time[0]
# shift time_axis
time_axis = (raw_time - acq_start)
# convert from nanoseconds to seconds
time_axis = time_axis * 1e-9
2.3 - Selection of relevant channels and respective window to be analysed
For visualisation purposes we will only plot the the first 100 samples of the accelerometer"s z axis.# get z axis of accelerometer
z_acc = data[:,3]
# set the number of samples to be shown
num_samples = 100
# get the first 100 samples
time_axis_samples = time_axis[:num_samples]
z_acc_samples = z_acc[:num_samples]
Now lets have a look at the data in a plot!
Additionally, we will shift the time axis so that the recording begins at zero and we will convert it from nanoseconds to seconds
Looking at the plot that is generated, we can clearly see that the signal is not equidistantly sampled.
3 - Calculating the approximate sampling rate
Now we will take a look at how to calculate the approximate sampling rate of the sensor. In order to do this, we will calculate the mean distance between sampling points and then calculate how many samples with this mean distance fit into one second.As we we will see, the sensor samples on average with approximately 99.59 Hz .
# calculate the distance between sampling points
sample_dist = diff(time_axis)
# calculate the mean distance
mean_dist = mean(sample_dist)
# calculate the number of samples within 1 second
samples_per_second = 1/mean_dist
4 - Resampling the signal
Now that we have seen that the signal is not equidistantly sampled and know what is the approximate sampling rate, we can resample the signal to a reasonable sampling rate.
In order to resample the signal, we will use one of
scipy"s interpolation methods
. To explain the method very briefly, it creates a function which allows for interpolation of the data to a desired range. Additionally, the interpolation method allows for setting which kind of interpolation is used. In order to keep things simple, we will just use linear interpolation, but feel free to try around a little bit with other interpolation functions.
# get the end of the acquisition
acq_end = time_axis[-1]
# create interpolation function
inter_func = interp1d(time_axis, z_acc, kind='linear')
# set sampling frequency
sample_freq = 100
# create new time axis
time_axis_inter = arange(0, acq_end, 1/sample_freq)
# interpolate the values
z_acc_inter = inter_func(time_axis_inter)
Lets plot the signal again and see the result. As we will see, the signal is now equidistantly sampled.
However, we need to keep in mind, that the interpolation leads to a slight shift of our data points. The shift of the points differs depending on the kind of interpolation method used.
We can see these shifts when we compare both signals in the same plot, as seen below. The original signal is shown in
orange
while the interpolated signal is shown in
red
. As before, we are only showing the first 100 samples of each signal.
Try running the code with different interpolation methods and see how the interpolated signal changes with the kind of interpolation method used.
5 - Resampling all sensor channels at once using the biosignalsnotebooks package
Doing the interpolation manually for each column might seem a bit redundant. Thus, the biosignalsnotebooks package has a function that handles all the work for you. This function uses the same mechanisms as we have implemented above, but is also able to handle multiple data channels. In case you are interested in the implementation, you are welcome to visit our GitHub biosignalsnotebooks repository. This linkThe function is called re_sample_data(...) and it takes the following parameters:
# resample all three acceleromter channels at once (the accelerometer data are columns 1-3)
time_inter, data_inter, sampling_rate_inter = bsnb.re_sample_data(raw_time, data[:,1:], shift_time_axis=True)
In this Jupyter notebook we learned how to resample signals from sensors integrated into the hardware of an Android smartphone and how to use the biosignalsnotebooks package in order to re-sample all channels of an Android sensor.
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
.