{
  "slug": "peak-detector",
  "name": "gizza-ai/peak-detector",
  "version": "0.1.0",
  "title": "Peak Detector — Find Local Maxima and Minima in a Signal — gizza.ai",
  "description": "Paste a 1-D signal and find its peaks and valleys, with prominence, height, distance and width filters. Free, runs in your browser.",
  "tags": [
    "peak detector",
    "find peaks online",
    "local maxima finder",
    "local minima finder",
    "signal peak finder",
    "prominence peak detection",
    "find peaks in data",
    "valley detector",
    "peak finding tool"
  ],
  "category": "audio",
  "urls": {
    "page": "https://gizza.ai/tools/peak-detector/",
    "markdown": "https://gizza.ai/tools/peak-detector/index.md",
    "descriptor": "https://gizza.ai/tools/peak-detector/tool.json",
    "deep_link_example": "https://gizza.ai/tools/peak-detector/?data=0%2C%201%2C%200%2C%203%2C%200%2C%202%2C%200&mode=maxima&separator=auto&smooth=0&min_value=e.g.%205&max_value=e.g.%20100&threshold=0&min_distance=0&min_prominence=0&min_width=0&rel_height=0.5&max_peaks=0&sort_by=position&format=text"
  },
  "cli": "gizza tool peak-detector \"0, 1, 0, 3, 0, 2, 0\"",
  "tool": {
    "description": "Find the local maxima (peaks) and local minima (valleys) in a pasted 1-D signal and report each one's 0-based index, value, prominence and width. Candidates can be filtered by amplitude band (min_value/max_value), vertical drop to both immediate neighbours (threshold), spacing between peaks (min_distance), prominence (min_prominence) and width (min_width), evaluated in that documented order; an optional moving-average window (smooth) suppresses noise before detection. Flat-topped peaks collapse to the middle sample and the first and last sample are never peaks. Results can be sorted by position, prominence or value and capped with max_peaks. Accepts comma, space, tab, newline, semicolon or pipe separated values, decimals, negatives and scientific notation, up to 20000 samples. Text, JSON or CSV output. Report-only — it never changes the data.",
    "parameters": {
      "additionalProperties": false,
      "properties": {
        "data": {
          "description": "The 1-D signal to analyse, as pasted text: one number per sample, in order. Values may be separated by commas, spaces, tabs, newlines, semicolons or pipes (see separator) — for example `0, 1, 0, 3, 0, 2, 0`. Integers, decimals, negatives and scientific notation (`1e6`) are all accepted; non-numeric tokens such as a pasted column header are skipped and counted. Up to 20000 samples per run. Indices in the report are 0-based, so the first sample is index 0.",
          "type": "string"
        },
        "format": {
          "default": "text",
          "description": "Output format. `text` (default) is the readable report: a peak table plus the highest peak, deepest valley, mean spacing, signal statistics and the filters in force. `json` returns the full report object, including each peak's bases and interpolated width endpoints. `csv` returns just the peak table with a header row, ready to paste into a spreadsheet.",
          "enum": [
            "text",
            "json",
            "csv"
          ],
          "type": "string"
        },
        "max_peaks": {
          "default": 0,
          "description": "Report at most this many peaks, applied AFTER sorting, so with `sort_by=prominence` it gives you the N most significant peaks. 0 (default) reports every peak that passed the filters. The report always states how many peaks matched in total, so you can see what was withheld.",
          "maximum": 10000,
          "minimum": 0,
          "type": "integer"
        },
        "max_value": {
          "default": "",
          "description": "Amplitude ceiling: ignore any extremum whose value is above this number. Blank (default) means no ceiling. Combined with min_value it forms a band, so you can isolate mid-height features and drop a saturating spike — for example `min_value=5` with `max_value=7`. min_value above max_value is rejected, since no value could pass.",
          "type": "string"
        },
        "min_distance": {
          "default": 0,
          "description": "Minimum spacing, in samples, between reported peaks of the same kind. 0 (default) turns it off. Peaks are kept tallest-first: the most extreme peak survives and every peak closer than this many samples to an already-kept one is dropped. Use it to report one peak per event when a single event produces a cluster of samples above the surroundings.",
          "maximum": 20000,
          "minimum": 0,
          "type": "integer"
        },
        "min_prominence": {
          "default": 0.0,
          "description": "Minimum prominence: how far the signal must fall on BOTH sides of the peak before it rises back above that peak (or reaches an end of the data). 0 (default) turns it off. This is the standard \"is this a real peak or just a bump on the side of a bigger one\" test, and is usually the most effective single filter on noisy data — try a few percent of the signal's range.",
          "minimum": 0,
          "type": "number"
        },
        "min_value": {
          "default": "",
          "description": "Amplitude floor: ignore any extremum whose value is below this number. Blank (default) means no floor. Applied to the value as you see it, so in `minima` mode it still means \"no lower than this\". Use it to skip the baseline wiggle of a signal whose real events all sit above a known level — for example `min_value=5` on a 0-10 signal.",
          "type": "string"
        },
        "min_width": {
          "default": 0.0,
          "description": "Minimum peak width in samples, measured across the peak at rel_height of its prominence with linear interpolation between samples. 0 (default) turns it off. Use it to reject a one-sample spike (width near 1) while keeping broad, genuine features — the complement of min_prominence, which judges height rather than breadth.",
          "minimum": 0,
          "type": "number"
        },
        "mode": {
          "default": "maxima",
          "description": "Which extrema to find. `maxima` (default) reports peaks — samples higher than both neighbours. `minima` reports valleys — samples lower than both neighbours; every measurement (prominence, width) is then the mirror image, measured on the way down. `both` reports peaks and valleys in one table with a `kind` column.",
          "enum": [
            "maxima",
            "minima",
            "both"
          ],
          "type": "string"
        },
        "rel_height": {
          "default": 0.5,
          "description": "Where the width is measured, as a fraction of the peak's prominence, 0-1 (default 0.5 = half prominence, the usual convention and the same reference point as a FWHM measurement). 1 measures right down at the peak's base, giving the widest number; a small value measures just below the tip. It changes the reported `width` and therefore what min_width rejects.",
          "maximum": 1,
          "minimum": 0,
          "type": "number"
        },
        "separator": {
          "default": "auto",
          "description": "How the samples are separated. `auto` (default) splits on any whitespace, comma, semicolon or pipe, which handles most pasted columns and CSV rows. Pick an explicit separator for ambiguous data — for example `newline` for one value per line, or `tab` for a column copied out of a spreadsheet. Blank entries are skipped.",
          "enum": [
            "auto",
            "comma",
            "newline",
            "space",
            "semicolon",
            "tab",
            "pipe"
          ],
          "type": "string"
        },
        "smooth": {
          "default": 0,
          "description": "Moving-average window, in samples, applied BEFORE detection to stop noise registering as peaks. 0 or 1 (default 0) means no smoothing. Must be an odd number so the window stays centred on its sample — try 3, 5 or 7 for lightly noisy data, larger for very noisy data. Reported values are the smoothed ones; the window shrinks at the two ends so no artificial ramp is introduced.",
          "maximum": 501,
          "minimum": 0,
          "type": "integer"
        },
        "sort_by": {
          "default": "position",
          "description": "Row order in the report. `position` (default) keeps the peaks in the order they occur in the signal — best for reading a trace end to end. `prominence` puts the most significant peaks first, and `value` the highest-valued ones; pair either with max_peaks to get a top-N list.",
          "enum": [
            "position",
            "prominence",
            "value"
          ],
          "type": "string"
        },
        "threshold": {
          "default": 0.0,
          "description": "Minimum vertical drop from the peak to BOTH of its immediate neighbours, in the signal's own units. 0 (default) turns the filter off. This is a purely local test — it rejects a peak that barely clears the samples touching it, without looking any further along the signal. Use min_prominence instead when you care how the peak compares to the wider curve.",
          "minimum": 0,
          "type": "number"
        }
      },
      "required": [
        "data"
      ],
      "type": "object"
    }
  }
}