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.
| Code | Input | Output | Description |
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 yet | Shares 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}")
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.