# -*- coding: utf-8 -*-
""" Phase-Amplitude Coupling
Phase-Amplitude Coupling (*PAC*) is the most famous and prominent approach for
studuying the Cross Frequency Coupling between slow and faster oscillations. The
phase of a low frequency drive the power of a higher frequency.
"""
# Author: Avraam Marimpis <avraam.marimpis@gmail.com>
from .estimator import Estimator
from ..analytic_signal import analytic_signal
import numpy as np
[docs]def pac(data, f_lo, f_hi, fs, estimator, pairs=None):
""" Phase-Amplitude Coupling
Compute the Phase Amplitude Couplgin using the given estimator for the given *data*,
between the specified *pairs* of channels.
Parameters
----------
data : array-like, shape = [n_electrodes, n_samples]
Multichannel recording data.
pairs : array-like
Each element is a tuple of length two.
f_lo : list of length 2
The low and high frequencies.
f_hi : list of length 2
The low and high frequencies.
fs : float
Sampling frequency.
estimator: iplv | plv | pli | corr
Estimator used
Valid options:
'iplv' : Imaginary Phase Locking Value
'plv' : Phase Locking Value
'pli' : Phase Lag Index
Returns
-------
ts : complex array-like, shape = [n_electrodes, n_electrodes, n_samples]
The PAC computed each time series.
avg : complex array-like, shape = [n_electrodes, n_electrodes]
The average PAC across all samples.
"""
pac = PAC(f_lo, f_hi, fs, estimator, pairs)
phases, phases_lohi = pac.preprocess(data)
return pac.estimate(phases, phases_lohi)
[docs]class PAC(Estimator):
""" Phase Amplitude Coupling (PAC)
"""
def __init__(self, f_lo, f_hi, fs, estimator, pairs=None):
self.f_lo = f_lo
self.f_hi = f_hi
self.fs = fs
self.estimator = estimator
self.pairs = pairs
[docs] def preprocess(self, data):
hilberted_lo, _, _ = analytic_signal(data, self.f_lo, self.fs)
phase = np.angle(hilberted_lo)
hilberted_hi, _, _ = analytic_signal(data, self.f_hi, self.fs)
amp = np.abs(hilberted_hi)
hilberted_lohi, _, _ = analytic_signal(amp, self.f_lo, self.fs)
phase_lohi = np.angle(hilberted_lohi)
return phase, phase_lohi
[docs] def mean(self, ts):
return self.estimator.mean(ts)
[docs] def estimate(self, phases, phases_lohi):
num_ts, ts_len = np.shape(phases)
self.pairs = [(r1, r2) for r1 in range(0, num_ts) for r2 in range(r1, num_ts)]
pacs_ts = np.zeros((num_ts, num_ts, ts_len), dtype=np.complex)
pacs_avg = np.zeros((num_ts, num_ts))
for pair in self.pairs:
p1, p2 = pair
phase1 = phases[p1,]
phase1_lohi = phases_lohi[p2,]
ts, avg = self.estimator.estimate_pair(phase1, phase1_lohi)
pacs_ts[pair] = ts
pacs_avg[pair] = avg
return pacs_ts, pacs_avg
[docs] def estimate_pair(self, phase1, phase1_lohi):
ts, avg = self.estimator.estimate_pair(phase1, phase1_lohi)
return ts, avg