Qu

findpeaks

Builtin index · Signal processing

findpeaks(x, [min_peak_height=], [min_peak_distance=])

Input: x, min_peak_height, min_peak_distance · Output: no output

What it is

x is a length-N vector; min_peak_height/min_peak_distance (optional numbers) as above. MATLAB-style [peaks, locations] = findpeaks(x, ...). Qu has no multi-return/tuple-unpacking assignment, so this returns a Model (kind "findpeaks") with fields peaks (a vector of the peak values), locations (a vector of their 0-indexed integer indices into x — not MATLAB's 1-indexing), prominences (a vector, one per peak, the real prominence value) and widths (a vector, one per peak, the width in samples at rel_height=0.5) — the same named-field convention qr/lu/svd/eig use. Shares its peak-finding/non-max-suppression logic with find_peaks above.

Overloads

One call shape — this function is not overloaded.

CodeInputOutputDescription
findpeaks(x, [min_peak_height=], [min_peak_distance=])
x vectorx is a length-N vector.
min_peak_height number, optionalmin_peak_height/min_peak_distance (optional numbers) as above.
min_peak_distance number, optionalmin_peak_height/min_peak_distance (optional numbers) as above.
not documented yetShares its peak-finding/non-max-suppression logic with find_peaks above.

Examples

From the documentation, and run by the build -- the output and the figure below are what the engine actually produced. Simplest first.

M = [4, 3; 6, 3]
res = qr(M)
print(res)
print("q = {res.q}")
print("r = {res.r}")

x = [0, 1, 3, 1, 0, 2, 4, 2, 0]
pk = findpeaks(x)
print(pk)
print("peaks = {pk.peaks}")
print("locations = {pk.locations}")
output
model(qr) {q = [0.5547, 0.83205; 0.83205, -0.5547], r = [7.211103, 4.160251; 0, 0.83205]}
q = [0.5547, 0.83205; 0.83205, -0.5547]
r = [7.211103, 4.160251; 0, 0.83205]
model(findpeaks) {peaks = [3, 4], locations = [2, 6], prominences = [3, 4], widths = [1.5, 2]}
peaks = [3, 4]
locations = [2, 6]

from tour

N = 512
Fs = 512
t = (0 to N - 1) / Fs
x = sin(2*pi*40*t) + 0.6*sin(2*pi*90*t)

X = fft(x)
mag = abs(X)
half = mag[0:N/2]

pk = findpeaks(half, min_peak_height=20, min_peak_distance=5)
print(pk)
freqs = pk.locations * (Fs / N)
print("Peak bin locations: {pk.locations}")
print("Peak frequencies (Hz): {freqs}")

from tour

function summarize(m: model<"qr">)
    return "qr: q is {rows(m.q)}x{cols(m.q)}, r is {rows(m.r)}x{cols(m.r)}"
end function

function summarize(m: model<"svd">)
    return "svd: singular values = {m.s}"
end function

function summarize(m: model)
    return "generic model, kind unhandled"
end function

A = [4, 3; 6, 3]
qres = qr(A)
sres = svd(A)
pk = findpeaks([0,1,3,1,0,2,4,2,0])

print(summarize(qres))
print(summarize(sres))
print(summarize(pk))

from tour

How it works

findpeaks(x, [min_peak_height=], [min_peak_distance=]) — MATLAB-style [peaks, locations] = findpeaks(x, ...). Qu has no multi-return/tuple-unpacking assignment (see the argmin/argmax/median/... doc comment history), so this returns a Value::Model instead, the same named-field multi-return convention qr/lu/svd/eig already use: kind "findpeaks", fields peaks (the values) and locations (their 0-indexed positions in x — Qu is 0-indexed everywhere, unlike MATLAB's 1-indexing, so there is deliberately no +1 offset here). Shares its actual peak- finding/non-max-suppression logic with find_peaks above (numeric::transforms::find_peaks) rather than a second implementation; min_prominence isn't exposed as a FILTER here since MATLAB's own findpeaks kwarg vocabulary this is modeled on is MinPeakHeight/MinPeakDistance, not prominence. Two more fields, prominences and widths (each one value per located peak, same order as peaks/ locations), are computed unconditionally via numeric::transforms::peak_prominence/peak_width (the real SciPy-style bounding-minima/interpolated-crossing algorithms, width at rel_height=0.5, "full width at half prominence") — this is the enriched alternative to find_peaks above for scripts that want the VALUES, not just filters on them.

From the note above this builtin in the interpreter, where the reasoning was written down as it was built.