code: def _compute_source_psd_epochs(
      epochs,
      inverse_operator,
      lambda2=1.0 / 9.0,
      method="dSPM",
      fmin=0.0,
      fmax=200.0,
      pick_ori=None,
      label=None,
      nave=1,
      pca=True,
      inv_split=None,
      bandwidth=4.0,
      adaptive=False,
      low_bias=True,
      n_jobs=None,
      prepared=False,
      method_params=None,
      return_sensor=False,
      use_cps=True,
  ):
      """Generate compute_source_psd_epochs."""
      logger.info("Considering frequencies %g ... %g Hz" % (fmin, fmax))
  
      if label:
          # TODO: add multi-label support
          # since `_prepare_source_params` can handle a list of labels now,
          # multi-label support should be within reach for psd calc as well
          _validate_type(
              label,
              types=(Label, BiHemiLabel, None),
              type_name=("Label or BiHemiLabel", "None"),
          )
  
      (
          K,
          sel,
          Vh,
          vertno,
          is_free_ori,
          noise_norm,
          _,
      ) = _prepare_source_params(
          inst=epochs,
          inverse_operator=inverse_operator,
          label=label,
          lambda2=lambda2,
          method=method,
          nave=nave,
          pca=pca,
          pick_ori=pick_ori,
          prepared=prepared,
          method_params=method_params,
          use_cps=use_cps,
      )
      # Simplify code with a tiny (rel. to other computations) penalty for eye
      # mult
      Vh = np.eye(K.shape[1]) if Vh is None else Vh
  
      # split the inverse operator
      if inv_split is not None:
          K_split = np.array_split(K, inv_split)
      else:
          K_split = [K]
  
      # compute DPSS windows
      n_times = len(epochs.times)
      sfreq = epochs.info["sfreq"]
  
      dpss, eigvals, adaptive = _compute_mt_params(
          n_times, sfreq, bandwidth, low_bias, adaptive, verbose=False
      )
  
      n_tapers = len(dpss)
      try:
          n_epochs = len(epochs)
      except RuntimeError:
          n_epochs = len(epochs.events)
          extra = "on at most %d epochs" % (n_epochs,)
      else:
          extra = "on %d epochs" % (n_epochs,)
      if isinstance(bandwidth, str):
          bandwidth = "%s windowing" % (bandwidth,)
      else:
          bandwidth = "%d tapers with bandwidth %0.1f Hz" % (
              n_tapers,
              bandwidth,
          )
      logger.info("Using %s %s" % (bandwidth, extra))
  
      if adaptive:
          parallel, my_psd_from_mt_adaptive, n_jobs = parallel_func(
              _psd_from_mt_adaptive, n_jobs
          )
      else:
          weights = np.sqrt(eigvals)[np.newaxis, :, np.newaxis]
  
      subject = _subject_from_inverse(inverse_operator)
      iter_epochs = ProgressBar(epochs, max_value=n_epochs)
      evoked_info = pick_info(epochs.info, sel, verbose=False)
      for k, e in enumerate(iter_epochs):
          data = np.dot(Vh, e[sel])  # reducing data rank
  
          # compute tapered spectra in sensor space
          x_mt, freqs = _mt_spectra(data, dpss, sfreq)
  
          if k == 0:
              freq_mask = (freqs >= fmin) & (freqs <= fmax)
              fstep = np.mean(np.diff(freqs))
              with evoked_info._unlock():
                  evoked_info["sfreq"] = 1.0 / fstep
          freqs = freqs[freq_mask]
  
          # sensor space PSD
          x_mt_sensor = np.empty(
              (len(sel), x_mt.shape[1], x_mt.shape[2]), dtype=x_mt.dtype
          )
          for i in range(n_tapers):
              x_mt_sensor[:, i, :] = np.dot(Vh.T, x_mt[:, i, :])
          if adaptive:
              out = parallel(
                  my_psd_from_mt_adaptive(x, eigvals, freq_mask)
                  for x in np.array_split(
                      x_mt_sensor, min(n_jobs, len(x_mt_sensor))
                  )
              )
              sensor_psd = np.concatenate(out)
          else:
              x_mt_sensor = x_mt_sensor[:, :, freq_mask]
              sensor_psd = _psd_from_mt(x_mt_sensor, weights)
  
          # allocate space for output
          psd = np.empty((K.shape[0], np.sum(freq_mask)))
  
          # Optionally, we split the inverse operator into parts to save memory.
          # Without splitting the tapered spectra in source space have size
          # (n_vertices x n_tapers x n_times / 2)
          pos = 0
          for K_part in K_split:
              # allocate space for tapered spectra in source space
              x_mt_src = np.empty(
                  (K_part.shape[0], x_mt.shape[1], x_mt.shape[2]),
                  dtype=x_mt.dtype,
              )
  
              # apply inverse to each taper (faster than equiv einsum)
              for i in range(n_tapers):
                  x_mt_src[:, i, :] = np.dot(K_part, x_mt[:, i, :])
  
              # compute the psd
              if adaptive:
                  out = parallel(
                      my_psd_from_mt_adaptive(x, eigvals, freq_mask)
                      for x in np.array_split(
                          x_mt_src, min(n_jobs, len(x_mt_src))
                      )
                  )
                  this_psd = np.concatenate(out)
              else:
                  x_mt_src = x_mt_src[:, :, freq_mask]
                  this_psd = _psd_from_mt(x_mt_src, weights)
  
              psd[pos : pos + K_part.shape[0], :] = this_psd
              pos += K_part.shape[0]
  
          # combine orientations
          if is_free_ori and pick_ori is None:
              psd = combine_xyz(psd, square=False)
  
          if noise_norm is not None:
              psd *= noise_norm**2
  
          out = _make_stc(
              psd,
              tmin=freqs[0],
              tstep=fstep,
              vertices=vertno,
              subject=subject,
              src_type=inverse_operator["src"].kind,
          )
  
          if return_sensor:
              comment = "Epoch %d PSD" % (k,)
              out = (
                  out,
                  EvokedArray(
                      sensor_psd,
                      evoked_info.copy(),
                      freqs[0],
                      comment,
                      nave,
                  ),
              )
  
          # we return a generator object for "stream processing"
          yield out
  
      iter_epochs.update(n_epochs)
  
imports: import numpy
  from .._fiff.constants import FIFF
  from .._fiff.pick import pick_info
  from ..baseline import _log_rescale, rescale
  from ..epochs import Epochs
  from ..event import make_fixed_length_events
  from ..evoked import EvokedArray
  from ..fixes import _safe_svd
  from ..label import BiHemiLabel, Label
  from ..parallel import parallel_func
  from ..source_estimate import _make_stc
  from ..time_frequency.multitaper import _compute_mt_params, _mt_spectra, _psd_from_mt, _psd_from_mt_adaptive
  from ..time_frequency.tfr import cwt, morlet
  from ..utils import ProgressBar, _check_option, _pl, _validate_type, logger, verbose
  from .inverse import INVERSE_METHODS, _assemble_kernel, _check_or_prepare, _check_ori, _pick_channels_inverse_operator, _subject_from_inverse, combine_xyz
label_desc: Use image node_id 11 for calling a global function with example usage: _compute_source_psd_epochs(epochs, inverse_operator, lambda2, method, fmin, fmax, pick_ori, label, nave, pca, inv_split, bandwidth, adaptive, low_bias, n_jobs, prepared, method_params, return_sensor, use_cps) without return types