name: "ECG R-Peak Detector"
category: "DSP & Numerical Algorithms"
complexity: "Medium"
description: |
  Implement a synchronous detector that identifies R-peak events from a
  stream of preprocessed ECG amplitude samples.

  Each rising edge of `clk` samples one unsigned 12-bit value on
  `sample_in`. The input stream is already preprocessed; higher values
  correspond to stronger candidate peaks. The module must examine a
  5-sample window and emit a one-cycle `peak_out` pulse only for samples
  that satisfy the rules below.

  PEAK RULE:
  - Let x[n] be the sample captured on cycle n after reset is deasserted.
  - Let t[n] be the value of `threshold` captured on that same cycle n.
  - A sample x[n] is a candidate peak only when all of the following are
    true:
      - x[n] is greater than or equal to t[n]
      - x[n] is strictly greater than x[n-2], x[n-1], x[n+1], and x[n+2]
  - Plateaus are therefore not peaks. If any compared neighbour has the
    same value as x[n], the candidate must be rejected.

  OUTPUT TIMING:
  - Because the decision for x[n] depends on x[n+1] and x[n+2], the module
    cannot decide immediately.
  - When the sample captured in cycle n is accepted as an R-peak,
    `peak_out` must be high for exactly one cycle on cycle n+2.
  - In every other cycle, `peak_out` must be low.
  - The first four sampled cycles after reset deassertion can never produce
    `peak_out`, because a full 5-sample window is not yet available.

  REFRACTORY RULE:
  - Accepted R-peaks must be separated by at least 50 sample intervals.
  - If x[p] is the most recent accepted peak sample, then a later candidate
    x[n] may be accepted only when n - p >= 50.
  - Any candidate with 1 <= n - p <= 49 must be rejected, even if it
    satisfies the amplitude and local-maximum conditions.
  - The refractory rule is defined using the sample indices of the accepted
    center samples, not the later `peak_out` pulse cycles.

  RESET:
  - `rst` is synchronous and active-high.
  - While `rst` is high, clear all sample history and refractory state, and
    drive `peak_out` low.
  - After reset is deasserted, detection restarts from an empty history.

interface:
  module_name: "ecg_r_peak_detector"
  clocked: true
  ports:
    - name: "clk"
      type: "input"
      width: "1"
      description: "System clock; one ECG sample is processed per cycle"
    - name: "rst"
      type: "input"
      width: "1"
      description: "Synchronous active-high reset"
    - name: "sample_in"
      type: "input"
      width: "12"
      description: "Unsigned preprocessed ECG amplitude sample"
    - name: "threshold"
      type: "input"
      width: "12"
      description: "Unsigned minimum amplitude required for an accepted peak"
    - name: "peak_out"
      type: "output"
      width: "1"
      description: "One-cycle pulse asserted when the sample from two cycles earlier is accepted as an R-peak"

target_platform:
  device_family: "AMD Xilinx Zynq-7000"

tasks:
  - name: "Area-Efficient ECG R-Peak Detector"
    constraints:
      max_lut: 110
      max_ff: 96
      max_bram: 0
      max_dsp: 0
      min_frequency: 180
    objective:
      goal: "minimise"
      target: "LUT"
