Source code for tvb.analyzers.info

# -*- coding: utf-8 -*-
#
#
# TheVirtualBrain-Scientific Package. This package holds all simulators, and
# analysers necessary to run brain-simulations. You can use it stand alone or
# in conjunction with TheVirtualBrain-Framework Package. See content of the
# documentation-folder for more details. See also http://www.thevirtualbrain.org
#
# (c) 2012-2023, Baycrest Centre for Geriatric Care ("Baycrest") and others
#
# This program is free software: you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software Foundation,
# either version 3 of the License, or (at your option) any later version.
# This program is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.  See the GNU General Public License for more details.
# You should have received a copy of the GNU General Public License along with this
# program.  If not, see <http://www.gnu.org/licenses/>.
#
#
#   CITATION:
# When using The Virtual Brain for scientific publications, please cite it as explained here:
# https://www.thevirtualbrain.org/tvb/zwei/neuroscience-publications
#
#

"""
This module implements information theoretic analyses. 

TODO: Fix docstring of sampen
TODO: Convert sampen to a traited class
TODO: Fix compatibility with  Python 3 and recent numpy

.. moduleauthor:: Marmaduke Woodman <marmaduke.woodman@univ-amu.fr>

"""
import numpy


[docs]def sampen(y, m=2, r=None, qse=False, taus=1, info=False, tile=numpy.tile, na=numpy.newaxis, abs=numpy.abs, log=numpy.log, r_=numpy.r_): """ Computes (quadratic) sample entropy of a given input signal y, with embedding dimension n, and a match tolerance of r (ref 2). If an array of scale factors, taus, are given, the signal will be coarsened by each factor and a corresponding entropy will be computed (ref 1). If no value for r is given, it will be set to 0.15*y.std(). Currently, the implementation is lazy and expects or coerces scale factors to integer values. With qse=True (default) the probability p is normalized for the value of r, giving the quadratic sample entropy, such that results from different values of r can be meaningfully compared (ref 2). ref 1: Costa, M., Goldberger, A. L., and Peng C.-K. (2002) Multiscale Entropy Analysis of Complex Physiologic Time Series. Phys Rev Lett 89 (6). ref 2: Lake, D. E. and Moorman, J. R. (2010) Accurate estimation of entropy in very short physiological time series. Am J Physiol Heart Circ Physiol To check that algorithm is working, look at ref 1, fig 1, and run >>> sampen(numpy.random.randn(3*10000), r=.15, taus=numpy.r_[1:20], qse=False, m=2) """ # if multiple scales given, run on each if type(taus) in (list, numpy.ndarray): return numpy.array([sampen(y, m=m, r=r, qse=qse, taus=int(tau)) for tau in taus]) # helper function to reformat arrays for matching subseq = lambda y, n: y[tile(r_[0:n], (y.size - n + 1, 1)) + r_[0:y.size - n + 1][:, na]] # default value of r if r is None: r = 0.15 * y.std() # if we have a scale factor, coarsen time series if taus > 1: y = y[:y.shape[0] // taus * taus].reshape((-1, taus)).mean(axis=1) # compute embedding of signal dims m, m+1, initialize match counts to 0 Y1 = subseq(y, m) Y2 = subseq(y, m + 1) c1 = 0 c2 = 0 # check for matches for i in range(Y1.shape[0] - 1): c1 += (abs(tile(Y1[i], (Y1.shape[0] - i - 1, 1)) - Y1[i + 1:]) < r).all(axis=1).sum() for i in range(Y2.shape[0] - 1): c2 += (abs(tile(Y2[i], (Y2.shape[0] - i - 1, 1)) - Y2[i + 1:]) < r).all(axis=1).sum() # ref 2, last paragraph of methods, warn inaccurate estimate if c2 < 5: print("m+1 template match count is low, %d < 5" % c2) p = c2 * 1.0 / c1 e = -log(p / (2 * r) if qse else p) if info: return e, p, c2, c1 else: return e