Repository: mne-tools/mne-python

Issue:
Allow for computation of TFR using Morlet wavelets but with fwhm as an alternative parameter to wave-number
### Describe the new feature or enhancement

It is nice to see `mne.time_frequency.fwhm` but it is a tad useless (except for final reporting), unless we can use `fwhm` values to construct the wavelets. For an instructive case, where this comes handy, see **Fig. 5 a (var)** in Cohen (2019).

### Describe your proposed implementation

As a new capability to `mne.time_frequency.morlet` and like methods.

### Describe possible alternatives

None

### Additional context

_No response_


Discussion:
IIRC there was some discussion of this back when https://github.com/mne-tools/mne-python/pull/11353 was being worked on.  @larsoner @britta-wstnr WDYT?  Can we support constructing wavelets based on their FWHM, and if so, what is a good API to do that?
Back then we added the formula to compute the FWHM to the docstring (e.g. of `mne.time_frequency.morlet`). Using this formula, also the adequate number of cycles for a desired FWHM can be computed and then passed to the function.

That being said, we could support this via the functions as well - I think we discussed it back in December at some point but I don't remember the pro's and con's anymore, @larsoner ?
If we want to add it, I guess a new parameter (maybe `wav_fwhm` or so)  that is mutually exclusive with `n_cycles` would be needed.
I think the idea was to avoid adding a new `kwarg` by having this convenience conversion function. But we could have mutually exclusive `kwargs` instead if it really helps
> I think the idea was to avoid adding a new `kwarg` by having this convenience conversion function

The function goes the wrong direction though: it takes in `freq` and `n_cycles` and spits out `fwhm`.

I can open a PR to add this, I think it's worthwhile.

Resolving patch:
diff --git a/mne/utils/docs.py b/mne/utils/docs.py
--- a/mne/utils/docs.py
+++ b/mne/utils/docs.py
@@ -1435,16 +1435,34 @@ def _reflow_param_docstring(docstring, has_first_line=True, width=75):
 """
 
 docdict['fwhm_morlet_notes'] = r"""
-In wavelet analysis, the oscillation that is defined by ``n_cycles`` is tapered
-by a Gaussian taper, i.e., the edges of the wavelet are dampened. This means
-that reporting the number of cycles is not necessarily helpful for
-understanding the amount of temporal smoothing that has been applied (see
-:footcite:`Cohen2019`). Instead, the full width at half-maximum (FWHM) of the
-wavelet can be reported.
-
-The FWHM of the wavelet at a specific frequency is defined as:
-:math:`\mathrm{FWHM} = \frac{\mathtt{n\_cycles} \times \sqrt{2 \ln{2}}}{\pi \times \mathtt{freq}}`
-(cf. eq. 4 in :footcite:`Cohen2019`).
+Convolution of a signal with a Morlet wavelet will impose temporal smoothing
+that is determined by the duration of the wavelet. In MNE-Python, the duration
+of the wavelet is determined by the ``sigma`` parameter, which gives the
+standard deviation of the wavelet's Gaussian envelope (our wavelets extend to
+±5 standard deviations to ensure values very close to zero at the endpoints).
+Some authors (e.g., :footcite:`Cohen2019`) recommend specifying and reporting
+wavelet duration in terms of the full-width half-maximum (FWHM) of the
+wavelet's Gaussian envelope. The FWHM is related to ``sigma`` by the following
+identity: :math:`\mathrm{FWHM} = \sigma \times 2 \sqrt{2 \ln{2}}` (or the
+equivalent in Python code: ``fwhm = sigma * 2 * np.sqrt(2 * np.log(2))``).
+If ``sigma`` is not provided, it is computed from ``n_cycles`` as
+:math:`\frac{\mathtt{n\_cycles}}{2 \pi f}` where :math:`f` is the frequency of
+the wavelet oscillation (given by ``freqs``). Thus when ``sigma=None`` the FWHM
+will be given by
+
+.. math::
+
+    \mathrm{FWHM} = \frac{\mathtt{n\_cycles} \times \sqrt{2 \ln{2}}}{\pi \times f}
+
+(cf. eq. 4 in :footcite:`Cohen2019`). To create wavelets with a chosen FWHM,
+one can compute::
+
+    n_cycles = desired_fwhm * np.pi * np.array(freqs) / np.sqrt(2 * np.log(2))
+
+to get an array of values for ``n_cycles`` that yield the desired FWHM at each
+frequency in ``freqs``.  If you want different FWHM values at each frequency,
+do the same computation with ``desired_fwhm`` as an array of the same shape as
+``freqs``.
 """  # noqa E501
 
 # %%


Test patch: