code: def _read_evoked_besa_mul(fname, verbose):
      """Create EvokedArray from a BESA .mul file."""
      with open(fname) as f:
          header = f.readline().strip()
          ch_names = f.readline().strip().split()
  
      fields = _parse_header(header)
      data = np.loadtxt(fname, skiprows=2, ndmin=2)
  
      if len(ch_names) != data.shape[1]:
          raise RuntimeError(
              "Mismatch between the number of channel names "
              f"defined in the .mul file ({len(ch_names)}) "
              "and the number of columns in the data matrix "
              f"({data.shape[1]})."
          )
  
      # Consolidate channel types
      ch_types = _read_elp_sidecar(fname)
      if ch_types is None:
          logger.info("Marking all channels as EEG.")
          ch_types = ["eeg"] * len(ch_names)
      else:
          ch_types = [ch_types[ch] for ch in ch_names]
  
      # Go over all the header fields and make sure they are all defined to
      # something sensible.
      if "TimePoints" in fields:
          fields["TimePoints"] = int(fields["TimePoints"])
          if fields["TimePoints"] != data.shape[0]:
              logger.warn(
                  f"The size of the data matrix ({data.shape}) does not "
                  f'match the "TimePoints" field ({fields["TimePoints"]}).'
              )
      if "Channels" in fields:
          fields["Channels"] = int(fields["Channels"])
          if fields["Channels"] != data.shape[1]:
              logger.warn(
                  f"The size of the data matrix ({data.shape}) does not "
                  f'match the "Channels" field ({fields["Channels"]}).'
              )
      if "SamplingInterval[ms]" in fields:
          fields["SamplingInterval[ms]"] = float(
              fields["SamplingInterval[ms]"]
          )
      else:
          raise RuntimeError(
              'No "SamplingInterval[ms]" field present. Could '
              "not determine sampling frequency."
          )
      if "BeginSweep[ms]" in fields:
          fields["BeginSweep[ms]"] = float(fields["BeginSweep[ms]"])
      else:
          fields["BeginSweep[ms]"] = 0.0
      if "Bins/uV" in fields:
          fields["Bins/uV"] = float(fields["Bins/uV"])
      else:
          fields["Bins/uV"] = 1
      if "SegmentName" not in fields:
          fields["SegmentName"] = ""
  
      # Build the Evoked object based on the header fields.
      info = create_info(
          ch_names,
          sfreq=1000 / fields["SamplingInterval[ms]"],
          ch_types=ch_types,
      )
      return EvokedArray(
          data.T / fields["Bins/uV"] / 1e6,
          info,
          tmin=fields["BeginSweep[ms]"] / 1000,
          comment=fields["SegmentName"],
          verbose=verbose,
      )
  
file_path: mne-python/mne/io/besa/besa.py
imports: from collections import OrderedDict
  from pathlib import Path
  import numpy
  from ..._fiff.meas_info import create_info
  from ...evoked import EvokedArray
  from ...utils import fill_doc, logger, verbose
label_desc: Use image node_id 3 for calling a global function with example usage: _read_evoked_besa_mul(fname, verbose) and returns: EvokedArray