Skip to content
This repository was archived by the owner on Aug 2, 2022. It is now read-only.

Commit d98f409

Browse files
author
Carlos Carreiras
committed
Additions to the tutorial.
1 parent 2b1ef41 commit d98f409

File tree

3 files changed

+287
-10
lines changed

3 files changed

+287
-10
lines changed

docs/images/ECG_raw.png

198 KB
Loading

docs/images/ECG_summary.png

379 KB
Loading

docs/tutorial.rst

Lines changed: 287 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
========
12
Tutorial
23
========
34

@@ -10,44 +11,320 @@ this tutorial we will discuss the major features of `biosppy` and introduce the
1011
terminology used by the package.
1112

1213
What are Biosignals?
13-
--------------------
14+
====================
15+
16+
Biosignals, in the most general sense, are measurements of physical properties
17+
of biological systems. These include the measurement of properties at the
18+
cellular level, such as concentrations of molecules, membrane potentials, and
19+
DNA assays. On a higher level, for a group of specialized cells (i.e. an organ)
20+
we are able to measure properties such as cell counts and histology, organ
21+
secretions, and electrical activity (the electrical system of the heart, for
22+
instance). Finally, for complex biological systems like the human being,
23+
biosignals also include blood and urine test measurements, core body
24+
temperature, motion tracking signals, and imaging techniques such as CAT and MRI
25+
scans. However, the term biosignal is most often applied to bioelectrical,
26+
time-varying signals. The following sub-sections briefly describe the biosignals
27+
covered by `biosppy`.
28+
29+
30+
31+
The following biosignals form the focus of `biosppy`:
32+
33+
* Blood Volume Pulse (BVP);
34+
* Electrocardiogram (ECG);
35+
* Electrodermal Activity (EDA);
36+
* Electroencephalogram (EEG);
37+
* Electromyogram (EMG);
38+
* Respiration (Resp).
39+
40+
Bla.
41+
42+
ECG
43+
---
44+
45+
Bla.
46+
47+
EMG
48+
---
49+
50+
Bla.
1451

1552
A very cool thing [ABCD88a]_.
1653
Another cool thing [ABCD88b]_.
1754

1855
What is Pattern Recognition?
19-
----------------------------
56+
============================
2057

2158
Bla.
2259

23-
A Note on Return Types
24-
----------------------
60+
A Note on Return Objects
61+
========================
2562

26-
Bla.
63+
Before we dig into the core aspects of the package, you will quickly notice
64+
that many of the methods and functions defined here return a custom object
65+
class. This return class is defined in :py:class:`biosppy.utils.ReturnTuple`.
66+
The goal of this return class is to strengthen the semantic relationship
67+
between a function's output variables, their names, and what is described in
68+
the documentation. Consider the following function definition:
69+
70+
.. code:: python
71+
72+
def compute(a, b):
73+
"""Simultaneously compute the sum, subtraction, multiplication and
74+
division between two integers.
75+
76+
Args:
77+
a (int): First input integer.
78+
b (int): Second input integer.
79+
80+
Returns:
81+
(tuple): containing:
82+
sum (int): Sum (a + b).
83+
sub (int): Subtraction (a - b).
84+
mult (int): Multiplication (a * b).
85+
div (int): Integer division (a / b).
86+
87+
"""
88+
89+
if b == 0:
90+
raise ValueError("Input 'b' cannot be zero.")
91+
92+
v1 = a + b
93+
v2 = a - b
94+
v3 = a * b
95+
v4 = a / b
96+
97+
return v1, v2, v3, v4
98+
99+
Note that Python doesn't actually support returning multiple objects. In this
100+
case, the ``return`` statement packs the objects into a tuple.
101+
102+
.. code:: python
103+
104+
>>> out = compute(4, 50)
105+
>>> type(out)
106+
<type 'tuple'>
107+
>>> print out
108+
(54, -46, 200, 0)
109+
110+
This is pretty straightforward, yet it shows one disadvantage of the native
111+
Python return pattern: the semantics of the output elements (i.e. what each
112+
variable actually represents) are only implicitly defined with the ordering
113+
of the docstring. If there isn't a dosctring available (yikes!), the only way
114+
to figure out the meaning of the output is by analyzing the code itself.
115+
116+
This is not necessarily a bad thing. One should always try to understand,
117+
at least in broad terms, how any given function works. However, the initial
118+
steps of the data analysis process encompass a lot of experimentation and
119+
interactive exploration of the data. This is important in order to have an
120+
initial sense of the quality of the data and what information we may be able to
121+
extract. In this case, the user typically already knows what a function does,
122+
but it is cumbersome to remember by heart the order of the outputs, without
123+
having to constantly check out the documentation.
124+
125+
For instance, the `numpy.histogram
126+
<http://docs.scipy.org/doc/numpy/reference/generated/numpy.histogram.html>`_
127+
function returns first the edges or the values of the histogram? Maybe it's the
128+
edges first, which correspond to the x axis. Oops, it's actually the other way
129+
around...
130+
131+
In this case, it could be useful to have an explicit reference directly in the
132+
return object to what each variable represents. Returning to the example above,
133+
we would like to have something like:
134+
135+
.. code:: python
136+
137+
>>> out = compute(4, 50)
138+
>>> print out
139+
(sum=54, sub=-46, mult=200, div=0)
140+
141+
This is exactly what :py:class:`biosppy.utils.ReturnTuple` accomplishes.
142+
Rewriting the `compute` function to work with `ReturnTuple` is simple. Just
143+
construct the return object with a tuple of strings with names for each output
144+
variable:
145+
146+
.. code:: python
147+
148+
from biosppy import utils
149+
150+
def compute_new(a, b):
151+
"""Simultaneously compute the sum, subtraction, multiplication and
152+
division between two integers.
153+
154+
Args:
155+
a (int): First input integer.
156+
b (int): Second input integer.
157+
158+
Returns:
159+
(ReturnTuple): containing:
160+
sum (int): Sum (a + b).
161+
sub (int): Subtraction (a - b).
162+
mult (int): Multiplication (a * b).
163+
div (int): Integer division (a / b).
164+
165+
"""
166+
167+
if b == 0:
168+
raise ValueError("Input 'b' cannot be zero.")
169+
170+
v1 = a + b
171+
v2 = a - b
172+
v3 = a * b
173+
v4 = a / b
174+
175+
# build the return object
176+
output = utils.ReturnTuple((v1, v2, v3, v4), ('sum', 'sub', 'mult', 'div'))
27177
178+
return output
179+
180+
The output now becomes:
181+
182+
.. code:: python
183+
184+
>>> out = compute_new(4, 50)
185+
>>> print out
186+
ReturnTuple(sum=54, sub=-46, mult=200, div=0)
187+
188+
It allows to access a specific variable by key, like a dictionary:
189+
190+
.. code:: python
191+
192+
>>> out['sum']
193+
54
194+
195+
And to list all the available keys:
196+
197+
.. code:: python
198+
199+
>>> out.keys()
200+
['sum', 'sub', 'mult', 'div']
201+
202+
It is also possible to convert the object to a more traditional dictionary,
203+
specifically an `OrderedDict <https://docs.python.org/2/library/collections.html#collections.OrderedDict>`_:
204+
205+
.. code:: python
206+
207+
>>> d = out.as_dict()
208+
>>> print d
209+
OrderedDict([('sum', 54), ('sub', -46), ('mult', 200), ('div', 0)])
210+
211+
Dictionary-like unpacking is supported:
212+
213+
.. code:: python
214+
215+
>>> some_function(**out)
216+
217+
`ReturnTuple` is heavily inspired by `namedtuple <https://docs.python.org/2/library/collections.html#collections.namedtuple>`_,
218+
but without the dynamic class generation at object creation. It is a subclass
219+
of `tuple`, therefore it maintains compatibility with the native return pattern.
220+
It is still possible to unpack the variables in the usual way:
221+
222+
.. code:: python
223+
224+
>>> a, b, c, d = compute_new(4, 50)
225+
>>> print a, b, c, d
226+
54 -46 200 0
227+
228+
The behavior is slightly different when only one variable is returned. In this
229+
case it is necessary to explicitly unpack a one-element tuple:
230+
231+
.. code:: python
232+
233+
from biosppy import utils
234+
235+
def foo():
236+
"""Returns 'bar'."""
237+
238+
out = 'bar'
239+
240+
return utils.ReturnTuple((out, ), ('out', ))
241+
242+
.. code:: python
243+
244+
>>> out, = foo()
245+
>>> print out
246+
'bar'
28247
29248
A First Approach
30-
----------------
249+
================
250+
251+
One of the major goals of `biosppy` is to provide an easy starting point into
252+
the world of biosignal processing. For that reason, we provide simple turnkey
253+
solutions for each of the supported biosignal types. These functions implement
254+
typical methods to filter, transform, and extract signal features. Let's see
255+
how this works for the example of the ECG signal.
256+
257+
The GitHub repository includes a few example signals (see
258+
`here <https://github.com/PIA-Group/BioSPPy/tree/master/examples>`_). To load
259+
and plot the raw ECG signal follow:
260+
261+
.. code:: python
262+
263+
>>> import numpy as np
264+
>>> import pylab as pl
265+
>>> from biosppy import storage
266+
>>>
267+
>>> signal, mdata = storage.load_txt('.../examples/ecg.txt')
268+
>>> Fs = mdata['sampling_rate']
269+
>>> N = len(signal) # number of samples
270+
>>> T = (N - 1) / Fs # duration
271+
>>> ts = np.linspace(0, T, N, endpoint=False) # relative timestamps
272+
>>> pl.plot(ts, signal, lw=2)
273+
>>> pl.grid()
274+
>>> pl.show()
275+
276+
This should produce a similar output to the one shown below.
277+
278+
.. image:: images/ECG_raw.png
279+
:align: center
280+
:width: 80%
281+
:alt: Example of a raw ECG signal.
282+
283+
This signal is a Lead I ECG signal acquired at 1000 Hz, with a resolution of 12
284+
bit. Although of good quality, it exhibits powerline noise interference, has a
285+
DC offset resulting from the acquisition device, and we can also observe the
286+
influence of breathing in the variability of R-peak amplitudes.
287+
288+
We can minimize the effects of these artifacts and extract a bunch of features
289+
with the :py:class:`biosppy.signals.ecg.ecg` function:
290+
291+
.. code:: python
292+
293+
>>> from biosppy.signals import ecg
294+
>>> out = ecg.ecg(signal=signal, sampling_rate=Fs, show=True)
295+
296+
It should produce a plot like the one below.
297+
298+
.. image:: images/ECG_summary.png
299+
:align: center
300+
:width: 80%
301+
:alt: Example of processed ECG signal.
302+
303+
304+
305+
306+
Signal Processing
307+
=================
31308

32309
Bla.
33310

34311
Clustering
35-
----------
312+
==========
36313

37314
Bla.
38315

39316
Biometrics
40-
----------
317+
==========
41318

42319
Bla.
43320

44321
What's Next?
45-
------------
322+
============
46323

47324
Bla.
48325

49326
References
50-
----------
327+
==========
51328

52329
.. [ABCD88a] Reference
53330

0 commit comments

Comments
 (0)