code: def _prepare_forward(
      forward,
      info,
      noise_cov,
      fixed,
      loose,
      rank,
      pca,
      use_cps,
      exp,
      limit_depth_chs,
      combine_xyz,
      allow_fixed_depth,
      limit,
  ):
      """Prepare a gain matrix and noise covariance for localization."""
      # Steps (according to MNE-C, we change the order of various steps
      # because our I/O is already done, and we create the objects
      # on the fly more easily):
      #
      # 1. Read the bad channels
      # 2. Read the necessary data from the forward solution matrix file
      # 3. Load the projection data
      # 4. Load the sensor noise covariance matrix and attach it to the forward
      # 5. Compose the depth-weighting matrix
      # 6. Compose the source covariance matrix
      # 7. Apply fMRI weighting (not done)
      # 8. Apply the linear projection to the forward solution
      # 9. Apply whitening to the forward computation matrix
      # 10. Exclude the source space points within the labels (not done)
      # 11. Do appropriate source weighting to the forward computation matrix
      #
  
      # make a copy immediately so we do it exactly once
      forward = forward.copy()
  
      # Deal with "fixed" and "loose"
      loose = _triage_loose(forward["src"], loose, fixed)
      del fixed
  
      # Figure out what kind of inverse is requested
      fixed_inverse = all(v == 0.0 for v in loose.values())
      constrained_inverse = any(v < 1.0 for v in loose.values())
  
      # We only support fixed orientations for surface and discrete source
      # spaces, not volume.
      if fixed_inverse and "volume" in loose:
          raise ValueError(
              "Computing inverse solutions for volume source "
              "spaces with fixed orientations is not "
              "supported."
          )
      if loose.get("volume", 1) < 1:
          raise ValueError(
              "Computing inverse solutions with restricted "
              "orientations (loose < 1) is not supported for "
              "volume source spaces."
          )
  
      # Deal with "depth"
      if exp is not None:
          exp = float(exp)
          if exp < 0:
              raise ValueError(
                  "depth exponent should be greater than or "
                  f"equal to 0, got {exp}"
              )
          exp = exp or None  # alias 0. -> None
  
      # Put the forward solution in correct orientation.
      # (delaying for the case of fixed ori with depth weighting if
      # allow_fixed_depth is True)
      if fixed_inverse:
          if not is_fixed_orient(forward):
              if allow_fixed_depth:
                  # can convert now
                  logger.info(
                      "Converting forward solution to fixed orientation"
                  )
                  convert_forward_solution(
                      forward,
                      force_fixed=True,
                      use_cps=True,
                      copy=False,
                  )
          elif exp is not None and not allow_fixed_depth:
              raise ValueError(
                  "For a fixed orientation inverse solution with depth "
                  "weighting, the forward solution must be free-orientation and "
                  "in surface orientation"
              )
      else:  # loose or free ori
          if is_fixed_orient(forward):
              raise ValueError(
                  "Forward operator has fixed orientation and can only "
                  "be used to make a fixed-orientation inverse "
                  "operator."
              )
          if constrained_inverse and not forward["surf_ori"]:
              logger.info(
                  "Converting forward solution to surface orientation"
              )
              convert_forward_solution(
                  forward, surf_ori=True, use_cps=use_cps, copy=False
              )
  
      forward, info_picked = _select_orient_forward(
          forward, info, noise_cov, copy=False
      )
      logger.info(
          "Selected %d channels"
          % (
              len(
                  info_picked["ch_names"],
              )
          )
      )
  
      if exp is None:
          depth_prior = None
      else:
          depth_prior = compute_depth_prior(
              forward,
              info_picked,
              exp=exp,
              limit_depth_chs=limit_depth_chs,
              combine_xyz=combine_xyz,
              limit=limit,
              noise_cov=noise_cov,
              rank=rank,
          )
  
      # Deal with fixed orientation forward / inverse
      if fixed_inverse:
          orient_prior = None
          if not is_fixed_orient(forward):
              if depth_prior is not None:
                  # Convert the depth prior into a fixed-orientation one
                  logger.info(
                      "    Picked elements from a free-orientation "
                      "depth-weighting prior into the fixed-orientation "
                      "one"
                  )
                  depth_prior = depth_prior[2::3]
              convert_forward_solution(
                  forward,
                  surf_ori=True,
                  force_fixed=True,
                  use_cps=use_cps,
                  copy=False,
              )
      else:  # Free or loose orientation
          if constrained_inverse:
              assert forward["surf_ori"]
          # In theory we could have orient_prior=None for loose=1., but
          # the MNE-C code does not do this
          orient_prior = compute_orient_prior(forward, loose=loose)
  
      logger.info("Whitening the forward solution.")
      noise_cov = prepare_noise_cov(
          noise_cov, info, info_picked["ch_names"], rank
      )
      whitener, _ = compute_whitener(
          noise_cov,
          info,
          info_picked["ch_names"],
          pca=pca,
          rank=rank,
          verbose=_verbose_safe_false(),
      )
      gain = np.dot(whitener, forward["sol"]["data"])
  
      logger.info("Creating the source covariance matrix")
      source_std = np.ones(gain.shape[1], dtype=gain.dtype)
      if depth_prior is not None:
          source_std *= depth_prior
      if orient_prior is not None:
          source_std *= orient_prior
      np.sqrt(source_std, out=source_std)
      gain *= source_std
      # Adjusting Source Covariance matrix to make trace of G*R*G' equal
      # to number of sensors.
      logger.info("Adjusting source covariance matrix.")
      trace_GRGT = np.linalg.norm(gain, ord="fro") ** 2
      n_nzero = (noise_cov["eig"] > 0).sum()
      scale = np.sqrt(n_nzero / trace_GRGT)
      source_std *= scale
      gain *= scale
  
      return (
          forward,
          info_picked,
          gain,
          depth_prior,
          orient_prior,
          source_std,
          trace_GRGT,
          noise_cov,
          whitener,
      )
  
imports: from copy import deepcopy
  from math import sqrt
  import numpy
  from scipy import linalg
  from scipy.stats import chi2
  from .._fiff.constants import FIFF
  from .._fiff.matrix import _read_named_matrix, _transpose_named_matrix, write_named_matrix
  from .._fiff.open import fiff_open
  from .._fiff.pick import channel_type, pick_channels, pick_info, pick_types
  from .._fiff.proj import _electrode_types, _needs_eeg_average_ref_proj, _read_proj, _write_proj, make_projector
  from .._fiff.tag import find_tag
  from .._fiff.tree import dir_tree_find
  from .._fiff.write import end_block, start_and_end_file, start_block, write_coord_trans, write_float, write_float_matrix, write_int, write_string
  from ..cov import Covariance, _read_cov, _write_cov, compute_whitener, prepare_noise_cov
  from ..epochs import BaseEpochs, EpochsArray
  from ..evoked import Evoked, EvokedArray
  from ..fixes import _safe_svd
  from ..forward import _read_forward_meas_info, _select_orient_forward, compute_depth_prior, compute_orient_prior, convert_forward_solution, is_fixed_orient
  from ..forward.forward import _triage_loose, write_forward_meas_info
  from ..html_templates import _get_html_template
  from ..io import BaseRaw
  from ..source_estimate import _get_src_type, _make_stc
  from ..source_space._source_space import _get_src_nn, _get_vertno, _read_source_spaces_from_tree, _write_source_spaces_to_fid, find_source_space_hemi, label_src_vertno_sel
  from ..surface import _normal_orth
  from ..time_frequency.tfr import _check_tfr_complex
  from ..transforms import _ensure_trans, transform_surface_to
  from ..utils import _check_compensation_grade, _check_depth, _check_fname, _check_option, _check_src_normal, _validate_type, _verbose_safe_false, check_fname, logger, repr_html, verbose, warn
  from ._eloreta import _compute_eloreta
label_desc: Use image node_id 22 for calling a global function with example usage: _prepare_forward(forward, info, noise_cov, fixed, loose, rank, pca, use_cps, exp, limit_depth_chs, combine_xyz, allow_fixed_depth, limit) and returns: forward,  info_picked,  gain,  depth_prior,  orient_prior,  source_std,  trace_GRGT,  noise_cov,  whitener