## Copyright (C) 2019 Jens ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{retval} =} peak_detect (@var{input1}, @var{input2}) ## ## @seealso{} ## @end deftypefn ## Author: Jens ## Created: 2019-05-20 function retval = peak_detect () frames = load ('-ascii', './frames.dat'); [numFrames, N] = size(frames) DO_SIM_PEAKS = 0; Nh = N; kn = 0.1 ks = 0.5; pa = 0.3; d_max = 30; am = 0.04; as = 0.2; Ad = 20; Cm = 0; pb_min = 5 pb_max = 37 s = zeros(1, Nh); a = zeros(1, Nh); Xm = zeros(1, Nh); Xs = zeros(1, Nh); peak_count = zeros(1, Nh); close all; figure for k=1:numFrames % Peak generation if DO_SIM_PEAKS z = fix(Nh*rand() + 1); if (rand() < pa) if (s(z) == 0) a(z) = ks; s(z) = fix(d_max*rand()); end end x = kn*randn(1, N); for n = 1:Nh if s(n) > 0 s(n) = s(n) - 1; f = 0.5-rand() + n; x = x + a(n)*cos(2*pi*f*(0:N-1)/N); end end X = abs(fft(x))/sqrt(N); X = X(1:Nh); X = 10*log10(X.*X); else X = frames(k,:); X = X(1:Nh); end % Init if k == 1 Xm = Xm + mean(X); Xs = Xs + mean(X); endif % ---------------------- % Peak detection % ---------------------- % Update of Xs Xs = (1-as)*Xs + as*X; % Update Xm at no-peak bins Xm = (1-am)*Xm + am*X; % Conditional update of Xm last = Xm(1); for n=2:Nh, if Xm(n) < (last+2) last = (1-am)*last + am*Xm(n); else Xm(n) = last; end end % Create peak distances by subtracting Xm Xd = (X-Xm); % Find peak candidates by thresholding peaks = Xd >= Ad; peak_pos = find(peaks); % Search true maximum peak using hill climbing numPeaksLast = 0; while(1) numPeaks = 0; for pos = peak_pos, while(1) y0 = X(pos); pos_p = min(Nh, pos+1); pos_n = max(1, pos-1); if X(pos_p) > y0 peaks(pos) = 0; peaks(pos_n) = 0; pos = pos_p; elseif X(pos_n) > y0 peaks(pos) = 0; peaks(pos_p) = 0; pos = pos_n; else peaks(pos_n) = 0; peaks(pos_p) = 0; numPeaks = numPeaks + 1; break; end end endfor if numPeaks == numPeaksLast break; end numPeaksLast = numPeaks; end peak_pos = find(peaks); % Sort peaks [v, n] = sort((Xd)(peak_pos), 'descend'); peak_pos_sorted = peak_pos(n); % Construct peak boxes peak_pos = []; peak_boxes_abs = Xm; peak_boxes_rel = zeros(1, Nh); for pos = peak_pos_sorted, % Find peak widths left = pos; right = pos; nom = 10; left_found = 0; right_found = 0; pbh = 0; while(~(left_found & right_found)) % Determine peak width left from center (pos) if Xd(left) > nom if left > 1 left = left - 1; else break; end else left_found = 1; endif % Determine peak width right from center (pos) if Xd(right) > nom if right < Nh right = right + 1; else break; end else right_found = 1; endif pbh_left = pos - left; pbh_right = right - pos; % Take larger peak width pbh = max(pbh_left, pbh_right); % Ensure peak box is at least pb_min pbh = max(pbh, pb_min); if pbh > pb_max pbh = 0; break; end end if pbh == 0 continue; endif % Use peak width for peak box pbox_start = max(1, pos-pbh); pbox_end = min(Nh, pos+pbh); % Find intersection box_height_abs = X(pos); box_height_rel = Xd(pos); does_intersect = 0; for n=pbox_start:pbox_end if peak_boxes_rel(n) > box_height_rel does_intersect = 1; break end endfor if does_intersect == 0 peak_boxes_abs(pbox_start:pbox_end) = box_height_abs * ones(1, pbox_end - pbox_start + 1); peak_boxes_rel(pbox_start:pbox_end) = box_height_rel * ones(1, pbox_end - pbox_start + 1); peak_pos = [peak_pos pos]; end endfor % Output subplot(2, 1, 1) plot(1:Nh, X, peak_pos, X(peak_pos), 'ro', 1:Nh, peak_boxes_abs, 'm-'); grid; axis([0, Nh, -60, 60]); legend('X', 'Peaks', 'Peak Box') subplot(2, 1, 2) plot(1:Nh, Xs-Xm, 1:Nh, Xm); grid; axis([0, Nh, -60, 60]); legend('X_s - Xm', 'X_m') pause(1/30); end endfunction