code: def coherence(
      X,
      window=128,
      overlap=0.75,
      fmin=None,
      fmax=None,
      fs=None,
      coh="ordinary",
  ):
      """Compute squared coherence.
  
      Parameters
      ----------
      X : ndarray, shape (n_channels, n_times)
          Multi-channel time-series, real-valued.
      window : int, default=128
          The length of the FFT window used for spectral estimation.
      overlap : float, default=0.75
          The percentage of overlap between window.
      fmin : float | None, default=None
          The minimal frequency to be returned.
      fmax : float | None, default=None
          The maximal frequency to be returned.
      fs : float | None, default=None
          The sampling frequency of the signal.
      coh : {'ordinary', 'instantaneous', 'lagged', 'imaginary'}, \
              default='ordinary'
          The coherence type, see :class:`pyriemann.estimation.Coherences`.
  
      Returns
      -------
      C : ndarray, shape (n_channels, n_channels, n_freqs)
          Squared coherence matrices, for each frequency bin.
      freqs : ndarray, shape (n_freqs,)
          The frequencies associated to coherence.
      """
      S, freqs = cross_spectrum(
          X, window=window, overlap=overlap, fmin=fmin, fmax=fmax, fs=fs
      )
      S2 = np.abs(S) ** 2  # squared cross-spectral modulus
  
      C = np.zeros_like(S2)
      f_inds = np.arange(0, C.shape[-1], dtype=int)
  
      # lagged coh not defined for DC and Nyquist bins, because S is real
      if coh == "lagged":
          if freqs is None:
              f_inds = np.arange(1, C.shape[-1] - 1, dtype=int)
              warnings.warn(
                  "DC and Nyquist bins are not defined for lagged-"
                  "coherence: filled with zeros"
              )
          else:
              f_inds_ = f_inds[(freqs > 0) & (freqs < fs / 2)]
              if not np.array_equal(f_inds_, f_inds):
                  warnings.warn(
                      "DC and Nyquist bins are not defined for lagged-"
                      "coherence: filled with zeros"
                  )
              f_inds = f_inds_
  
      for f in f_inds:
          psd = np.sqrt(np.diag(S2[..., f]))
          psd_prod = np.outer(psd, psd)
          if coh == "ordinary":
              C[..., f] = S2[..., f] / psd_prod
          elif coh == "instantaneous":
              C[..., f] = (S[..., f].real) ** 2 / psd_prod
          elif coh == "lagged":
              np.fill_diagonal(
                  S[..., f].real, 0.0
              )  # prevent div by zero on diag
              C[..., f] = (S[..., f].imag) ** 2 / (
                  psd_prod - (S[..., f].real) ** 2
              )
          elif coh == "imaginary":
              C[..., f] = (S[..., f].imag) ** 2 / psd_prod
          else:
              raise ValueError(f"{coh} is not a supported coherence")
  
      return C, freqs
  
imports: import warnings
  from functools import wraps
  import numpy
  from scipy.linalg import block_diag
  from scipy.stats import chi2
  from sklearn.covariance import oas, ledoit_wolf, fast_mcd
  from .distance import distance_mahalanobis
  from .test import is_square, is_real_type
label_desc: Use image node_id 19 for calling a global function with example usage: coherence(X, window, overlap, fmin, fmax, fs, coh) and returns: C,  freqs