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

Commit

Permalink
Additions to the tutorial.
Browse files Browse the repository at this point in the history
  • Loading branch information
Carlos Carreiras committed Sep 18, 2015
1 parent 2b1ef41 commit d98f409
Show file tree
Hide file tree
Showing 3 changed files with 287 additions and 10 deletions.
Binary file added docs/images/ECG_raw.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/ECG_summary.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
297 changes: 287 additions & 10 deletions docs/tutorial.rst
@@ -1,3 +1,4 @@
========
Tutorial
========

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

What are Biosignals?
--------------------
====================

Biosignals, in the most general sense, are measurements of physical properties
of biological systems. These include the measurement of properties at the
cellular level, such as concentrations of molecules, membrane potentials, and
DNA assays. On a higher level, for a group of specialized cells (i.e. an organ)
we are able to measure properties such as cell counts and histology, organ
secretions, and electrical activity (the electrical system of the heart, for
instance). Finally, for complex biological systems like the human being,
biosignals also include blood and urine test measurements, core body
temperature, motion tracking signals, and imaging techniques such as CAT and MRI
scans. However, the term biosignal is most often applied to bioelectrical,
time-varying signals. The following sub-sections briefly describe the biosignals
covered by `biosppy`.



The following biosignals form the focus of `biosppy`:

* Blood Volume Pulse (BVP);
* Electrocardiogram (ECG);
* Electrodermal Activity (EDA);
* Electroencephalogram (EEG);
* Electromyogram (EMG);
* Respiration (Resp).

Bla.

ECG
---

Bla.

EMG
---

Bla.

A very cool thing [ABCD88a]_.
Another cool thing [ABCD88b]_.

What is Pattern Recognition?
----------------------------
============================

Bla.

A Note on Return Types
----------------------
A Note on Return Objects
========================

Bla.
Before we dig into the core aspects of the package, you will quickly notice
that many of the methods and functions defined here return a custom object
class. This return class is defined in :py:class:`biosppy.utils.ReturnTuple`.
The goal of this return class is to strengthen the semantic relationship
between a function's output variables, their names, and what is described in
the documentation. Consider the following function definition:

.. code:: python
def compute(a, b):
"""Simultaneously compute the sum, subtraction, multiplication and
division between two integers.
Args:
a (int): First input integer.
b (int): Second input integer.
Returns:
(tuple): containing:
sum (int): Sum (a + b).
sub (int): Subtraction (a - b).
mult (int): Multiplication (a * b).
div (int): Integer division (a / b).
"""
if b == 0:
raise ValueError("Input 'b' cannot be zero.")
v1 = a + b
v2 = a - b
v3 = a * b
v4 = a / b
return v1, v2, v3, v4
Note that Python doesn't actually support returning multiple objects. In this
case, the ``return`` statement packs the objects into a tuple.

.. code:: python
>>> out = compute(4, 50)
>>> type(out)
<type 'tuple'>
>>> print out
(54, -46, 200, 0)
This is pretty straightforward, yet it shows one disadvantage of the native
Python return pattern: the semantics of the output elements (i.e. what each
variable actually represents) are only implicitly defined with the ordering
of the docstring. If there isn't a dosctring available (yikes!), the only way
to figure out the meaning of the output is by analyzing the code itself.

This is not necessarily a bad thing. One should always try to understand,
at least in broad terms, how any given function works. However, the initial
steps of the data analysis process encompass a lot of experimentation and
interactive exploration of the data. This is important in order to have an
initial sense of the quality of the data and what information we may be able to
extract. In this case, the user typically already knows what a function does,
but it is cumbersome to remember by heart the order of the outputs, without
having to constantly check out the documentation.

For instance, the `numpy.histogram
<http://docs.scipy.org/doc/numpy/reference/generated/numpy.histogram.html>`_
function returns first the edges or the values of the histogram? Maybe it's the
edges first, which correspond to the x axis. Oops, it's actually the other way
around...

In this case, it could be useful to have an explicit reference directly in the
return object to what each variable represents. Returning to the example above,
we would like to have something like:

.. code:: python
>>> out = compute(4, 50)
>>> print out
(sum=54, sub=-46, mult=200, div=0)
This is exactly what :py:class:`biosppy.utils.ReturnTuple` accomplishes.
Rewriting the `compute` function to work with `ReturnTuple` is simple. Just
construct the return object with a tuple of strings with names for each output
variable:

.. code:: python
from biosppy import utils
def compute_new(a, b):
"""Simultaneously compute the sum, subtraction, multiplication and
division between two integers.
Args:
a (int): First input integer.
b (int): Second input integer.
Returns:
(ReturnTuple): containing:
sum (int): Sum (a + b).
sub (int): Subtraction (a - b).
mult (int): Multiplication (a * b).
div (int): Integer division (a / b).
"""
if b == 0:
raise ValueError("Input 'b' cannot be zero.")
v1 = a + b
v2 = a - b
v3 = a * b
v4 = a / b
# build the return object
output = utils.ReturnTuple((v1, v2, v3, v4), ('sum', 'sub', 'mult', 'div'))
return output
The output now becomes:

.. code:: python
>>> out = compute_new(4, 50)
>>> print out
ReturnTuple(sum=54, sub=-46, mult=200, div=0)
It allows to access a specific variable by key, like a dictionary:

.. code:: python
>>> out['sum']
54
And to list all the available keys:

.. code:: python
>>> out.keys()
['sum', 'sub', 'mult', 'div']
It is also possible to convert the object to a more traditional dictionary,
specifically an `OrderedDict <https://docs.python.org/2/library/collections.html#collections.OrderedDict>`_:

.. code:: python
>>> d = out.as_dict()
>>> print d
OrderedDict([('sum', 54), ('sub', -46), ('mult', 200), ('div', 0)])
Dictionary-like unpacking is supported:

.. code:: python
>>> some_function(**out)
`ReturnTuple` is heavily inspired by `namedtuple <https://docs.python.org/2/library/collections.html#collections.namedtuple>`_,
but without the dynamic class generation at object creation. It is a subclass
of `tuple`, therefore it maintains compatibility with the native return pattern.
It is still possible to unpack the variables in the usual way:

.. code:: python
>>> a, b, c, d = compute_new(4, 50)
>>> print a, b, c, d
54 -46 200 0
The behavior is slightly different when only one variable is returned. In this
case it is necessary to explicitly unpack a one-element tuple:

.. code:: python
from biosppy import utils
def foo():
"""Returns 'bar'."""
out = 'bar'
return utils.ReturnTuple((out, ), ('out', ))
.. code:: python
>>> out, = foo()
>>> print out
'bar'
A First Approach
----------------
================

One of the major goals of `biosppy` is to provide an easy starting point into
the world of biosignal processing. For that reason, we provide simple turnkey
solutions for each of the supported biosignal types. These functions implement
typical methods to filter, transform, and extract signal features. Let's see
how this works for the example of the ECG signal.

The GitHub repository includes a few example signals (see
`here <https://github.com/PIA-Group/BioSPPy/tree/master/examples>`_). To load
and plot the raw ECG signal follow:

.. code:: python
>>> import numpy as np
>>> import pylab as pl
>>> from biosppy import storage
>>>
>>> signal, mdata = storage.load_txt('.../examples/ecg.txt')
>>> Fs = mdata['sampling_rate']
>>> N = len(signal) # number of samples
>>> T = (N - 1) / Fs # duration
>>> ts = np.linspace(0, T, N, endpoint=False) # relative timestamps
>>> pl.plot(ts, signal, lw=2)
>>> pl.grid()
>>> pl.show()
This should produce a similar output to the one shown below.

.. image:: images/ECG_raw.png
:align: center
:width: 80%
:alt: Example of a raw ECG signal.

This signal is a Lead I ECG signal acquired at 1000 Hz, with a resolution of 12
bit. Although of good quality, it exhibits powerline noise interference, has a
DC offset resulting from the acquisition device, and we can also observe the
influence of breathing in the variability of R-peak amplitudes.

We can minimize the effects of these artifacts and extract a bunch of features
with the :py:class:`biosppy.signals.ecg.ecg` function:

.. code:: python
>>> from biosppy.signals import ecg
>>> out = ecg.ecg(signal=signal, sampling_rate=Fs, show=True)
It should produce a plot like the one below.

.. image:: images/ECG_summary.png
:align: center
:width: 80%
:alt: Example of processed ECG signal.




Signal Processing
=================

Bla.

Clustering
----------
==========

Bla.

Biometrics
----------
==========

Bla.

What's Next?
------------
============

Bla.

References
----------
==========

.. [ABCD88a] Reference
Expand Down

0 comments on commit d98f409

Please sign in to comment.