git-svn-id: http://moon:8086/svn/software/trunk/projects/GnuRadio@466 b431acfa-c32f-4a4a-93f1-934dc6c82436
237 lines
4.6 KiB
Matlab
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 = 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
|