code: def _psd_from_mt_adaptive(
      x_mt, eigvals, freq_mask, max_iter=250, return_weights=False
  ):
      r"""Use iterative procedure to compute the PSD from tapered spectra.
  
      .. note:: Modified from NiTime.
  
      Parameters
      ----------
      x_mt : array, shape=(n_signals, n_tapers, n_freqs)
          The DFTs of the tapered sequences (only positive frequencies)
      eigvals : array, length n_tapers
          The eigenvalues of the DPSS tapers
      freq_mask : array
          Frequency indices to keep
      max_iter : int
          Maximum number of iterations for weight computation.
      return_weights : bool
          Also return the weights
  
      Returns
      -------
      psd : array, shape=(n_signals, np.sum(freq_mask))
          The computed PSDs
      weights : array shape=(n_signals, n_tapers, np.sum(freq_mask))
          The weights used to combine the tapered spectra
  
      Notes
      -----
      The weights to use for making the multitaper estimate, such that
      :math:`S_{mt} = \sum_{k} |w_k|^2S_k^{mt} / \sum_{k} |w_k|^2`
      """
      n_signals, n_tapers, n_freqs = x_mt.shape
  
      if len(eigvals) != n_tapers:
          raise ValueError("Need one eigenvalue for each taper")
  
      if n_tapers < 3:
          raise ValueError(
              "Not enough tapers to compute adaptive weights."
          )
  
      rt_eig = np.sqrt(eigvals)
  
      # estimate the variance from an estimate with fixed weights
      psd_est = _psd_from_mt(x_mt, rt_eig[np.newaxis, :, np.newaxis])
      x_var = trapezoid(psd_est, dx=np.pi / n_freqs) / (2 * np.pi)
      del psd_est
  
      # allocate space for output
      psd = np.empty((n_signals, np.sum(freq_mask)))
  
      # only keep the frequencies of interest
      x_mt = x_mt[:, :, freq_mask]
  
      if return_weights:
          weights = np.empty((n_signals, n_tapers, psd.shape[1]))
  
      for i, (xk, var) in enumerate(zip(x_mt, x_var)):
          # combine the SDFs in the traditional way in order to estimate
          # the variance of the timeseries
  
          # The process is to iteratively switch solving for the following
          # two expressions:
          # (1) Adaptive Multitaper SDF:
          # S^{mt}(f) = [ sum |d_k(f)|^2 S_k(f) ]/ sum |d_k(f)|^2
          #
          # (2) Weights
          # d_k(f) = [sqrt(lam_k) S^{mt}(f)] / [lam_k S^{mt}(f) + E{B_k(f)}]
          #
          # Where lam_k are the eigenvalues corresponding to the DPSS tapers,
          # and the expected value of the broadband bias function
          # E{B_k(f)} is replaced by its full-band integration
          # (1/2pi) int_{-pi}^{pi} E{B_k(f)} = sig^2(1-lam_k)
  
          # start with an estimate from incomplete data--the first 2 tapers
          psd_iter = _psd_from_mt(xk[:2, :], rt_eig[:2, np.newaxis])
  
          err = np.zeros_like(xk)
          for n in range(max_iter):
              d_k = psd_iter / (
                  eigvals[:, np.newaxis] * psd_iter
                  + (1 - eigvals[:, np.newaxis]) * var
              )
              d_k *= rt_eig[:, np.newaxis]
              # Test for convergence -- this is overly conservative, since
              # iteration only stops when all frequencies have converged.
              # A better approach is to iterate separately for each freq, but
              # that is a nonvectorized algorithm.
              # Take the RMS difference in weights from the previous iterate
              # across frequencies. If the maximum RMS error across freqs is
              # less than 1e-10, then we're converged
              err -= d_k
              if np.max(np.mean(err**2, axis=0)) < 1e-10:
                  break
  
              # update the iterative estimate with this d_k
              psd_iter = _psd_from_mt(xk, d_k)
              err = d_k
  
          if n == max_iter - 1:
              warn(
                  "Iterative multi-taper PSD computation did not converge."
              )
  
          psd[i, :] = psd_iter
  
          if return_weights:
              weights[i, :, :] = d_k
  
      if return_weights:
          return psd, weights
      else:
          return psd
  
file_path: mne-python/mne/time_frequency/multitaper.py
imports: import numpy
  from scipy.fft import rfft, rfftfreq
  from scipy.integrate import trapezoid
  from scipy.signal import get_window
  from scipy.signal.windows import dpss
  from ..parallel import parallel_func
  from ..utils import _check_option, logger, verbose, warn
label_desc: Use image node_id 2 for calling a global function with example usage: _psd_from_mt_adaptive(x_mt, eigvals, freq_mask, max_iter, return_weights) and returns: psd,  weights, psd