def test_interpolate_spectrum(): # Test with single buffer exclusion zone freqs, powers = gen_power_spectrum(\ [1, 75], [1, 1], [[10, 0.5, 1.0], [60, 2, 0.1]]) exclude = [58, 62] freqs_out, powers_out = interpolate_spectrum(freqs, powers, exclude) assert np.array_equal(freqs, freqs_out) assert np.all(powers) assert powers.shape == powers_out.shape mask = np.logical_and(freqs >= exclude[0], freqs <= exclude[1]) assert powers[mask].sum() > powers_out[mask].sum() # Test with multiple buffer exclusion zones freqs, powers = gen_power_spectrum(\ [1, 150], [1, 100, 1], [[10, 0.5, 1.0], [60, 1, 0.1], [120, 0.5, 0.1]]) exclude = [[58, 62], [118, 122]] freqs_out, powers_out = interpolate_spectrum(freqs, powers, exclude) assert np.array_equal(freqs, freqs_out) assert np.all(powers) assert powers.shape == powers_out.shape for f_range in exclude: mask = np.logical_and(freqs >= f_range[0], freqs <= f_range[1]) assert powers[mask].sum() > powers_out[mask].sum()
def test_translate_sim_spectrum(): sim_params = SimParams([1, 1], [10, 0.5, 1], 0) freqs, spectrum = gen_power_spectrum([3, 40], *sim_params) translated_spectrum, new_sim_params = translate_sim_spectrum( spectrum, 0.5, sim_params) assert not np.all(translated_spectrum == spectrum) assert new_sim_params.aperiodic_params[0] == 1.5
def test_interpolate_spectrum(): freqs, powers = gen_power_spectrum(\ [1, 75], [1, 1], [[10, 0.5, 1.0], [60, 2, 0.1]]) freqs_out, powers_out = interpolate_spectrum(freqs, powers, [58, 62]) assert np.array_equal(freqs, freqs_out) assert np.all(powers) assert powers.shape == powers_out.shape
def test_rotate_sim_spectrum(): sim_params = SimParams([1, 1], [10, 0.5, 1], 0) freqs, spectrum = gen_power_spectrum([3, 40], *sim_params) rotated_spectrum, new_sim_params = rotate_sim_spectrum( freqs, spectrum, 0.5, 20, sim_params) assert not np.all(rotated_spectrum == spectrum) assert new_sim_params.aperiodic_params[1] == 1.5
def test_translate_spectrum(): # Create a spectrum to use for test translation freqs, spectrum = gen_power_spectrum([1, 100], [1, 1], []) # Check that translation transforms the power spectrum translated_spectrum = translate_spectrum(spectrum, delta_offset=1.) assert not np.all(translated_spectrum == spectrum) # Check that 0 translation returns the same spectrum translated_spectrum = translate_spectrum(spectrum, delta_offset=0.) assert np.all(translated_spectrum == spectrum)
def get_tfm(): """Get a FOOOF object, with a fit power spectrum, for testing.""" freq_range = [3, 50] ap_params = [50, 2] gaussian_params = [10, 0.5, 2, 20, 0.3, 4] xs, ys = gen_power_spectrum(freq_range, ap_params, gaussian_params) tfm = FOOOF(verbose=False) tfm.fit(xs, ys) return tfm
def test_rotate_spectrum(): # Create a spectrum to use for test rotations freqs, spectrum = gen_power_spectrum([1, 100], [1, 1], []) # Check that rotation transforms the power spectrum rotated_spectrum = rotate_spectrum(freqs, spectrum, delta_exponent=0.5, f_rotation=25.) assert not np.all(rotated_spectrum == spectrum) # Check that 0 rotation returns the same spectrum rotated_spectrum = rotate_spectrum(freqs, spectrum, delta_exponent=0., f_rotation=25.) assert np.all(rotated_spectrum == spectrum)
# Interpolating Line Noise Peaks # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # # One approach is to interpolate away line noise peaks, in the frequency domain. This # approach simply gets rid of the peaks, interpolating the data to maintain the 1/f # character of the data, allowing for subsequent fitting. # # The :func:`~fooof.utils.interpolate_spectrum` function allows for doing simple # interpolation. Given a narrow frequency region, this function interpolates the spectrum, # such that the 'peak' of the line noise is removed. # ################################################################################################### # Generate an example power spectrum, with line noise freqs1, powers1 = gen_power_spectrum([3, 75], [1, 1], [[10, 0.75, 2], [60, 1, 0.5]]) # Visualize the generated power spectrum plot_spectra(freqs1, powers1, log_powers=True) ################################################################################################### # # In the plot above, we have an example spectrum, with some power line noise. # # To prepare this data for fitting, we can interpolate away the line noise region. # ################################################################################################### # Interpolate away the line noise region interp_range = [58, 62]
def FOOOF(eeg_epoch_full_df): # Import required code for visualizing example models from fooof import FOOOF from fooof.sim.gen import gen_power_spectrum from fooof.sim.utils import set_random_seed from fooof.plts.annotate import plot_annotated_model # Set random seed, for consistency generating simulated data set_random_seed(10) # Simulate example power spectra freqs1, powers1 = gen_power_spectrum([3, 40], [1, 1], [[10, 0.2, 1.25], [30, 0.15, 2]]) # Initialize power spectrum model objects and fit the power spectra fm1 = FOOOF(min_peak_height=0.05, verbose=False) fm1.fit(freqs1, powers1) plot_annotated_model(fm1, annotate_aperiodic=True) # Constants freq_range = [1, 40] alpha_range = (7, 12) # Initialize a FOOOF object fm = FOOOF(peak_width_limits=[1, 8], max_n_peaks=6, min_peak_height=0.4) # Get the PSD of our EEG Signal sig = eeg_epoch_full_df['Cz'][0] freq, psd = getMeanFreqPSD(sig) fm.add_data(freq, psd, freq_range) fm.fit() fm.report() # Get PSD averages for each channel for each event type (0=left or 1=right) psd_averages_by_type = {} for event_type in event_types.keys(): psds_only_one_type = {} freqs_only_one_type = {} for i, row in eeg_epoch_full_df[eeg_epoch_full_df["event_type"] == event_type].iterrows(): for ch in all_chans: if ch not in psds_only_one_type: psds_only_one_type[ch] = list() freqs_only_one_type[ch] = list() f, p = getMeanFreqPSD(row[ch]) psds_only_one_type[ch].append(p) freqs_only_one_type[ch].append(f) avg_psds_one_type = {} for ch in all_chans: psds_only_one_type[ch] = np.array(psds_only_one_type[ch]) avg_psds_one_type[ch] = np.mean(psds_only_one_type[ch], axis=0) psd_averages_by_type[event_type] = dict(avg_psds_one_type) # Visualize the parameters in these two classes of C4 activity fm_left_C4 = FOOOF(peak_width_limits=[1, 8], max_n_peaks=6, min_peak_height=0.4) fm_left_C4.add_data(freqs_only_one_type[eeg_chans[0]][0], psd_averages_by_type[0]['C4'], freq_range) fm_left_C4.fit() fm_left_C4.report() fm_right_C4 = FOOOF(peak_width_limits=[1, 8], max_n_peaks=6, min_peak_height=0.4) fm_right_C4.add_data(freqs_only_one_type[eeg_chans[0]][0], psd_averages_by_type[1]['C4'], freq_range) fm_right_C4.fit() fm_right_C4.report() # Calculate central freq, alpha power, and bandwidth for each channel and each trial # This cell takes a few minutes to run (~8 mins on my computer). There are 3680 trials in the training data. # Initialize a fooof object fm = FOOOF(peak_width_limits=[1, 8], max_n_peaks=6, min_peak_height=0.4) # Some will not have alpha peaks, use these variables to keep track num_with_alpha = 0 num_without_alpha = 0 fooof_parameters = {} for i in range(len(eeg_epoch_full_df)): # Print the trial number every 100 to make sure we're making progress if i % 100 == 0: print(i) for ch in all_chans: # Determine the key CF_key = ch + "_alpha_central_freq" PW_key = ch + "_alpha_power" BW_key = ch + "_alpha_band_width" if CF_key not in fooof_parameters: fooof_parameters[CF_key] = [] if PW_key not in fooof_parameters: fooof_parameters[PW_key] = [] if BW_key not in fooof_parameters: fooof_parameters[BW_key] = [] # Calculate the PSD for the desired signal sig = eeg_epoch_full_df[ch][i] freq, psd = getMeanFreqPSD(sig) # Set the frequency and spectral data into the FOOOF model and get peak params fm.add_data(freq, psd, freq_range) fm.fit() peak_params = fm.peak_params_ # Only select the peaks within alpha power peak_params_alpha = [] for param in peak_params: if (param[0] > alpha_range[0]) and (param[0] < alpha_range[1]): peak_params_alpha.append(param) # Take the average if there are multiple peaks detected, otherwise 0 everything means = [] if len(peak_params_alpha) > 0: num_with_alpha += 1 means = np.mean(peak_params_alpha, axis=0) else: num_without_alpha += 1 means = [0, 0, 0] fooof_parameters[CF_key].append(means[0]) fooof_parameters[PW_key].append(means[1]) fooof_parameters[BW_key].append(means[2]) fooof_parameters_df = pd.DataFrame(fooof_parameters) print("% with alpha:", num_with_alpha / (num_with_alpha + num_without_alpha)) return fooof_parameters_df
# Define default aperiodic values ap = [0, 1] # Define default periodic values for band specific peaks theta = [6, 0.4, 1] alpha = [10, 0.5, 0.75] beta = [25, 0.3, 1.5] # Set random seed, for consistency generating simulated data set_random_seed(21) ################################################################################################### # Simulate a power spectrum freqs, powers = gen_power_spectrum(f_range, ap, [theta, alpha, beta], nlv, f_res) ################################################################################################### # Calculating Band Ratios # ~~~~~~~~~~~~~~~~~~~~~~~ # # Band ratio measures are a ratio of power between defined frequency bands. # # We can now define a function we can use to calculate band ratio measures, and # apply it to our baseline power spectrum. # # For this example, we will be using the theta / beta ratio, which is the # most commonly applied band ratio measure. # # Note that it doesn't matter exactly which ratio measure or which frequency band # definitions we use, as the general properties demonstrated here generalize
# Simulate a group of power spectra freqs, powers, sim_params = gen_group_power_spectra(n_spectra, freq_range, ap_params, pe_params, nlv, return_params=True) ################################################################################################### # Print out the SimParams objects that track the parameters used to create power spectra for sim_param in sim_params: print(sim_param) ################################################################################################### # You can also use a SimParams object to regenerate a particular power spectrum cur_params = sim_params[0] freqs, powers = gen_power_spectrum(freq_range, *cur_params) ################################################################################################### # Managing Parameters # ------------------- # # There are also helper functions for managing and selecting parameters for # simulating groups of power spectra. # # These functions include: # # - :func:`~.param_sampler` which can be used to sample parameters from possible options # - :func:`~.param_iter` which can be used to iterate across parameter ranges # - :func:`~.param_jitter` which can be used to add some 'jitter' to simulation parameters #
# Import simulation utilities to create example data from fooof.sim.gen import gen_power_spectrum # Import functions that can transform power spectra from fooof.sim.transform import (rotate_spectrum, translate_spectrum, rotate_sim_spectrum, translate_sim_spectrum, compute_rotation_offset, compute_rotation_frequency) # Import plot function to visualize power spectra from fooof.plts.spectra import plot_spectra ################################################################################################### # Generate a simulated power spectrum freqs, powers, params = gen_power_spectrum([3, 40], [1, 1], [10, 0.5, 1], return_params=True) ################################################################################################### # Rotating Power Spectra # ---------------------- # # The :func:`~.rotate_spectrum` function takes in a power spectrum, and # rotates the power spectrum a specified amount, around a specified frequency point, # changing the aperiodic exponent of the spectrum. # ################################################################################################### # Rotation settings delta_exp = 0.25 # How much to change the exponent by f_rotation = 20 # The frequency at which to rotate the spectrum
f_range = [3, 35] # Define baseline parameter values ap_base = [0, 1.5] pe_base = [[10, 0.5, 1], [22, 0.2, 2]] # Define parameters sets with changes in each parameter pw_diff = [[10, 0.311, 1], [22, 0.2, 2]] cf_diff = [[11.75, 0.5, 1], [22, 0.2, 2]] off_diff = [-0.126, 1.5] exp_diff = [-0.87, 0.75] ################################################################################################### # Create baseline power spectrum, to compare to freqs, powers_base = gen_power_spectrum(f_range, ap_base, pe_base, nlv, f_res) ################################################################################################### # Create comparison power spectra, with differences in different parameters of the data _, powers_pw = gen_power_spectrum(f_range, ap_base, pw_diff, nlv, f_res) _, powers_cf = gen_power_spectrum(f_range, ap_base, cf_diff, nlv, f_res) _, powers_off = gen_power_spectrum(f_range, off_diff, pe_base, nlv, f_res) _, powers_exp = gen_power_spectrum(f_range, exp_diff, pe_base, nlv, f_res) ################################################################################################### # Collect the comparison power spectra together all_powers = { 'Alpha Power Change': powers_pw, 'Alpha Frequency Change': powers_cf,
# # In this example, we will simulated power spectra to explore the available # plotting options. First, we'll create two spectra, using an example with different # aperiodic components with the same oscillations, including theta, alpha & beta peaks. # ################################################################################################### # Settings & parameters for the simulations freq_range = [3, 40] ap_1 = [0.75, 1.5] ap_2 = [0.25, 1] peaks = [[6, 0.2, 1], [10, 0.3, 1], [25, 0.15, 3]] # Simulate two example power spectra freqs, powers1 = gen_power_spectrum(freq_range, ap_1, peaks) freqs, powers2 = gen_power_spectrum(freq_range, ap_2, peaks) ################################################################################################### # Plotting Individual Power Spectra # --------------------------------- # # First we will start with the core plotting function that plots an individual power spectrum. # # The :func:`~.plot_spectra` function takes in an array of frequency values and a 1d array of # of power values, and plots the corresponding power spectrum. # # This function, as all the functions in the plotting module, takes in optional inputs # `log_freqs` and `log_powers` that control whether the frequency and power axes # are plotted in log space. #
# sphinx_gallery_thumbnail_number = 5 # Import required code for visualizing example models from fooof import FOOOF from fooof.sim.gen import gen_power_spectrum from fooof.sim.utils import set_random_seed from fooof.plts.spectra import plot_spectra from fooof.plts.annotate import plot_annotated_model ################################################################################################### # Set random seed, for consistency generating simulated data set_random_seed(21) # Simulate example power spectra freqs1, powers1 = gen_power_spectrum([3, 40], [1, 1], [[10, 0.2, 1.25], [30, 0.15, 2]]) freqs2, powers2 = gen_power_spectrum([1, 150], [1, 125, 1.25], [[8, 0.15, 1.], [30, 0.1, 2]]) ################################################################################################### # Initialize power spectrum model objects and fit the power spectra fm1 = FOOOF(min_peak_height=0.05, verbose=False) fm2 = FOOOF(min_peak_height=0.05, aperiodic_mode='knee', verbose=False) fm1.fit(freqs1, powers1) fm2.fit(freqs2, powers2) ################################################################################################### # # Now, we have some data and models to work with. #
# Set consistent aperiodic parameters ap_params = [1, 1] # Set periodic parameters, defined to vary between groups # All parameters are set to match, except for systematic power differences pe_g1 = [[2, 0.25, 1], [6, 0.2, 1], [10, 0.5, 1.5], [20, 0.2, 3], [40, 0.25, 3.5]] pe_g2 = [[2, 0.5, 1], [6, 0.3, 1], [10, 0.5, 1.5], [20, 0.15, 3], [40, 0.15, 3.5]] # Set random seed, for consistency generating simulated data set_random_seed(21) ################################################################################################### # Simulate example power spectra for each group freqs, g1_spectrum_bands = gen_power_spectrum(f_range, ap_params, pe_g1, nlv) freqs, g2_spectrum_bands = gen_power_spectrum(f_range, ap_params, pe_g2, nlv) ################################################################################################### # Plot the power spectra differences, representing the 'band-by-band' idea plot_spectra_shading(freqs, [g1_spectrum_bands, g2_spectrum_bands], log_powers=True, linewidth=3, shades=bands.definitions, shade_colors=shade_cols, labels=labels) plt.xlim(f_range); plt.title('Band-by-Band', t_settings); ################################################################################################### # Flatten the Spectra # ~~~~~~~~~~~~~~~~~~~
def main(): ## Individual Model Plot # Download examples data files needed for this example freqs = load_fooof_data('freqs.npy', folder='data') spectrum = load_fooof_data('spectrum.npy', folder='data') # Initialize and fit an example power spectrum model fm = FOOOF(peak_width_limits=[1, 6], max_n_peaks=6, min_peak_height=0.2, verbose=False) fm.fit(freqs, spectrum, [3, 40]) # Save out the report fm.save_report('FOOOF_report.png', 'img') ## Group Plot # Download examples data files needed for this example freqs = load_fooof_data('group_freqs.npy', folder='data') spectra = load_fooof_data('group_powers.npy', folder='data') # Initialize and fit a group of example power spectrum models fg = FOOOFGroup(peak_width_limits=[1, 6], max_n_peaks=6, min_peak_height=0.2, verbose=False) fg.fit(freqs, spectra, [3, 30]) # Save out the report fg.save_report('FOOOFGroup_report.png', 'img') ## Make the icon plot # Simulate an example power spectrum fs, ps = gen_power_spectrum([4, 35], [0, 1], [[10, 0.3, 1], [22, 0.15, 1.25]], nlv=0.01) def custom_style(ax, log_freqs, log_powers): """Custom styler-function for the icon plot.""" # Set the top and right side frame & ticks off ax.spines['right'].set_visible(False) ax.spines['top'].set_visible(False) # Set linewidth of remaining spines ax.spines['left'].set_linewidth(10) ax.spines['bottom'].set_linewidth(10) ax.set_xticks([], []) ax.set_yticks([], []) # Create and save out the plot plot_spectrum(fs, ps, log_freqs=False, log_powers=True, lw=12, alpha=0.8, color='grey', plot_style=custom_style, ax=check_ax(None, [6, 6])) plt.tight_layout() plt.savefig('img/spectrum.png') ## Clean Up # Remove the data folder shutil.rmtree('data')
# create and return a simulated power spectrum. Note that the parameters that define the peaks # are labeled as gaussian parameters, as these parameters define the simulated gaussians # directly, and are not the modified peak parameters that the model outputs. # ################################################################################################### # Settings & parameters for creating a simulated power spectrum freq_range = [3, 40] # The frequency range to simulate aperiodic_params = [1, 1] # Parameters defining the aperiodic component periodic_params = [10, 0.3, 1] # Parameters for any periodic components ################################################################################################### # Generate a simulated power spectrum freqs, powers = gen_power_spectrum(freq_range, aperiodic_params, periodic_params) ################################################################################################### # Plot the simulated power spectrum plot_spectrum(freqs, powers, log_freqs=True, log_powers=False) ################################################################################################### # Simulating With Different Parameters # ------------------------------------ # # Power spectra can be simulated with any desired parameters in the power spectrum model. # # The aperiodic mode for the simulated power spectrum is inferred from the parameters provided. # If two parameters are provided, this is interpreted as [offset, exponent] for simulating # a power spectra with a 'fixed' aperiodic component. If three parameters are provided, as in
################################################################################################### # Set the frequency range to generate the power spectrum f_range = [1, 50] # Set aperiodic component parameters, as [offset, exponent] ap_params = [20, 2] # Gaussian peak parameters gauss_params = [[10, 1.0, 2.5], [20, 0.8, 2], [32, 0.6, 1]] # Set the level of noise to generate the power spectrum with nlv = 0.1 # Set random seed, for consistency generating simulated data set_random_seed(21) # Create a simulated power spectrum freqs, spectrum = gen_power_spectrum(f_range, ap_params, gauss_params, nlv) ################################################################################################### # Fit an (unconstrained) model, liable to overfit fm = FOOOF() fm.report(freqs, spectrum) ################################################################################################### # # Notice that in the above fit, we are very likely to think that the model has # been overzealous in fitting peaks, and is therefore overfitting. # # This is also suggested by the model r-squared, which is suspiciously # high, given the amount of noise we in the simulated power spectrum. #
# sphinx_gallery_thumbnail_number = 2 # Import matplotlib to help manage plotting import matplotlib.pyplot as plt # Import the FOOOF object from fooof import FOOOF # Import simulation functions to create some example data from fooof.sim.gen import gen_power_spectrum ################################################################################################### # Generate an example power spectrum freqs, powers = gen_power_spectrum([3, 50], [1, 1], [[9, 0.25, 0.5], [22, 0.1, 1.5], [25, 0.2, 1.]]) ################################################################################################### # Plotting From FOOOF Objects # ~~~~~~~~~~~~~~~~~~~~~~~~~~~ # # The FOOOF object has a :meth:`~fooof.FOOOF.plot` method that can be used to visualize # data and models available in the :class:`~fooof.FOOOF` object. # ################################################################################################### # Initialize a FOOOF object, and add some data to it fm = FOOOF(verbose=False) fm.add_data(freqs, powers)
# # Note that all FOOOF functions that simulate power spectra take in # gaussian parameters, not the modified peak parameters. # ################################################################################################### # Settings for creating a simulated power spectrum freq_range = [3, 40] # The frequency range to simulate aperiodic_params = [1, 1] # Parameters defining the aperiodic component gaussian_params = [10, 0.3, 1] # Parameters for any periodic components ################################################################################################### # Generate a simulated power spectrum fs, ps = gen_power_spectrum(freq_range, aperiodic_params, gaussian_params) ################################################################################################### # Plot the simulated power spectrum plot_spectrum(fs, ps, log_freqs=True, log_powers=False) ################################################################################################### # Simulating With Different Parameters # ------------------------------------ # # Power spectra can be simulated with any desired parameters for the FOOOF power spectra model. # # The aperiodic mode for the simulated power spectrum is inferred from the parameters provided. # If two parameters are provided, this is interpreted as [offset, exponent] for simulating # a power spectra with a 'fixed' aperiodic component. If three parameters are provided, as in
Apply transformations to power spectra. """ ################################################################################################### # Imports from fooof.sim.gen import gen_power_spectrum from fooof.sim.transform import rotate_spectrum from fooof.plts.spectra import plot_spectra ################################################################################################### # Generate a simulated power spectrum fs, ps = gen_power_spectrum([3, 40], [1, 1], [10, 0.5, 1]) ################################################################################################### # rotate_spectrum # --------------- # # The :func:`rotate_spectrum` function takes in a power spectrum, and rotates the # power spectrum a specified amount, around a specified frequency point, changing # the aperiodic exponent of the spectrum. # ################################################################################################### # Rotate the power spectrum nps = rotate_spectrum(fs, ps, 0.25, 20)
from fooof.sim.gen import gen_power_spectrum ################################################################################################### # # First, we will simulate some example data, and fit some individual power spectrum models. # ################################################################################################### # Settings for simulations freq_range = [1, 50] freq_res = 0.25 # Create some example power spectra freqs, powers_1 = gen_power_spectrum(freq_range, [0, 1.0], [10, 0.25, 2], nlv=0.00, freq_res=freq_res) freqs, powers_2 = gen_power_spectrum(freq_range, [0, 1.2], [9, 0.20, 1.5], nlv=0.01, freq_res=freq_res) freqs, powers_3 = gen_power_spectrum(freq_range, [0, 1.5], [11, 0.3, 2.5], nlv=0.02, freq_res=freq_res) ################################################################################################### # Initialize a set of FOOOF objects fm1, fm2, fm3 = FOOOF(max_n_peaks=4), FOOOF(max_n_peaks=4), FOOOF( max_n_peaks=4) # Fit power spectrum models
# Checking the Error of Individual Model Fits # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # # First we will start by examining frequency-by-frequency error of an individual model fit, # using simulated data. # # The function for analyzing error from a FOOOF object is # :func:`~.compute_pointwise_error_fm`. # To start with, we will indicate to this function to plot the frequency-by-frequency # error of our model fit. # ################################################################################################### # Simulate an example power spectrum freqs, powers = gen_power_spectrum([3, 50], [1, 1], [10, 0.25, 0.5]) ################################################################################################### # Initialize a FOOOF object to fit with fm = FOOOF(verbose=False) # Parameterize our power spectrum fm.fit(freqs, powers) ################################################################################################### # Calculate the error per frequency of the model compute_pointwise_error_fm(fm, plot_errors=True) ###################################################################################################