Skip to content

Knee model issue #384

@nb-bu

Description

@nb-bu

Hi fooof/specparam team,

First of all: Thanks for this really cool work, the toolbox is super useful! I've already gladly applied it in previous work (the fixed model without a knee).

Now to my current issue: In a project, I am also interested in the knee parameter, as we want to extract tau as an indicator for intrinsic neural timescales from the knee, based on your/Richard Gao's reported approach.

Our EEG data is recorded from 64 channels and preprocessed with a standard Matlab pipeline (roughly based on Arnaud Delormes proposed pipeline). PSD's are then created using pwelch with
win = 1000; % window size for pwelch
ov = 0.5; % overlap for pwelch
[psd, freqs] = pwelch(EEG_even.data(jx,:), win, [ov*win], [], EEG_even.srate);
Afterwards, I'm fooofing the PSD through the fooof_mat implementation. The whole code loops over all electrodes from all recordings of all participants.

The issue is: for some PSD's (i.e., for some people's specific electrodes), fooof fails with the following warning:

Model fitting was unsuccessful.
Error using EEG_preprocessing_updated_251201 (line 461)
Python Error: TypeError: 'NoneType' object is not iterable

I've tried making sense of the error message, but I can't quite wrap my head around what the underlying cause of the issue is. The PSD generally looks "fine", I believe, at least it's not flat/empty.

The thing is, on a given PSD where the knee model fails, a fixed model fits without issues (see attached images). However, I do explicitly want the knee parameter for my INT/tau extraction.
If the problem were also that a given PSD doesn't show a bend/knee, shouldn't the algorithm with the free parameter (knee mode) simply fit the parameter at the value where it's fixed for fixed mode, and still converge?

Image Image

I have tried tweaking the fooof settings already (peak width limits, max peaks, min peak height etc), which doesn't seem to make any difference for the error. The only thing that seems to make a difference is the frequency range (used for both bandpass filtering and fooof algorithm), where my script might not fail for the same electrode PSD after a f_range change, but will then fail for another person's PSD.

Some of my latest tryout-settings are posted below (note that my aspired f_range for fitting would be [1, 45] ).

f_range = [1, 135];

settings = struct(...
'peak_width_limits', [0.5, 12], ...
'max_n_peaks', 8, ... % Inf, ...
'min_peak_height', 0.1, ...
'peak_threshold', 2.0, ...
'aperiodic_mode', 'knee', ...

freqs = freqs'; % Transpose, to make inputs row vectors
psd = psd';

fooof_results = fooof(freqs, psd, f_range, settings, true);

Before writing this issue, I already googled and went through many of the other posted issues, but I couldn't find a relevant explanation.
Am I overlooking something super obvious here? Does anybody know of similar issues?

Would be super thankful for your opinion. I could proceed with the fallback option of just not fitting the fooof model to these few specific electrodes or replacing them with NA, but I wanted to see if there is a clear reason for this error first.

Version info:
Matlab version 2020b
EEGLAB version 2025.0.0
Fooof version 1.1.1
Fooof_mat version 1.0.0
Python version 3.8

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions