Generation of Poincaré Plot from ECG Analysis
Difficulty Level:
Tags pre-process☁ecg☁poincare

The Poincaré Plot defines a geometrical and non-linear approach for studying heart rate variability and in a more generic perspective is also a methodology to quantify the level of chaos in periodic processes.

This structure consists in a bidimensional plot, where each of its points has as coordinates the duration of two consecutive RR intervals ( $RR[i]$, $RR[i + 1]$ ), i.e. from tachogram each pair of samples i and i + 1 define a point in the Poincaré Plot.

There are two reference lines mathematically defined by the following equations:

\begin{equation} RR[i + 1] = RR[i] \end{equation} \begin{equation} RR[i + 1] = -RR[i] + 2 avg(RR) \end{equation}

If the dispersion of Poincaré points in relation to these lines is high, than it can be concluded that heart rate variability is high.


1 - Importing needed packages

In [1]:
# biosignalsnotebooks own package for loading and plotting the acquired data
import biosignalsnotebooks as bsnb

# Scientific packages
import numpy
import math

2 - Load of acquired ECG data

In [2]:
# Load of data (using a relative path of the project)
data, header = bsnb.load("/signal_samples/ecg_5_min.h5", get_header=True)

3 - Identification of mac address of the device and the channel used during acquisition

In [3]:
channel = list(data.keys())[0]
In [4]:
print ("Mac Address: " + str(header["device name"]) + " Channel: " + str(channel))
Mac Address: b'00:07:80:58:9B:3F' Channel: CH1

4 - Storage of sampling frequency and acquired data inside variables

In [5]:
# Sampling frequency and acquired data
fs = header["sampling rate"]

# Signal Samples
signal = data[channel]
time = numpy.linspace(0, len(signal) / fs, len(signal))

5 - Generation of tachogram

In [6]:
tachogram_data, tachogram_time = bsnb.tachogram(signal, fs, signal=True, out_seconds=True)

6 - Axes of Poincaré plot

In [7]:
rr_i = tachogram_data[:-1]
rr_i_plus_1 = tachogram_data[1:]

7 - Generation of Poincaré Plot

In [8]:
bsnb.dispersion(rr_i, rr_i_plus_1, 'RR\u1D62 (s)', 'RR\u1D62\u208A\u2081 (s)')
Out[8]:
[Figure(id='1001', ...)]

8 - Determination of SD1 and SD2 parameters

These parameters quantify the dispersion level of the Poincaré samples regarding to each reference line, being proportional to the short and long-term heart rate variability, respectively.

\begin{equation} SD1 = \sqrt{\frac{SDSD^2}{2}} \end{equation} \begin{equation} SD2 = \sqrt{2 \times SDNN^2 - SD1^2} \end{equation}
where:
\begin{equation} SDSD = \sqrt{\frac{\sum_{i=2}^N ((RR[i] - RR[i - 1]) - \overline{RR_i - RR_{i - 1}})^2}{N - 1}} \end{equation} \begin{equation} SDNN = \sqrt{\frac{\sum_{i=1}^N (RR[i] - \overline{RR})^2}{N - 1}} \end{equation}
and:
$\overline{RR_i - RR_{i - 1}}$ is the average value of the first derivative of tachogram, while $\overline{RR}$ is the average value of the tachogram samples
In [9]:
tachogram_diff = numpy.diff(tachogram_data)
SDSD = numpy.std(tachogram_diff)
SDNN = numpy.std(tachogram_data)
        
SD1 = numpy.sqrt(0.5 * numpy.power(SDSD, 2))
SD2 = numpy.sqrt(2 * numpy.power(SDNN, 2) - numpy.power(SD1, 2))

avg_rr = numpy.average(tachogram_data)

9 - Representation of Poincaré Plot with associated parameters

In [10]:
list_figures = bsnb.plot_poincare(tachogram_data)

This procedure can be automatically done by poincare function in process module of biosignalsnotebooks package

In [11]:
x_axis, y_axis, SD1, SD2 = bsnb.poincare(signal, fs, signal=True, in_seconds=False)

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 !

In [12]:
bsnb.css_style_apply()
.................... CSS Style Applied to Jupyter Notebook .........................
Out[12]: