Files
GnuRadio/matlab/peak_detect.m
T
jens 1d18b02c6e - fixed messed up peak_box_abs
- refactored var names

git-svn-id: http://moon:8086/svn/software/trunk/projects/GnuRadio@457 b431acfa-c32f-4a4a-93f1-934dc6c82436
2019-05-24 21:10:13 +00:00

237 lines
4.6 KiB
Matlab

## 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
## <https://www.gnu.org/licenses/>.
## -*- texinfo -*-
## @deftypefn {} {@var{retval} =} peak_detect (@var{input1}, @var{input2})
##
## @seealso{}
## @end deftypefn
## Author: Jens <jens@orion>
## 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 = Xd(pos) - 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