Thursday, April 28, 2011

How to extract specific values from auto-correlated data in MATLAB?

I have been working on extracting the peak values from a graph (see previous question) which looks like this:

alt text

but I have noticed that for some of the xcorr graphs I have been working on the values do not turn out as expected and they normally turn out looking more like this:

alt text

and this:

alt text

Instead of trying to pick the peak values like the code was doing in the first figure, how would I go about trying to pick the values where the downward slope momentarily evens itself out (as shown in Figure 3)?

When I try and run the code in its current state on data like the ones shown in Figure 2 & 3, I do not get any useful data back in return.

I think I need an if statement or similar in the 'find extrema points' section but I'm not sure whether that is correct or not. My .M code for the function looks like this so far:

[inputname, pathname] = uigetfile('*.wav', 'Select WAV-file');

thumb1 = inputname;               %# Get filename information
fprintf('\n%s is being turned into a 30s thumbnail...\n', thumb1);
fprintf('Please wait..!\n\n');
%# load the signal
[y, fs, nb] = wavread(thumb1);
y = mean(y,2);                               %# stereo, take avrg of 2 channels

%# Calculate frame energy
fWidth = round(fs*1);                    %# 10ms
numFrames = floor(length(y)/fWidth);
energy = zeros(1,numFrames);
for f=1:numFrames
  energy(f) = sum( y((f-1)*fWidth+1:f*fWidth).^2 );
end

%# smooth the signal (moving average with window size = 1% * length of data)
WINDOW_SIZE = round(length(energy) * 0.01);  %# 200
XX = filtfilt(ones(1,WINDOW_SIZE)/WINDOW_SIZE, 1, energy);

%# auto-correlation
[r,lags] = xcorr(XX, 'biased');

%# find extrema points
dr = diff(r);
eIdx = find(dr(1:end-1) .* dr(2:end) <= 0) + 1;

[~,loc] = sort(r(eIdx), 'descend');
loc = loc(1:min(3,end));                     %# take the highest 3 values

inf=lags( eIdx(loc) );

thumb=max(inf);

startrecord=round((thumb/1)*fs);
endrecord=round(((thumb+30)/1)*fs);

wavwrite(y(startrecord:endrecord), fs, nb, 'Temp1');
fprintf('The thumbnail of %s has been created.\n\n', thumb1);

Sorry that it all looks so messy, but I wanted to get some visual examples in!

From stackoverflow
  • Those are inflexion points, and if you take the first derivative of your data you will see those as big deviations from a pretty constant slope.

    Play with a boxcar average to do minimal smoothing and with the first derivative to find those inflexion points.

    Mark Spivey : Seeing as how there is already smoothing applied to the signal, I assume I should only be working on finding the first derivative? I've done a bit of looking around, but to be honest I'm not great at maths so a lot of what is being said is going straight over my head. I think I should be trying to use the gradient function to find the values though? Is that along the right lines?
    Marco : I am not familiar with mathlab. Try the gradient function on the data to see what it looks like. The inflection points will look like maxima/minima. The function should be flattish and positive before the peak, then cross the x-axis and be flattish and negative afterward.
  • I believe that it will be easier to find peaks in the negative value of the second derivative. Constant or nearly constant slope will result in 2nd-der =0; anything else, including your actual peaks and inflection points, will have a non-zero 2nd-der. By finding peaks in the negative values, you'll only get the positive peaks, not the negative peaks.

0 comments:

Post a Comment