code: def find_ecg_events(
      raw,
      event_id=999,
      ch_name=None,
      tstart=0.0,
      l_freq=5,
      h_freq=35,
      qrs_threshold="auto",
      filter_length="10s",
      return_ecg=False,
      reject_by_annotation=True,
      verbose=None,
  ):
      """Find ECG events by localizing the R wave peaks.
  
      Parameters
      ----------
      raw : instance of Raw
          The raw data.
      %(event_id_ecg)s
      %(ch_name_ecg)s
      %(tstart_ecg)s
      %(l_freq_ecg_filter)s
      qrs_threshold : float | str
          Between 0 and 1. qrs detection threshold. Can also be "auto" to
          automatically choose the threshold that generates a reasonable
          number of heartbeats (40-160 beats / min).
      %(filter_length_ecg)s
      return_ecg : bool
          Return the ECG data. This is especially useful if no ECG channel
          is present in the input data, so one will be synthesized. Defaults to
          ``False``.
      %(reject_by_annotation_all)s
  
          .. versionadded:: 0.18
      %(verbose)s
  
      Returns
      -------
      ecg_events : array
          The events corresponding to the peaks of the R waves.
      ch_ecg : string
          Name of channel used.
      average_pulse : float
          The estimated average pulse. If no ECG events could be found, this will
          be zero.
      ecg : array | None
          The ECG data of the synthesized ECG channel, if any. This will only
          be returned if ``return_ecg=True`` was passed.
  
      See Also
      --------
      create_ecg_epochs
      compute_proj_ecg
      """
      skip_by_annotation = (
          ("edge", "bad") if reject_by_annotation else ()
      )
      del reject_by_annotation
      idx_ecg = _get_ecg_channel_index(ch_name, raw)
      if idx_ecg is not None:
          logger.info(
              "Using channel %s to identify heart beats."
              % raw.ch_names[idx_ecg]
          )
          ecg = raw.get_data(picks=idx_ecg)
      else:
          ecg, _ = _make_ecg(raw, start=None, stop=None)
      assert ecg.ndim == 2 and ecg.shape[0] == 1
      ecg = ecg[0]
      # Deal with filtering the same way we do in raw, i.e. filter each good
      # segment
      onsets, ends = _annotations_starts_stops(
          raw, skip_by_annotation, "reject_by_annotation", invert=True
      )
      ecgs = list()
      max_idx = (ends - onsets).argmax()
      for si, (start, stop) in enumerate(zip(onsets, ends)):
          # Only output filter params once (for info level), and only warn
          # once about the length criterion (longest segment is too short)
          use_verbose = verbose if si == max_idx else "error"
          ecgs.append(
              filter_data(
                  ecg[start:stop],
                  raw.info["sfreq"],
                  l_freq,
                  h_freq,
                  [0],
                  filter_length,
                  0.5,
                  0.5,
                  1,
                  "fir",
                  None,
                  copy=False,
                  phase="zero-double",
                  fir_window="hann",
                  fir_design="firwin2",
                  verbose=use_verbose,
              )
          )
      ecg = np.concatenate(ecgs)
  
      # detecting QRS and generating events. Since not user-controlled, don't
      # output filter params here (hardcode verbose=False)
      ecg_events = qrs_detector(
          raw.info["sfreq"],
          ecg,
          tstart=tstart,
          thresh_value=qrs_threshold,
          l_freq=None,
          h_freq=None,
          verbose=False,
      )
  
      # map ECG events back to original times
      remap = np.empty(len(ecg), int)
      offset = 0
      for start, stop in zip(onsets, ends):
          this_len = stop - start
          assert this_len >= 0
          remap[offset : offset + this_len] = np.arange(start, stop)
          offset += this_len
      assert offset == len(ecg)
  
      if ecg_events.size > 0:
          ecg_events = remap[ecg_events]
      else:
          ecg_events = np.array([])
  
      n_events = len(ecg_events)
      duration_sec = len(ecg) / raw.info["sfreq"] - tstart
      duration_min = duration_sec / 60.0
      average_pulse = n_events / duration_min
      logger.info(
          "Number of ECG events detected : %d (average pulse %d / "
          "min.)" % (n_events, average_pulse)
      )
  
      ecg_events = np.array(
          [
              ecg_events + raw.first_samp,
              np.zeros(n_events, int),
              event_id * np.ones(n_events, int),
          ]
      ).T
      out = (ecg_events, idx_ecg, average_pulse)
      ecg = ecg[np.newaxis]  # backward compat output 2D
      if return_ecg:
          out += (ecg,)
      return out
  
file_path: mne-python/mne/preprocessing/ecg.py
imports: import numpy
  from .._fiff.meas_info import create_info
  from .._fiff.pick import _picks_to_idx, pick_channels, pick_types
  from ..annotations import _annotations_starts_stops
  from ..epochs import BaseEpochs, Epochs
  from ..evoked import Evoked
  from ..filter import filter_data
  from ..io import BaseRaw, RawArray
  from ..utils import int_like, logger, sum_squared, verbose, warn
label_desc: Use image node_id 2 for calling a global function with example usage: find_ecg_events(raw, event_id, ch_name, tstart, l_freq, h_freq, qrs_threshold, filter_length, return_ecg, reject_by_annotation, verbose) and returns: out