code: def compute_chpi_locs(
      info,
      chpi_amplitudes,
      t_step_max=1.0,
      too_close="raise",
      adjust_dig=False,
      verbose=None,
  ):
      """Compute locations of each cHPI coils over time.
  
      Parameters
      ----------
      %(info_not_none)s
      %(chpi_amplitudes)s
          Typically obtained by :func:`mne.chpi.compute_chpi_amplitudes`.
      t_step_max : float
          Maximum time step to use.
      too_close : str
          How to handle HPI positions too close to the sensors,
          can be ``'raise'`` (default), ``'warning'``, or ``'info'``.
      %(adjust_dig_chpi)s
      %(verbose)s
  
      Returns
      -------
      %(chpi_locs)s
  
      See Also
      --------
      compute_chpi_amplitudes
      compute_head_pos
      read_head_pos
      write_head_pos
      extract_chpi_locs_ctf
  
      Notes
      -----
      This function is designed to take the output of
      :func:`mne.chpi.compute_chpi_amplitudes` and:
  
      1. Get HPI coil locations (as digitized in ``info['dig']``) in head coords.
      2. If the amplitudes are 98%% correlated with last position
         (and Δt < t_step_max), skip fitting.
      3. Fit magnetic dipoles using the amplitudes for each coil frequency.
  
      The number of fitted points ``n_pos`` will depend on the velocity of head
      movements as well as ``t_step_max`` (and ``t_step_min`` from
      :func:`mne.chpi.compute_chpi_amplitudes`).
  
      .. versionadded:: 0.20
      """
      # Set up magnetic dipole fits
      _check_option(
          "too_close", too_close, ["raise", "warning", "info"]
      )
      _check_chpi_param(chpi_amplitudes, "chpi_amplitudes")
      _validate_type(info, Info, "info")
      sin_fits = chpi_amplitudes  # use the old name below
      del chpi_amplitudes
      proj = sin_fits["proj"]
      meg_picks = pick_channels(
          info["ch_names"], proj["data"]["col_names"], ordered=True
      )
      info = pick_info(info, meg_picks)  # makes a copy
      with info._unlock():
          info["projs"] = [proj]
      del meg_picks, proj
      meg_coils = _concatenate_coils(
          _create_meg_coils(info["chs"], "accurate")
      )
  
      # Set up external model for interference suppression
      safe_false = _verbose_safe_false()
      cov = make_ad_hoc_cov(info, verbose=safe_false)
      whitener, _ = compute_whitener(cov, info, verbose=safe_false)
  
      # Make some location guesses (1 cm grid)
      R = np.linalg.norm(meg_coils[0], axis=1).min()
      guesses = _make_guesses(
          dict(R=R, r0=np.zeros(3)),
          0.01,
          0.0,
          0.005,
          verbose=safe_false,
      )[0]["rr"]
      logger.info(
          "Computing %d HPI location guesses (1 cm grid in a %0.1f cm "
          "sphere)" % (len(guesses), R * 100)
      )
      fwd = _magnetic_dipole_field_vec(guesses, meg_coils, too_close)
      fwd = np.dot(fwd, whitener.T)
      fwd.shape = (guesses.shape[0], 3, -1)
      fwd = np.linalg.svd(fwd, full_matrices=False)[2]
      guesses = dict(rr=guesses, whitened_fwd_svd=fwd)
      del fwd, R
  
      iter_ = list(zip(sin_fits["times"], sin_fits["slopes"]))
      chpi_locs = dict(times=[], rrs=[], gofs=[], moments=[])
      # setup last iteration structure
      hpi_dig_dev_rrs = apply_trans(
          invert_transform(info["dev_head_t"])["trans"],
          _get_hpi_initial_fit(info, adjust=adjust_dig),
      )
      last = dict(
          sin_fit=None,
          coil_fit_time=sin_fits["times"][0] - 1,
          coil_dev_rrs=hpi_dig_dev_rrs,
      )
      n_hpi = len(hpi_dig_dev_rrs)
      del hpi_dig_dev_rrs
      for fit_time, sin_fit in ProgressBar(
          iter_, mesg="cHPI locations "
      ):
          # skip this window if bad
          if not np.isfinite(sin_fit).all():
              continue
  
          # check if data has sufficiently changed
          if last["sin_fit"] is not None:  # first iteration
              corrs = np.array(
                  [
                      np.corrcoef(s, lst)[0, 1]
                      for s, lst in zip(sin_fit, last["sin_fit"])
                  ]
              )
              corrs *= corrs
              # check to see if we need to continue
              if (
                  fit_time - last["coil_fit_time"] <= t_step_max - 1e-7
                  and (corrs > 0.98).sum() >= 3
              ):
                  # don't need to refit data
                  continue
  
          # update 'last' sin_fit *before* inplace sign mult
          last["sin_fit"] = sin_fit.copy()
  
          #
          # 2. Fit magnetic dipole for each coil to obtain coil positions
          #    in device coordinates
          #
          coil_fits = [
              _fit_magnetic_dipole(
                  f, x0, too_close, whitener, meg_coils, guesses
              )
              for f, x0 in zip(sin_fit, last["coil_dev_rrs"])
          ]
          rrs, gofs, moments = zip(*coil_fits)
          chpi_locs["times"].append(fit_time)
          chpi_locs["rrs"].append(rrs)
          chpi_locs["gofs"].append(gofs)
          chpi_locs["moments"].append(moments)
          last["coil_fit_time"] = fit_time
          last["coil_dev_rrs"] = rrs
      n_times = len(chpi_locs["times"])
      shapes = dict(
          times=(n_times,),
          rrs=(n_times, n_hpi, 3),
          gofs=(n_times, n_hpi),
          moments=(n_times, n_hpi, 3),
      )
      for key, val in chpi_locs.items():
          chpi_locs[key] = np.array(val, float).reshape(shapes[key])
      return chpi_locs
  
imports: import copy
  import itertools
  from functools import partial
  import numpy
  from scipy.linalg import orth
  from scipy.optimize import fmin_cobyla
  from scipy.spatial.distance import cdist
  from ._fiff.constants import FIFF
  from ._fiff.meas_info import Info, _simplify_info
  from ._fiff.pick import _picks_to_idx, pick_channels, pick_channels_regexp, pick_info, pick_types
  from ._fiff.proj import Projection, setup_proj
  from .channels.channels import _get_meg_system
  from .cov import compute_whitener, make_ad_hoc_cov
  from .dipole import _make_guesses
  from .event import find_events
  from .fixes import jit
  from .forward import _concatenate_coils, _create_meg_coils, _magnetic_dipole_field_vec
  from .io import BaseRaw
  from .io.ctf.trans import _make_ctf_coord_trans_set
  from .io.kit.constants import KIT
  from .io.kit.kit import RawKIT
  from .preprocessing.maxwell import _get_mf_picks_fix_mags, _prep_mf_coils, _regularize_out, _sss_basis
  from .transforms import _angle_between_quats, _fit_matched_points, _quat_to_affine, als_ras_trans, apply_trans, invert_transform, quat_to_rot, rot_to_quat
  from .utils import ProgressBar, _check_fname, _check_option, _on_missing, _pl, _validate_type, _verbose_safe_false, logger, use_log_level, verbose, warn
label_desc: Use image node_id 30 for calling a global function with example usage: compute_chpi_locs(info, chpi_amplitudes, t_step_max, too_close, adjust_dig, verbose) and returns: chpi_locs