Help Required With Graph Plotting in MATLAB - matlab

I am about to present my work that I have created in MATLAB, but I am having trouble manipulating my data into a presentable form using the plot function.
My code looks like this:
[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*10e-3); %# 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
Basically I want to plot the energy of the track over time (in seconds).
plot(energy)
nearly does what I require, but I have an unusual amount of blank space at the end of the track which is not present in the .wav file. This blank space is the main issue that I'm having. Ideally I would like the x axis to be displayed in seconds! Any help would be much appreciated.
edit1:
Using the first suggested method:

There's also
axis tight
which sets "tight" limits for the axis. See doc: http://www.mathworks.com/help/techdoc/ref/axis.html

By default, Matlab uses some heuristic rules to choose the limits of graph scales. You can override them with the xlim and ylim functions (e.g. xlim([0 length(energy)])).
If you want to plot against actual time, you can do something like:
t = (0:length(energy)-1) / fs; % Timebase in seconds
plot(t, energy);

Related

Getting frequency response of my microphone

I'm trying to get a frequency response curve from a microphone that I have connected to my pc, using matlab.
I think I'm pretty close of getting the final code, but i think I'm missing something.
This is what I have right now:
close all, clear all, clc
x = 5; % seconds recording
Fs = 44100; % Sampling frequency
T = 1/Fs; % Sample time
L= x*1000; % Length of signal
t = (0:L-1)*T; % Time vector
% Record your voice for 'x' seconds.
recObj = audiorecorder(Fs, 24, 1);
disp('Start of Recording.');
recordblocking(recObj, x);
disp('End of Recording.');
% Store data in double-precision array.
myRecording = getaudiodata(recObj);
NFFT = 2^nextpow2(L); % Next power of 2 from length of y
fourier = fft(myRecording);
Y = fft(myRecording,NFFT)/L;
f = Fs/2*linspace(0,1,NFFT/2+1);
X = 2*abs(Y(1:NFFT/2+1));
samples = get(recObj,'TotalSamples');
plot(f,X)
title('Single-Sided Amplitude Spectrum)
xlabel('Frequency (Hz)')
ylabel('|Y(f)|')
This part of the code is correct I think.
For example, when I play a tone of 5kHz I get this plot:
Now I play pink noise, and add this small part of code to convert it to dB, so I can get the frequency response curve:
dbX = db(X);
plot(f,dbX)
I expect (or my goal is..) a frequency response curve (as you can find on google images for example, I don't have enough reputation for more than 2 links, so sorry I didn't use a picture link here) , but I got this instead:
Clearly I'm doing something wrong, but I don't know what ..
You are closer than you think. Here are three tips to get a little closer.
Firstly, you need a logarithmic plot of your frequency domain data. Use semilogx() instead of plot.
Secondly, you're going to need to smooth the data. The simplest function for this in Matlab is smooth() but there are more advanced options that may better suit your needs.
Finally, in order to get a relative response, subtract the mean from your data. dbx_relative = dbx-mean(dbx)
Putting it all together:
dbX = db(X);
relative_dbx = dbx-mean(dbx);
smoothed_dbx = smooth(relative_dbx);
semilogx(f,smoothed_dbx);
Use pwelch to compute the transfer function between the stimulus signal (i.e. the reference audio waveform ) and the response (what you measure with your microphone).

MATLAB: saving scatter plot takes too long

I'm using scatter function to plot data containing only 25000 rows, however when I use saveas function to save the image as png, it takes 2+ minutes to do so.
For example:
scatter(x,y,'filled');
pic_name = ['scatterplot.png'];
tic
saveas(gcf,pic_name,'png');
toc
Elapsed time is 152.681511 seconds.
Is there a quicker way to save a scatter plot?
scatter is known to be slow for high number of datapoints; that might include saving them (each point has a difference color, thus needs separate handling).
You might want to try plotting the data differently, like described here: matlab: scatter plots with high number of datapoints
This way, you get the same behaviour as with regular plots.
Instead of calling saveas(), you could try calling getframe() and then calling imwrite(), like this:
npoints = 25000;
x = linspace(0,3*pi, npoints);
y = cos(x) + rand(1, npoints);
scatter_series_handle = scatter(x,y,'filled');
pic_name = ['scatterplot.png'];
axes_handle = get(scatter_series_handle, 'Parent');
figure_handle = get(axes_handle, 'Parent');
img = getframe(figure_handle);
imwrite(img.cdata, pic_name, 'png');

Plotting many lines as a heatmap

I have a large number (~1000) of files from a data logger that I am trying to process.
If I wanted to plot the trend from a single one of these log files I could do it using
plot(timevalues,datavalues)
I would like to be able to view all of these lines at same time in a similar way to how an oscilloscope has a "persistant" mode.
I can probably cobble together something that uses histograms but am hoping there is pre-existing or more elegant solution to this problem.
You can do exactly what you are suggesting yourself, i.e. plotting the heatmap of the signals.
Consider the following: I'll build a test signals (out of sine waves of different amplitude), then I'll plot the heatmap via hist3 and imagesc.
The idea is to build an auxiliary signal which is just the juxtaposition of all your time histories (both in x and y), then extract basic bivariate statistics out of that.
% # Test signals
xx = 0 : .01 : 2* pi;
center = 1;
eps_ = .2;
amps = linspace(center - eps_ , center + eps_ , 100 );
% # the auxiliary signal will be stored in the following variables
yy = [];
xx_f = [];
for A = amps
xx_f = [xx_f,xx];
yy = [yy A*sin(xx)];
end
% # final heat map
colormap(hot)
[N,C] = hist3([xx_f' yy'],[100 100]);
imagesc(C{1},C{2},N')
You can use also jet colormap instead of hot colormap for readability.
In the following the amplitude is gaussian instead of homogeneus.
here's a "primitive" solution that is just using hist:
%# generate some fake data
x=-8:0.01:8;
y=10*sinc(x);
yy=bsxfun(#plus,y,0.1*randn(numel(x),1000)' );
yy(randi(1000,1,200),:)= 5-randi(10)+ circshift(yy(randi(1000,1,200),:),[1 randi(numel(x),1,200)]);
%# get plot limit parameters
plot(x,yy)
yl=get(gca,'Ylim');
xl=get(gca,'Xlim');
close all;
%# set 2-d histogram ranges
ybins=100;
xbins=numel(x);
yrange=linspace(yl(1),yl(2),ybins);
xrange=linspace(xl(1),xl(2),xbins);
%# prealocate
m=zeros(numel(yrange),numel(xrange));
% build 2d hist
for n=1:numel(x)
ind=hist(yy(:,n),yrange);
m(:,n)=m(:,n)+ind(:);
end
imagesc(xrange,yrange,m)
set(gca,'Ydir','normal')
Why don't you normalize the data and then add all the lines together? You could then plot the heatmap from the single datafile.

Plotting with a time axis in Matlab using dateTick and dateNumbers

I am making a script to plot burst signal events on a pesudo-waterfall.
With x-axis being frequencyand y-axis being time I plot a line from
[event-frequency event-startTimeStamp] to [event-frequency event-endTimeStamp]
to represent each burst.
I am using the following code:
tstart = datenum(0,0,0,0,0,0);
tend = datenum(0,0,0,0,0,1);
timeInterval=tend-tstart;
xlim([0 10]);
hold on;
cla;
timeAxis = linspace(tstart, tend, 100);
set(gca,'YTick',timeAxis,'FontSize',6,'YDir','reverse');
datetick('y','HH:MM::SS.FFF','keepticks');
plot([1 1],[tstart tstart+timeInterval/4]);
plot([2 2],[tstart+timeInterval/8 tstart+timeInterval/2]);
tstart=tstart + timeInterval;
tend=tend + timeInterval;
The paragraph from the cla can be repeated to plot 'signals' in later time increments of one second. This works fine.
If I change the first two lines to the following: edit: using this value cuz it's the timestamp of the first burst
tstart = datenum(2011,6,13,15,10,40.999);
tend = tstart + datenum(0,0,0,0,0,1);
The plot looks horrible and the labels get messed up into a black mess. I can't work out why it's happening. Anybody know?
(copy-pastable code if you wanna try it out)
-Daniel
Try not showing all the tick marks, instead only a subset of them. Something along the lines:
set(gca,'YTick',timeAxis(1:10:end))
Also read up on DATETICK options: 'keepticks' and 'keeplimits'

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:
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:
and this:
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!
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.
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.