def average_power_distribution(ridge_results, exclude_coi=False): ''' Compute the power distribution of an ensemble of (ridge-)analyzed signals. Central measure is the time-averaged ridge-power of individual signals. Parameters ---------- ridge_results : sequence (or iterable) of DataFrames holding the ridge data for the individual signals check pyboat.core.eval_ridge for details about the DataFrame structure exclude_coi : bool, if True only average the ridge outside of the COI, for short noisy trajectories there might be no such points! ''' powers = [] # collect the time-averaged powers for rd in ridge_results: if exclude_coi: # take only ridge power outside of COI i_left, i_right = find_COI_crossing(rd) mpower = (rd.power[i_left:i_right]).mean() else: mpower = rd.power.mean() powers.append(mpower) return np.array(powers)
def plot_readout(ridge_data, time_unit="a.u.", draw_coi=False, fig=None): """ ridge_data from core.eval_ridge(...) creates four axes: period, phase, amplitude and power """ # restore the original complete time vector tvec = np.arange(ridge_data.Nt) * ridge_data.dt i_left, i_right = find_COI_crossing(ridge_data) if fig is None: fig = ppl.figure(figsize=(7, 4.8)) periods = ridge_data["periods"] phases = ridge_data["phase"] powers = ridge_data["power"] amplitudes = ridge_data["amplitude"] ridge_t = ridge_data["time"] # indexable # check for discontinuous ridge if np.all(np.diff(ridge_t, n=2) < 1e-12): # draw continuous lines lstyle = '-' mstyle = '' else: lstyle = '' mstyle = 'o' fig.subplots_adjust(wspace=0.3, left=0.11, top=0.98, right=0.97, bottom=0.14) axs = fig.subplots(2, 2, sharex=True) for ax in axs.flatten(): ax.spines['top'].set_visible(False) ax.spines['right'].set_visible(False) ax1 = axs[0, 0] ax2 = axs[0, 1] ax3 = axs[1, 0] ax4 = axs[1, 1] # periods ax1.plot(ridge_t.loc[i_left:i_right], periods.loc[i_left:i_right], color=PERIOD_COLOR, alpha=0.8, lw=2.5, ls=lstyle, marker=mstyle, ms=1.5) # inside COI ax1.plot(ridge_t.loc[:i_left], periods.loc[:i_left], '--', color=PERIOD_COLOR, alpha=0.8, ms=2.5) ax1.plot(ridge_t.loc[i_right:], periods.loc[i_right:], '--', color=PERIOD_COLOR, alpha=0.8, ms=2.5) ax1.set_ylabel(f"Period ({time_unit})", fontsize=label_size) ax1.grid(True, axis="y") yl = ax1.get_ylim() ax1.set_ylim((max([0, 0.75 * yl[0]]), 1.25 * yl[1])) # only now draw the COI? if draw_coi: draw_COI(ax1, tvec) ax1.tick_params(axis="both", labelsize=tick_label_size) # ax1.set_ylim( (120,160) ) # phases ax2.plot(ridge_t.loc[i_left:i_right], phases.loc[i_left:i_right], "-", c=PHASE_COLOR, alpha=0.8, ls=lstyle, marker=mstyle, ms=1.5) # inside COI ax2.plot(ridge_t.loc[:i_left], phases.loc[:i_left], '-.', color=PHASE_COLOR, alpha=0.5, ms=2.5) ax2.plot(ridge_t.loc[i_right:], phases.loc[i_right:], '-.', color=PHASE_COLOR, alpha=0.5, ms=2.5) ax2.set_ylabel("Phase (rad)", fontsize=label_size, labelpad=0.5) ax2.set_yticks((0, pi, 2 * pi)) ax2.set_yticklabels(("$0$", "$\pi$", "$2\pi$")) ax2.tick_params(axis="both", labelsize=tick_label_size) # amplitudes ax3.plot(ridge_t.loc[i_left:i_right], amplitudes.loc[i_left:i_right], c=AMPLITUDE_COLOR, lw=2.5, alpha=0.9, ls=lstyle, marker=mstyle, ms=1.5) # inside COI ax3.plot(ridge_t.loc[:i_left], amplitudes.loc[:i_left], '--', color=AMPLITUDE_COLOR, alpha=0.6, ms=2.5) ax3.plot(ridge_t.loc[i_right:], amplitudes.loc[i_right:], '--', color=AMPLITUDE_COLOR, alpha=0.6, ms=2.5) ax3.set_ylim((0, 1.1 * amplitudes.max())) ax3.ticklabel_format(style="sci", axis="y", scilimits=(0, 0)) ax3.yaxis.offsetText.set_fontsize(tick_label_size) ax3.set_ylabel("Amplitude (a.u.)", fontsize=label_size) ax3.set_xlabel("Time (" + time_unit + ")", fontsize=label_size) ax3.tick_params(axis="both", labelsize=tick_label_size) # powers ax4.plot(ridge_t.loc[i_left:i_right], powers.loc[i_left:i_right], lw=2.5, alpha=0.8, color=POWER_COLOR, ls=lstyle, marker=mstyle, ms=1.5) # inside COI ax4.plot(ridge_t.loc[:i_left], powers.loc[:i_left], '--', color=POWER_COLOR, alpha=0.6, ms=2.5) ax4.plot(ridge_t.loc[i_right:], powers.loc[i_right:], '--', color=POWER_COLOR, alpha=0.6, ms=2.5) ax4.set_ylim((0, 1.1 * powers.max())) ax4.set_ylabel("Power (wnp)", fontsize=label_size) ax4.set_xlabel("Time (" + time_unit + ")", fontsize=label_size) ax4.tick_params(axis="both", labelsize=tick_label_size)
def average_power_distribution(ridge_results, signal_ids=None, exclude_coi=False): ''' Compute the power distribution of an ensemble of (ridge-)analyzed signals. Central measure is the time-averaged ridge-power of individual signals. Parameters ---------- ridge_results : sequence of DataFrames, holds the ridge data for the individual signals. Check pyboat.core.eval_ridge for details about the DataFrame structure signal_ids : sequence, optional labels of the analyzed signals, if not given a numeric sequence of len(ridge_results) will be used as labels exclude_coi : bool, if True only average the ridge outside of the COI, for short noisy trajectories there might be no such points! Returns ------- power_series : pandas Series with the signal_ids as index and averaged powers as values ''' powers = [] ids = [] if signal_ids is None: signal_ids = np.arange(len(ridge_results)) assert len(signal_ids) == len(ridge_results) # collect the time-averaged powers for rd, _id in zip(ridge_results, signal_ids): if exclude_coi: # take only ridge power outside of COI i_left, i_right = find_COI_crossing(rd) mpower = (rd.power[i_left:i_right]).mean() else: mpower = rd.power.mean() # can happen if ridge exclusively inside COI if not np.isnan(mpower): powers.append(mpower) ids.append(_id) powers_series = pd.Series(index=ids, data=powers) # sort by power, descending powers_series.sort_values(ascending=False, inplace=True) return powers_series