Source code for specparam.objs.model

"""Model object, which defines the power spectrum model.

Code Notes
----------
Methods without defined docstrings import docs at runtime, from aliased external functions.
"""

import numpy as np

from specparam.objs.base import BaseObject
from specparam.objs.algorithm import SpectralFitAlgorithm
from specparam.core.reports import save_model_report
from specparam.core.modutils import copy_doc_func_to_method
from specparam.core.errors import NoModelError
from specparam.core.strings import gen_settings_str, gen_model_results_str, gen_issue_str
from specparam.plts.model import plot_model
from specparam.data.utils import get_model_params
from specparam.data.conversions import model_to_dataframe
from specparam.sim.gen import gen_model

###################################################################################################
###################################################################################################

[docs]class SpectralModel(SpectralFitAlgorithm, BaseObject): """Model a power spectrum as a combination of aperiodic and periodic components. WARNING: frequency and power values inputs must be in linear space. Passing in logged frequencies and/or power spectra is not detected, and will silently produce incorrect results. Parameters ---------- peak_width_limits : tuple of (float, float), optional, default: (0.5, 12.0) Limits on possible peak width, in Hz, as (lower_bound, upper_bound). max_n_peaks : int, optional, default: inf Maximum number of peaks to fit. min_peak_height : float, optional, default: 0 Absolute threshold for detecting peaks. This threshold is defined in absolute units of the power spectrum (log power). peak_threshold : float, optional, default: 2.0 Relative threshold for detecting peaks. This threshold is defined in relative units of the power spectrum (standard deviation). aperiodic_mode : {'fixed', 'knee'} Which approach to take for fitting the aperiodic component. verbose : bool, optional, default: True Verbosity mode. If True, prints out warnings and general status updates. Attributes ---------- freqs : 1d array Frequency values for the power spectrum. power_spectrum : 1d array Power values, stored internally in log10 scale. freq_range : list of [float, float] Frequency range of the power spectrum, as [lowest_freq, highest_freq]. freq_res : float Frequency resolution of the power spectrum. modeled_spectrum_ : 1d array The full model fit of the power spectrum, in log10 scale. aperiodic_params_ : 1d array Parameters that define the aperiodic fit. As [Offset, (Knee), Exponent]. The knee parameter is only included if aperiodic component is fit with a knee. peak_params_ : 2d array Fitted parameter values for the peaks. Each row is a peak, as [CF, PW, BW]. gaussian_params_ : 2d array Parameters that define the gaussian fit(s). Each row is a gaussian, as [mean, height, standard deviation]. r_squared_ : float R-squared of the fit between the input power spectrum and the full model fit. error_ : float Error of the full model fit. n_peaks_ : int The number of peaks fit in the model. has_data : bool Whether data is loaded to the object. has_model : bool Whether model results are available in the object. Notes ----- - Commonly used abbreviations used in this module include: CF: center frequency, PW: power, BW: Bandwidth, AP: aperiodic - Input power spectra must be provided in linear scale. Internally they are stored in log10 scale, as this is what the model operates upon. - Input power spectra should be smooth, as overly noisy power spectra may lead to bad fits. For example, raw FFT inputs are not appropriate. Where possible and appropriate, use longer time segments for power spectrum calculation to get smoother power spectra, as this will give better model fits. - The gaussian params are those that define the gaussian of the fit, where as the peak params are a modified version, in which the CF of the peak is the mean of the gaussian, the PW of the peak is the height of the gaussian over and above the aperiodic component, and the BW of the peak, is 2*std of the gaussian (as 'two sided' bandwidth). """
[docs] def __init__(self, peak_width_limits=(0.5, 12.0), max_n_peaks=np.inf, min_peak_height=0.0, peak_threshold=2.0, aperiodic_mode='fixed', verbose=True, **model_kwargs): """Initialize model object.""" BaseObject.__init__(self, aperiodic_mode=aperiodic_mode, periodic_mode='gaussian', debug_mode=model_kwargs.pop('debug_mode', False), verbose=verbose) SpectralFitAlgorithm.__init__(self, peak_width_limits=peak_width_limits, max_n_peaks=max_n_peaks, min_peak_height=min_peak_height, peak_threshold=peak_threshold, **model_kwargs)
[docs] def report(self, freqs=None, power_spectrum=None, freq_range=None, plt_log=False, plot_full_range=False, **plot_kwargs): """Run model fit, and display a report, which includes a plot, and printed results. Parameters ---------- freqs : 1d array, optional Frequency values for the power spectrum. power_spectrum : 1d array, optional Power values, which must be input in linear space. freq_range : list of [float, float], optional Frequency range to fit the model to. If not provided, fits across the entire given range. plt_log : bool, optional, default: False Whether or not to plot the frequency axis in log space. plot_full_range : bool, default: False If True, plots the full range of the given power spectrum. Only relevant / effective if `freqs` and `power_spectrum` passed in in this call. **plot_kwargs Keyword arguments to pass into the plot method. Plot options with a name conflict be passed by pre-pending 'plot_'. e.g. `freqs`, `power_spectrum` and `freq_range`. Notes ----- Data is optional, if data has already been added to the object. """ self.fit(freqs, power_spectrum, freq_range) self.plot(plt_log=plt_log, freqs=freqs if plot_full_range else plot_kwargs.pop('plot_freqs', None), power_spectrum=power_spectrum if \ plot_full_range else plot_kwargs.pop('plot_power_spectrum', None), freq_range=plot_kwargs.pop('plot_freq_range', None), **plot_kwargs) self.print_results(concise=False)
[docs] def print_settings(self, description=False, concise=False): """Print out the current settings. Parameters ---------- description : bool, optional, default: False Whether to print out a description with current settings. concise : bool, optional, default: False Whether to print the report in a concise mode, or not. """ print(gen_settings_str(self, description, concise))
[docs] def print_results(self, concise=False): """Print out model fitting results. Parameters ---------- concise : bool, optional, default: False Whether to print the report in a concise mode, or not. """ print(gen_model_results_str(self, concise))
[docs] @staticmethod def print_report_issue(concise=False): """Prints instructions on how to report bugs and/or problematic fits. Parameters ---------- concise : bool, optional, default: False Whether to print the report in a concise mode, or not. """ print(gen_issue_str(concise))
[docs] def get_params(self, name, col=None): """Return model fit parameters for specified feature(s). Parameters ---------- name : {'aperiodic_params', 'peak_params', 'gaussian_params', 'error', 'r_squared'} Name of the data field to extract. col : {'CF', 'PW', 'BW', 'offset', 'knee', 'exponent'} or int, optional Column name / index to extract from selected data, if requested. Only used for name of {'aperiodic_params', 'peak_params', 'gaussian_params'}. Returns ------- out : float or 1d array Requested data. Raises ------ NoModelError If there are no model fit parameters available to return. Notes ----- If there are no fit peak (no peak parameters), this method will return NaN. """ if not self.has_model: raise NoModelError("No model fit results are available to extract, can not proceed.") return get_model_params(self.get_results(), name, col)
[docs] @copy_doc_func_to_method(plot_model) def plot(self, plot_peaks=None, plot_aperiodic=True, freqs=None, power_spectrum=None, freq_range=None, plt_log=False, add_legend=True, ax=None, data_kwargs=None, model_kwargs=None, aperiodic_kwargs=None, peak_kwargs=None, **plot_kwargs): plot_model(self, plot_peaks=plot_peaks, plot_aperiodic=plot_aperiodic, freqs=freqs, power_spectrum=power_spectrum, freq_range=freq_range, plt_log=plt_log, add_legend=add_legend, ax=ax, data_kwargs=data_kwargs, model_kwargs=model_kwargs, aperiodic_kwargs=aperiodic_kwargs, peak_kwargs=peak_kwargs, **plot_kwargs)
[docs] @copy_doc_func_to_method(save_model_report) def save_report(self, file_name, file_path=None, add_settings=True, **plot_kwargs): save_model_report(self, file_name, file_path, add_settings, **plot_kwargs)
[docs] def to_df(self, peak_org): """Convert and extract the model results as a pandas object. Parameters ---------- peak_org : int or Bands How to organize peaks. If int, extracts the first n peaks. If Bands, extracts peaks based on band definitions. Returns ------- pd.Series Model results organized into a pandas object. """ return model_to_dataframe(self.get_results(), peak_org)
def _regenerate_model(self): """Regenerate model fit from parameters.""" self.modeled_spectrum_, self._peak_fit, self._ap_fit = gen_model( self.freqs, self.aperiodic_params_, self.gaussian_params_, return_components=True)