import numpy as np
import pandas as pd
from .utils_complexity_symbolize import complexity_symbolize
[docs]
def fractal_petrosian(signal, symbolize="C", show=False):
"""**Petrosian fractal dimension (PFD)**
Petrosian (1995) proposed a fast method to estimate the fractal dimension by converting the
signal into a binary sequence from which the fractal dimension is estimated. Several variations
of the algorithm exist (e.g., ``"A"``, ``"B"``, ``"C"`` or ``"D"``), primarily differing in the
way the discrete (symbolic) sequence is created (see func:`complexity_symbolize` for details).
The most common method (``"C"``, by default) binarizes the signal by the sign of consecutive
differences.
.. math::
\\frac{log(N)}{log(N) + log(\\frac{N}{N+0.4N_{\\delta}})}
Most of these methods assume that the signal is periodic (without a linear trend). Linear
detrending might be useful to eliminate linear trends (see :func:`.signal_detrend`).
See Also
--------
information_mutual, entropy_svd
Parameters
----------
signal : Union[list, np.array, pd.Series]
The signal (i.e., a time series) in the form of a vector of values.
symbolize : str
Method to convert a continuous signal input into a symbolic (discrete) signal. By default,
assigns 0 and 1 to values below and above the mean. Can be ``None`` to skip the process (in
case the input is already discrete). See :func:`complexity_symbolize` for details.
show : bool
If ``True``, will show the discrete the signal.
Returns
-------
pfd : float
The petrosian fractal dimension (PFD).
info : dict
A dictionary containing additional information regarding the parameters used
to compute PFD.
Examples
----------
.. ipython:: python
import neurokit2 as nk
signal = nk.signal_simulate(duration=2, frequency=[5, 12])
@savefig p_fractal_petrosian1.png scale=100%
pfd, info = nk.fractal_petrosian(signal, symbolize = "C", show=True)
@suppress
plt.close()
.. ipython:: python
pfd
info
References
----------
* Esteller, R., Vachtsevanos, G., Echauz, J., & Litt, B. (2001). A comparison of waveform
fractal dimension algorithms. IEEE Transactions on Circuits and Systems I: Fundamental Theory
and Applications, 48(2), 177-183.
* Petrosian, A. (1995, June). Kolmogorov complexity of finite sequences and recognition of
different preictal EEG patterns. In Proceedings eighth IEEE symposium on computer-based
medical systems (pp. 212-217). IEEE.
* Kumar, D. K., Arjunan, S. P., & Aliahmad, B. (2017). Fractals: applications in biological
Signalling and image processing. CRC Press.
* Goh, C., Hamadicharef, B., Henderson, G., & Ifeachor, E. (2005, June). Comparison of fractal
dimension algorithms for the computation of EEG biomarkers for dementia. In 2nd International
Conference on Computational Intelligence in Medicine and Healthcare (CIMED2005).
"""
# Sanity checks
if isinstance(signal, (np.ndarray, pd.DataFrame)) and signal.ndim > 1:
raise ValueError(
"Multidimensional inputs (e.g., matrices or multichannel data) are not supported yet."
)
# Binarize the sequence
symbolic = complexity_symbolize(signal, method=symbolize, show=show)
# if isinstance(method, str) and method.lower() in ["d", "r"]:
# # These methods are already based on the consecutive differences
# n_inversions = symbolic.sum()
# else:
# # Note: np.diff(symbolic).sum() wouldn't work in case there's a seq like [0, -1, 1]
# n_inversions = (symbolic[1:] != symbolic[:-1]).sum()
n_inversions = (symbolic[1:] != symbolic[:-1]).sum()
n = len(symbolic)
pfd = np.log10(n) / (np.log10(n) + np.log10(n / (n + 0.4 * n_inversions)))
return pfd, {"Symbolization": symbolize}