def test_fooof_checks(): """Test various checks, errors and edge cases in FOOOF.""" xs, ys = gen_power_spectrum([3, 50], [50, 2], [10, 0.5, 2]) tfm = FOOOF() # Check dimension error with raises(ValueError): tfm.fit(xs, np.reshape(ys, [1, len(ys)])) # Check shape mismatch error with raises(ValueError): tfm.fit(xs[:-1], ys) # Check trim_spectrum range tfm.fit(xs, ys, [3, 40]) # Check freq of 0 issue xs, ys = gen_power_spectrum([3, 50], [50, 2], [10, 0.5, 2]) tfm.fit(xs, ys) assert tfm.freqs[0] != 0 # Check fit, and string report model error (no data / model fit) tfm = FOOOF() with raises(ValueError): tfm.fit()
def run_foof(x, y): """ Fits the FOOOF (fitting oscillations & one over f) model. Returns slopes (num obs), offsets (num obs), and the peak fit power spectra (num obs x num features) """ res_shape = (y.shape[0], y.shape[-1]) if y.ndim == 3 else y.shape[0] slopes = np.full(res_shape, np.nan, dtype='float32') offsets = np.full(res_shape, np.nan, dtype='float32') resids = np.full(y.shape, np.nan, dtype='float32') # initialize foof fm = FOOOF(peak_width_limits=[1.0, 8.0], peak_threshold=0.5) for i, this_event in enumerate(y): if this_event.ndim == 2: freq_dim = np.array([n == len(x) for n in this_event.shape]) freq_dim_num = np.where(freq_dim)[0][0] if freq_dim_num == 0: this_event = this_event.T for j, this_event_sub in enumerate(this_event): fm.add_data(x, y) fm.fit() offsets[i, j] = fm.background_params_[0] slopes[i, j] = fm.background_params_[1] resids[i, :, j] = fm._peak_fit else: fm.add_data(x, this_event) fm.fit() offsets[i] = fm.background_params_[0] slopes[i] = fm.background_params_[1] resids[i] = fm._peak_fit return slopes, offsets, resids
def get_fooof(self, ind, regenerate=False): """Return a FOOOF object from specified model in a FOOOFGroup object. Parameters ---------- ind : int The index of the FOOOFResult in FOOOFGroup.group_results to load. regenerate : bool, optional Whether to regenerate the model fits from the given fit parameters. default : False Returns ------- inst : FOOOF() object The FOOOFResult data loaded into a FOOOF object. """ # Initialize a FOOOF object, with same settings as current FOOOFGroup fm = FOOOF(self.peak_width_limits, self.max_n_peaks, self.min_peak_amplitude, self.peak_threshold, self.background_mode, self.verbose) # Add data for specified single power spectrum, if available # The power spectrum is inverted back to linear, as it's re-logged when added to FOOOF if np.any(self.power_spectra): fm.add_data(self.freqs, np.power(10, self.power_spectra[ind])) # Add results for specified power spectrum, regenerating full fit if requested fm.add_results(self.group_results[ind], regenerate=regenerate) return fm
def _run_fooof(raw, fmin=0.001, fmax=1, tmin=0, tmax=None, n_overlap=200, n_fft=400, peak_width_limits=(0.5, 12.0)): """Prepare data for FOOOF including welch and scaling, then apply.""" from fooof import FOOOF spectra, freqs = psd_welch(raw, fmin=fmin, fmax=fmax, tmin=tmin, tmax=tmax, n_overlap=n_overlap, n_fft=n_fft) # FOOOF doesn't like low frequencies, so multiple by 10. # This is corrected for in the output below. freqs = freqs * 10 # Remember these values are really 0.001 to 1.2 Hz fm = FOOOF(peak_width_limits=peak_width_limits) # And these values are really 0.0001 to 1 Hz freq_range = [0.001, 10] fm.fit(freqs, np.mean(spectra, axis=0), freq_range) return fm
def run_fooofgroup(number_of_patients, base_params_save_path, patient_group, brain_region, freq_range): """converts text files of Power and Frequency to numpy files to be processed by FOOOFGroup """ joiner = [ base_params_save_path, patient_group, 'Results_', brain_region, '/' ] params_save_path = ''.join(str(e) for e in joiner) fm = FOOOF(peak_width_limits=[1.5, 8], max_n_peaks=6, min_peak_amplitude=0.3) joiner = [ base_params_save_path, 'raw_', patient_group, 'data/', frequencies_file_name ] """remove hashtags before ", delimiter" for text files with comma-separated data points""" realfreqs = np.loadtxt( ''.join(joiner)) #, delimiter = ',', usecols=range((118))) joiner = [ base_params_save_path, 'raw_', patient_group, 'data/', power_file_name ] realspectrum = np.loadtxt( ''.join(joiner)) #,delimiter = ',', usecols=range((118))) joiner = [ base_params_save_path, patient_group, 'Results_', brain_region, '/Freqs_', brain_region, '_', patient_group, '.npy' ] np.save(''.join(joiner), np.array(realfreqs)) joiner = [ base_params_save_path, patient_group, 'Results_', brain_region, '/Freqs_', brain_region, '_', patient_group, '.npy' ] frequencies = np.load(''.join(joiner)) #load new freqlist joiner = [ params_save_path, 'Spec_', brain_region, '_', patient_group, '.npy' ] np.save(''.join(joiner), np.array(realspectrum)) joiner = [ params_save_path, 'Spec_', brain_region, '_', patient_group, '.npy' ] spectrum = np.load(''.join(joiner)) #load new powlist """flattens, to pdfs""" get_flattened_plots(spectrum, frequencies, number_of_patients, fm, fg, patient_group, brain_region, params_save_path) """group results, to pdf""" get_group_results(fg, frequencies, spectrum, freq_range, params_save_path) """Extract background data, to pdfs""" get_data_for_each_fit(fg, params_save_path, patient_group, brain_region) """saves individual fits, to pdfs!""" get_individual_fits(number_of_patients, patient_group, brain_region, fg, params_save_path)
def run_fooof(freq_path,loc_path,save_report_path,save_variables_path,save_variable_prefix,save_variables = True ,save_report=True,freq_range=[1,30],channel = 'Oz'): freqIterator = folderIterator(freq_path) chan_inds_iterator = chanIndIterator(loc_path) # Constant bg_ppts= []# background parameters/ppts peak_ppts = [] errors = [] for chan_ind, freq_var in zip(chan_inds_iterator,freqIterator) if True: # if files[0].endswith(".mat"): TODO: set the conditions for safety power,spectrum = getFreqValuesVec(freq_var) if chan_ind != -1 power = 10**np.array(power[chan_ind]) spectrum=np.array(spectrum).flatten() # Initialize FOOOF object fm = FOOOF(peak_width_limits=[0.5,8]) # Model the power spectrum with FOOOF, and print out a report fm.fit(spectrum, power, freq_range) bg_ppts.append(fm.background_params_) peak_ppts.append(fm.peak_params_) errors.append(fm.error_) if save_report: fm.save_report(str(freq_var[-7:-4]),save_report_path) if save_variables : with cd(save_variables_path): save_file(save_variable_prefix+'bg_ppts.npy',bg_ppts) save_file(save_variable_prefix+'peak_ppts.npy',peak_ppts) save_file(save_variable_prefix+'errors.npy',errors)
def refit_aperiodic(freqs, powers, peak_fit): """Refit the aperiodic component following the periodic refit. Parameters ---------- freqs : 1d array Frequency values for the power spectrum, in linear scale. powers : 1d array Power values, in log10 scale. peak_fit : 1d array Perodic refit, in log10 scale. Returns ------- ap_params : 1d array Exponent and offset values. ap_fit : 1d array Regenerated aperiodic fit. """ # Access simple ap fit method _fm = FOOOF() _fm.power_spectrum = powers _fm.freqs = freqs # Remove peaks spectrum_peak_rm = powers - peak_fit # Refit ap_params = _fm._simple_ap_fit(freqs, spectrum_peak_rm) ap_fit = gen_aperiodic(freqs, ap_params) return ap_params, ap_fit
def test_copy(): """Test copy FOOOF method.""" tfm = FOOOF(verbose=False) ntfm = tfm.copy() assert tfm != ntfm
def avg_fg(fg, avg='mean'): """Average across a FOOOFGroup object.""" if avg == 'mean': avg_func = np.nanmean elif avg == 'median': avg_func = np.nanmedian ap_params = avg_func(fg.get_all_data('aperiodic_params'), 0) peak_params = avg_func( get_band_peak_group(fg.get_all_data('peak_params'), [7, 14], len(fg)), 0) peak_params = peak_params[np.newaxis, :] gaussian_params = avg_func( get_band_peak_group(fg.get_all_data('gaussian_params'), [7, 14], len(fg)), 0) gaussian_params = gaussian_params[np.newaxis, :] r2 = avg_func(fg.get_all_data('r_squared')) error = avg_func(fg.get_all_data('error')) results = FOOOFResults(ap_params, peak_params, r2, error, gaussian_params) # Create the new FOOOF object, with settings, data info & results fm = FOOOF() fm.add_settings(fg.get_settings()) fm.add_data_info(fg.get_data_info()) fm.add_results(results) return fm
def get_fooof(self, ind, regenerate=False): """Return a FOOOF object from specified model in a FOOOFGroup object. Parameters ---------- ind : int The index of the FOOOFResults in FOOOFGroup.group_results to load. regenerate : bool, optional, default: False Whether to regenerate the model fits from the given fit parameters. Returns ------- inst : FOOOF() object The FOOOFResults data loaded into a FOOOF object. """ # Initialize a FOOOF object, with same settings as current FOOOFGroup fm = FOOOF(*self.get_settings(), verbose=self.verbose) # Add data for specified single power spectrum, if available # The power spectrum is inverted back to linear, as it's re-logged when added to FOOOF if np.any(self.power_spectra): fm.add_data(self.freqs, np.power(10, self.power_spectra[ind])) # If no power spectrum data available, copy over data information & regenerate freqs else: fm.add_meta_data(self.get_meta_data()) # Add results for specified power spectrum, regenerating full fit if requested fm.add_results(self.group_results[ind]) if regenerate: fm._regenerate_model() return fm
def test_copy(): """Test copy FOOOF method.""" tfm = FOOOF() ntfm = tfm.copy() assert tfm != ntfm
def test_fooof_report(skip_if_no_mpl): """Check that running the top level model method runs.""" tfm = FOOOF() tfm.report(*gen_power_spectrum([3, 50], [50, 2], [10, 0.5, 2, 20, 0.3, 4])) assert tfm
def whitening(X, ordar=10, block_length=256, sfreq=1., zero_phase=True, plot=False, use_fooof=False): n_trials, n_channels, n_times = X.shape ar_model = Arma(ordar=ordar, ordma=0, fs=sfreq, block_length=block_length) ar_model.periodogram(X.reshape(-1, n_times), hold=False, mean_psd=True) if use_fooof: # pragma: no cover # Fit the psd with a 1/f^a background model plus a gaussian mixture. # We keep only the background model # (pip install fooof) from fooof import FOOOF fm = FOOOF(background_mode='fixed', verbose=False) power_spectrum = ar_model.psd[-1][0] freqs = np.linspace(0, sfreq / 2.0, len(power_spectrum)) fm.fit(freqs, power_spectrum, freq_range=None) # repete first point, which is f_0 bg_fit = np.r_[fm._bg_fit[0], fm._bg_fit][None, :] ar_model.psd.append(np.power(10, bg_fit)) if zero_phase: ar_model.psd[-1] = np.sqrt(ar_model.psd[-1]) ar_model.estimate() # apply the whitening for zero-phase filtering X_white = apply_whitening(ar_model, X, zero_phase=zero_phase, mode='same') assert X_white.shape == X.shape # removes edges n_times_white = X_white.shape[-1] X_white *= signal.tukey(n_times_white, alpha=3 / float(n_times_white))[None, None, :] if plot: # pragma: no cover import matplotlib.pyplot as plt # plot the Power Spectral Density (PSD) before/after ar_model.arma2psd(hold=True) if zero_phase: ar_model.psd[-2] **= 2 ar_model.psd[-1] **= 2 ar_model.periodogram(X_white.reshape(-1, n_times), hold=True, mean_psd=True) labels = ['signal', 'model AR', 'signal white'] if use_fooof: labels = ['signal', 'FOOOF fit', 'model AR', 'signal white'] ar_model.plot('periodogram before/after whitening', labels=labels, fscale='lin') plt.legend(loc='lower left') return ar_model, X_white
def run_fooof_trials(timewin, padlabel): """ Use FOOOF to get individual trial slope and HFA (offset) measurements. """ for subject in SUBJECTS: print(subject) # Load data. mat_contents = sio.loadmat('/Volumes/DATAHD/Active/KAH/' + subject + '/psd/' + subject + '_FR1_psd_' + str(timewin[0]) + '_' + str(timewin[1]) + padlabel + '.mat') # Extract frequency axis and power spectra. PSDs are 'channels x frequencies x trials'. freq = np.squeeze(mat_contents['freq']) psds = mat_contents['psds'] # Initialize FOOOF model. foof_model = FOOOF(background_mode='fixed', peak_width_limits=[2.5, 12], peak_threshold=np.inf) # Initialize output (list of FOOOF oscillation parameters), one for each channel and trial. slopes = [[[] for _ in range(psds.shape[-1])] for _ in range(psds.shape[0])] hfa = [[[] for _ in range(psds.shape[-1])] for _ in range(psds.shape[0])] # Fit model per channel per trial. for ichan in range(psds.shape[0]): for itrial in range(psds.shape[-1]): # Fit for slope and HFA. try: foof_model.fit(freq, psds[ichan, :, itrial], [2, 150]) except Exception: print('Skipping channel {}, trial {} because of slope'. format(ichan, itrial)) continue hfa[ichan][itrial] = foof_model.background_params_[0] slopes[ichan][itrial] = foof_model.background_params_[1] # # Fit for HFA. # try: # foof_model.fit(freq, psds[ichan, :, itrial], [2, 150]) # except Exception: # print('Skipping channel {}, trial {} because of hfa'.format(ichan, itrial)) # continue # hfa[ichan][itrial] = foof_model.background_params_[0] # Save to .mat file. sio.savemat( '/Volumes/DATAHD/Active/KAH/' + subject + '/fooof/' + subject + '_FR1_fooof_' + str(timewin[0]) + '_' + str(timewin[1]) + padlabel + '_slopes_hfa.mat', { 'slopes': slopes, 'hfa': hfa }) print('Done.')
def test_get_obj_desc(): desc = get_obj_desc() tfm = FOOOF() objs = dir(tfm) # Test that everything in dict is a valid component of the fooof object for ke, va in desc.items(): for it in va: assert it in objs
def average_fg(fg, bands, avg_method='mean', generate_model=True): """Average across a FOOOFGroup object. Parameters ---------- fg : FOOOFGroup A FOOOFGroup object with data to average across. bands : Bands Bands object that defines the frequency bands to collapse peaks across. avg : {'mean', 'median'} Averaging function to use. generate_model : bool, optional, default: True Whether to generate the model for the averaged parameters. Returns ------- fm : FOOOF FOOOF object containing the average results from the FOOOFGroup input. """ if avg_method not in ['mean', 'median']: raise ValueError('Requested average method not understood.') if not len(fg): raise ValueError( 'Input FOOOFGroup has no fit results - can not proceed.') if avg_method == 'mean': avg_func = np.nanmean elif avg_method == 'median': avg_func = np.nanmedian ap_params = avg_func(fg.get_params('aperiodic_params'), 0) peak_params = np.array([avg_func(get_band_peak_fg(fg, band, 'peak_params'), 0) \ for label, band in bands]) gaussian_params = np.array([avg_func(get_band_peak_fg(fg, band, 'gaussian_params'), 0) \ for label, band in bands]) r2 = avg_func(fg.get_params('r_squared')) error = avg_func(fg.get_params('error')) results = FOOOFResults(ap_params, peak_params, r2, error, gaussian_params) # Create the new FOOOF object, with settings, data info & results fm = FOOOF() fm.add_settings(fg.get_settings()) fm.add_meta_data(fg.get_meta_data()) fm.add_results(results) # Generate the model from the average parameters if generate_model: fm._regenerate_model() return fm
def test_fooof_fit_knee(): """Test FOOOF fit, with a knee.""" bgp = [50, 2, 1] gauss_params = [10, 0.5, 2, 20, 0.3, 4] xs, ys = gen_power_spectrum([3, 50], bgp, gauss_params) tfm = FOOOF(background_mode='knee') tfm.fit(xs, ys) # Note: currently, this test has no accuracy checking at all assert True
def test_fooof_fit_knee(): """Test FOOOF fit, with a knee.""" ap_params = [50, 2, 1] gaussian_params = [10, 0.5, 2, 20, 0.3, 4] xs, ys = gen_power_spectrum([3, 50], ap_params, gaussian_params) tfm = FOOOF(aperiodic_mode='knee', verbose=False) tfm.fit(xs, ys) # Note: currently, this test has no accuracy checking at all assert True
def get_tfm(): """Get a FOOOF object, with a fit power spectrum, for testing.""" freq_range = [3, 50] bg_params = [50, 2] gauss_params = [10, 0.5, 2, 20, 0.3, 4] xs, ys = gen_power_spectrum(freq_range, bg_params, gauss_params) tfm = FOOOF() tfm.fit(xs, ys) return tfm
def get_all_features(eeg_epoch_full_df): power_ratios_df, std_err_df, avg_df = getPowerBin(eeg_epoch_full_df) band_ratios_df = getPowerBandRatios(power_ratios_df) diff_df = get_channel_relationships(power_ratios_df) insta_stat_df = get_alpha_instantaneous_statistics(eeg_epoch_full_df) fooof_parameters_df = FOOOF(eeg_epoch_full_df) # Concatenate power_ratios_df with band_ratios_df to get full feature df feature_df = pd.concat([ power_ratios_df, band_ratios_df, diff_df, insta_stat_df, fooof_parameters_df ], axis=1) return feature_df
def test_fooof_load(): """Test load into FOOOF. Note: loads files from test_core_io.""" file_name_all = 'test_fooof_str_all' file_name_res = 'test_fooof_str_res' file_path = pkg.resource_filename(__name__, 'test_files') tfm = FOOOF() tfm.load(file_name_all, file_path) assert tfm tfm.load(file_name_res, file_path) assert tfm
def cal_FOOOF_parameters(pxx, f, rois=210, freq_range=[0.5, 48]): # initialize FOOOF oject fm = FOOOF() # create variables FOOOF_offset = np.empty(rois) FOOOF_slope = np.empty(rois) # loop over all rois for roi in np.arange(rois): # model the power spectrum with FOOOF for each roi in rois # LD: this part does not run because the size of the freqs var is somehow not consistent fm.fit(f, pxx[:, roi], freq_range) FOOOF_offset[roi] = fm.background_params_[0] FOOOF_slope[roi] = fm.background_params_[1] return FOOOF_offset, FOOOF_slope
def test_fooof_fit_nk(): """Test FOOOF fit, no knee.""" bgp = [50, 2] gauss_params = [10, 0.5, 2, 20, 0.3, 4] xs, ys = gen_power_spectrum([3, 50], bgp, gauss_params) tfm = FOOOF() tfm.fit(xs, ys) # Check model results - background parameters assert np.all(np.isclose(bgp, tfm.background_params_, [0.5, 0.1])) # Check model results - gaussian parameters for ii, gauss in enumerate(group_three(gauss_params)): assert np.all(np.isclose(gauss, tfm._gaussian_params[ii], [1.5, 0.25, 0.5]))
def test_fooof_fit_failure(): """Test that fit handles a failure.""" # Use a new FOOOF, that is monkey-patched to raise an error # This mimicks the main fit-failure, without requiring bad data / waiting for it to fail. tfm = FOOOF() def raise_runtime_error(*args, **kwargs): raise RuntimeError('Test-MonkeyPatch') tfm._fit_peaks = raise_runtime_error # Run a FOOOF fit - this should raise an error, but continue in try/except tfm.fit(*gen_power_spectrum([3, 50], [50, 2], [10, 0.5, 2, 20, 0.3, 4])) # Check after failing out of fit, all results are reset for result in get_obj_desc()['results']: cur_res = getattr(tfm, result) assert cur_res is None or np.all(np.isnan(cur_res))
def calc_spec_peak(freqs, powers, fitting_bw=[1, 55], out_image_path=None): '''Spectral fitting routine from the FOOOF toolbox https://fooof-tools.github.io/fooof/index.html doi: https://doi.org/10.1101/299859 Fit the spectral peaks and return the fit parameters Save the image of the spectral data and peak fits Inputs: freqs - numpy array of frequencies powers - numpy array of spectral power fitting_bw - Reduce the total bandwidth to fit the 1/f and spectral peaks Outputs: params - parameters from the FOOOF fit ''' #Crop Frequencies for 1/f powers = powers[(freqs > fitting_bw[0]) & (freqs <= fitting_bw[1])] freqs = freqs[(freqs > fitting_bw[0]) & (freqs <= fitting_bw[1])] # Initialize power spectrum model objects and fit the power spectra fm1 = FOOOF(min_peak_height=0.05, verbose=False) fm1.fit(freqs, powers) if out_image_path is not None: import matplotlib from matplotlib import pylab matplotlib.use('Agg') # import pylab fig = pylab.Figure(figsize=[10, 6]) #, dpi=150) ax = fig.add_subplot() plot_annotated_model(fm1, annotate_peaks=False, ax=ax) fig.tight_layout() fig.savefig(out_image_path, dpi=150, bbox_inches="tight") params = fm1.get_results() params.peak_params[0] # plot_spectrum(freqs, powers, log_powers=True, # color='black', label='Original Spectrum') return params
def test_fooof_fit_nk(): """Test FOOOF fit, no knee.""" ap_params = [50, 2] gauss_params = [10, 0.5, 2, 20, 0.3, 4] xs, ys = gen_power_spectrum([3, 50], ap_params, gauss_params) tfm = FOOOF(verbose=False) tfm.fit(xs, ys) # Check model results - aperiodic parameters assert np.all(np.isclose(ap_params, tfm.aperiodic_params_, [0.5, 0.1])) # Check model results - gaussian parameters for ii, gauss in enumerate(group_three(gauss_params)): assert np.all( np.isclose(gauss, tfm.gaussian_params_[ii], [2.0, 0.5, 1.0]))
def compute_FOOOF(data, sf, precision=0.1, max_freq=80, noverlap=None, nperseg=None, nfft=None, n_peaks=5, extended_returns=False, graph=False): if nperseg is None: mult = 1 / precision nfft = sf * mult nperseg = nfft noverlap = nperseg // 10 freqs1, psd = scipy.signal.welch(data, sf, nfft=nfft, nperseg=nperseg, noverlap=noverlap) fm = FOOOF(peak_width_limits=[precision * 2, 3], max_n_peaks=50, min_peak_height=0.2) freq_range = [(sf / len(data)) * 2, max_freq] fm.fit(freqs1, psd, freq_range) if graph is True: fm.report(freqs1, psd, freq_range) peaks_temp = [] amps_temp = [] for p in range(len(fm.peak_params_)): try: peaks_temp.append(fm.peak_params_[p][0]) amps_temp.append(fm.peak_params_[p][1]) except: print('no peaks were found') pass peaks_temp = [x for _, x in sorted(zip(amps_temp, peaks_temp)) ][::-1][0:n_peaks] amps_temp = sorted(amps_temp)[::-1][0:n_peaks] peaks_temp = [np.round(p, 2) for p in peaks_temp] if extended_returns is True: return peaks_temp, amps_temp, freqs1, psd return peaks_temp, amps_temp
def fit_fooof(freqs, powers, freq_range, init_kwargs, n_jobs): """A generalized FOOOF fit function to handle 1d, 2d, or 3d arrays. Parameters ---------- powers : 1d, 2d, or 3d array Power values for a single spectrum, or group of power spectra. Power values are stored internally in log10 scale. freqs : 1d array Frequency values for the power spectra. freq_range : list of [float, float] Frequency range of the power spectra, as [lowest_freq, highest_freq]. init_kwargs : dict FOOOF object initialization kwargs. n_jobs : int Specificy the number of jobs to run in parrallel for 2d or 3d arrays. Returns ------- model : FOOOF, FOOOFGroup, or list of FOOOFGroup objects. A FOOOF object that has been fit. A 1d array will return a FOOOF objects, a 2d array will return a FOOOFGroup object, and a 3d array will return a list of FOOOFGroup objects. """ if powers.ndim == 1: # Fit a 1d array model = FOOOF(**init_kwargs) model.fit(freqs, powers, freq_range=freq_range) elif powers.ndim == 2: # Fit a 2d array model = FOOOFGroup(**init_kwargs) model.fit(freqs, powers, freq_range=freq_range, n_jobs=n_jobs) elif powers.ndim == 3: # Fit a 3d array model = FOOOFGroup(**init_kwargs) model = fit_fooof_3d(model, freqs, powers, n_jobs=n_jobs) else: raise ValueError( 'The power_spectrum argument must specify a 1d, 2d, or 3d array.') return model
def get_tt_psd_peaks(freqs, pxx, theta_range=None): if theta_range is None: theta_range = [4, 12] n_chans = pxx.shape[0] sixty_range = [58, 62] df = pd.DataFrame( columns=['th_pk', 'th_amp', '60_pk', '60_amp', '1/f_r2', 'rmse']) for ch in range(n_chans): fm = FOOOF(max_n_peaks=2, peak_threshold=2.0, peak_width_limits=[0.5, 6.0], verbose=False) fm.fit(freqs, pxx[ch], [2, 100]) pks = fm.peak_params_.flatten()[::3] amps = fm.peak_params_.flatten()[1::3] idx = (pks >= theta_range[0]) & (pks <= theta_range[1]) theta_pk = pks[idx] theta_amp = amps[idx] idx = (pks >= sixty_range[0]) & (pks <= sixty_range[1]) sixty_pk = pks[idx] sixty_amp = amps[idx] if len(theta_pk) == 1: df.at[ch, 'th_pk'] = np.around(theta_pk[0], decimals=2) df.at[ch, 'th_amp'] = np.around(theta_amp[0], decimals=2) elif len(theta_pk) > 1: df.at[ch, 'th_pk'] = np.around(np.mean(theta_pk), decimals=2) df.at[ch, 'th_amp'] = np.around(np.mean(theta_amp), decimals=2) if len(sixty_pk) == 1: df.at[ch, '60_pk'] = np.around(sixty_pk[0], decimals=2) df.at[ch, '60_amp'] = np.around(sixty_amp[0], decimals=2) elif len(sixty_pk) > 1: df.at[ch, '60_pk'] = np.around(np.mean(sixty_pk), decimals=2) df.at[ch, '60_amp'] = np.around(np.mean(sixty_amp), decimals=2) df.at[ch, 'rmse'] = np.around(fm.error_, decimals=3) df.at[ch, '1/f_r2'] = np.around(fm.r_squared_, decimals=3) return df
def fooofy(components, spectra, x_range, group=True): """ fit FOOOF model on given spectrum and return params components: frequencies or PC dimensions spectra: PSDs or variance explained x_range: range for x axis of spectrum to fit group: whether to use FOOOFGroup or not """ if group: fg = FOOOFGroup(max_n_peaks=0, aperiodic_mode='fixed', verbose=False) #initialize FOOOF object else: fg = FOOOF(max_n_peaks=0, aperiodic_mode='fixed', verbose=False) #initialize FOOOF object #print(spectra.shape, components.shape) #Use this line if things go weird fg.fit(components, spectra, x_range) exponents = fg.get_params('aperiodic_params', 'exponent') errors = fg.get_params('error') # MAE offsets = fg.get_params('aperiodic_params', 'offset') return exponents, errors, offsets