[docs]defsignal_phase(signal,method="radians"):"""**Compute the phase of the signal** The real phase has the property to rotate uniformly, leading to a uniform distribution density. The prophase typically doesn't fulfill this property. The following functions applies a nonlinear transformation to the phase signal that makes its distribution exactly uniform. If a binary vector is provided (containing 2 unique values), the function will compute the phase of completion of each phase as denoted by each value. Parameters ---------- signal : Union[list, np.array, pd.Series] The signal (i.e., a time series) in the form of a vector of values. method : str The values in which the phase is expressed. Can be ``"radians"`` (default), ``"degrees"`` (for values between 0 and 360) or ``"percents"`` (for values between 0 and 1). See Also -------- signal_filter, signal_zerocrossings, signal_findpeaks Returns ------- array A vector containing the phase of the signal, between 0 and 2*pi. Examples -------- .. ipython:: python import neurokit2 as nk signal = nk.signal_simulate(duration=10) phase = nk.signal_phase(signal) @savefig p_signal_phase1.png scale=100% nk.signal_plot([signal, phase]) @suppress plt.close() ..ipython:: python rsp = nk.rsp_simulate(duration=30) phase = nk.signal_phase(rsp, method="degrees") @savefig p_signal_phase2.png scale=100% nk.signal_plot([rsp, phase]) @suppress plt.close() .. ipython:: python # Percentage of completion of two phases signal = nk.signal_binarize(nk.signal_simulate(duration=10)) phase = nk.signal_phase(signal, method="percents") @savefig p_signal_phase3.png scale=100% nk.signal_plot([signal, phase]) """# If binary signaliflen(set(np.array(signal)[~np.isnan(np.array(signal))]))==2:phase=_signal_phase_binary(signal)else:phase=_signal_phase_prophase(signal)ifmethod.lower()in["degree","degrees"]:phase=np.rad2deg(phase)ifmethod.lower()in["perc","percent","percents","percentage"]:phase=np.rad2deg(phase)/360returnphase
# =============================================================================# Method# =============================================================================def_signal_phase_binary(signal):phase=itertools.chain.from_iterable(np.linspace(0,1,sum([1foriinv]))for_,vinitertools.groupby(signal))phase=np.array(list(phase))# Convert to radiantphase=np.deg2rad(phase*360)returnphasedef_signal_phase_prophase(signal):pi2=2.0*np.pi# Get pro-phaseprophase=np.mod(np.angle(scipy.signal.hilbert(signal)),pi2)# Transform a pro-phase to a real phasesort_idx=np.argsort(prophase)# Get a sorting indexreverse_idx=np.argsort(sort_idx)# Get index reversing sortingtht=pi2*np.arange(prophase.size)/(prophase.size)# Set up sorted real phasephase=tht[reverse_idx]# Reverse the sorting of itreturnphase