I am new to working with time series in Matlab and am struggling with getting this going. I have time series heat-transfer data (over a period of 20ms in steps of 1 microsecond) at these 11 locations (see code below). I am clueless as to how I could put them together to be able to generate a plot at each time step and use getframe at each timestep to make an animation. Any help on how to get started with this would be much appreciated. Here is a link to the 11 data files, providing time on column1 and heat transfer on column2: https://drive.google.com/open?id=1oDAdapqvL-blecb7BOLzxpeiJBsqLd59
Please feel free to suggest any other tools (matplotlib/plotly etc.) that may be better in this scenario as well. Thanks a ton!
close all
clear all
x1=399.5
x2=400.5
y0=0
y1=4
y2=8
y3=12
y4=16
y5=20
y6=-4
y7=-8
y8=-12
y9=-16
y10=-20
%The gauge locations for the first row will be [x1,y1], [x1,y3], [x1,y5], [x1,y6], [x1,y8],
%[x1,y10]
%The gauge locations for the second row will be [x2,y0], [x2,y2], [x2,y4], [x2,y7],
%[x2,y9]
figure
plot(x1,y1,'r.', x1,y3,'r.', x1, y5, 'r.', x1, y6, 'r.', x1, y8, 'r.', x1, y10, 'r.')
hold
plot(x2,y0,'b.', x2,y2,'b.', x2, y4, 'b.', x2, y7, 'b.', x2, y9, 'b.')
axis([390 410 -30 30])
In Matlab you can use, as you said the getFrame and writeVideo functions. Ill explain it for a very general case, which you can then apply to yours.
Let's say we have a plot that changes it's data at every iteration inside a for loop (happens frequently when solving PDEs and so on) with an exemplary function solverIteration (made up...). We are plotting a vector y over our domain x.
In order to record the video we have to do the following:
video = VideoWriter('myVideo.avi'); %Create a video object
open(video); % Open video source - restricts the use of video for your program
for m=1:K
y = solverIteration(y);
plot(x,y);
drawnow;
vidFrame = getframe(gcf);
% instead of gcf you can specify which figure you want to capture
clf;
writeVideo(video,vidFrame); % adds frames to the video
end
close(video);
This script is an example for how to record a video. There are several examples and explanations at the official matlab site.
Related
Using MATLAB I apply Matching Pursuit to approximate a signal. My problem is that I struggle to visualize the time-frequency representation of the selected atoms. I'm trying to produce a Wigner plot similar to the following image (source).
I have looked into the Wavelet Toolbox, Signal Processing Toolbox as well as the open source Time-Frequency Toolbox, but I'm possibly just using the wrong parameters, since my experience with signal processing is quite limited.
Example
Using this data my goal is to reproduce the plot from above.
% fit the signal using MP
itermax = 50;
signal = load('signal.txt');
dict = wmpdictionary(length(signal));
[signal_fit, r, coeff, iopt, qual, X] = wmpalg('OMP', signal, dict, ...
'itermax', itermax);
% wigner plot of the simulated signal
tfrwv(signal_fit) % wigner-ville function from time-frequency toolbox
% wigner plot of each atom
atoms = full(dict(:, iopt)) % selected atoms
for i = 1:itermax
tfrwv(atoms(:, i))
end
Unfortunately, none of the resulting plots comes close to the target visualization. Note, that in the example I use tfrwv with standard parameters which I tweak with the GUI that it opens.
I'd greatly appreciate your help.
Update
I think I have now understood that one needs to use Gabor atoms to get blobs with shapes resembling stretched gaussians. Unfortunately, there are no Gabor functions in the predefined dicts of the Signal Processing Toolbox. However, this question helped me in implementing the needed dictionaries, such that I get atoms which look quite similar to the example:
Since my plots come close but are not perfect, there are still two questions open:
Can all of the blobs that we see in the first example be modeled by Gabor atoms alone, or do I need another dictionary of functions?
How can I combine the indidividual imagesc plots into a single visualization?
To answer your second question 'How can I combine the indidividual imagesc plots into a single visualization?'
If you have multiple 2d matrices that you want to superimpose and display using imagesc, I would suggest taking the element-wise maximum.
For example, I generate two 31x31 grids with gaussians with different mean and variance.
function F = generate2dGauss(mu, Sigma)
x1 = -3:.2:3; x2 = -3:.2:3;
[X1,X2] = meshgrid(x1,x2);
F = mvnpdf([X1(:) X2(:)],mu,Sigma);
F = reshape(F,length(x2),length(x1));
end
F1 = generate2dGauss([1 1], [.25 .3; .3 1]);
F2 = generate2dGauss([-1 -1], [.1 .1; .1 1]);
I can plot them with subplots as in your example,
figure;
subplot(1,2,1);
title('Atom 1');
imagesc(F1);
subplot(1,2,2);
title('Atom 2');
imagesc(F2);
Or I can plot the per element maximum of the two grids.
figure;
title('Both Atoms');
imagesc(max(F1, F2));
You can also experiment with element-wise means, sums, etc, but based on the example you give, I think maximum will give you the cleanest looking result.
Possible pros and cons of different functions:
Maximum will work best if your atoms always have zero-valued backgrounds and no negative values. If the background is zero-valued, but the atoms also contain negative values, the negative values may be covered up by the background of other atoms. If your atom's overlap, the higher value will of course dominate.
Mean will make your peaks less high, but may be more intuitive where you have overlap between atoms.
Sum will make overlapping areas larger valued.
If you have non-zero backgrounds, you could also try using logical indexing. You would have to make some decisions about what to do in overlapping areas, but it would make it easy to filter out backgrounds.
Q. How can I combine the indidividual imagesc plots into a single visualization?
A. Use subplot to draw multiple plots, find below sample with 2 by 2 plots in a figure. Change your equations in code
x = linspace(-5,5);
y1 = sin(x);
subplot(2,2,1)
plot(x,y1)
title('First subplot')
y2 = sin(2*x);
subplot(2,2,2)
plot(x,y2)
title('Second subplot')
y3 = sin(4*x);
subplot(2,2,3)
plot(x,y3)
title('Third subplot')
y4 = sin(6*x);
subplot(2,2,4)
plot(x,y4)
title('Fourth subplot')
This is the kind of plot i imagined myself.
https://de.mathworks.com/help/matlab/ref/waterfall.html
Ok, i don't want to explain too much, how my code works. It would take too much time. Just try the second code yourself. Take any small wav-file you can find. When you compile the code, you can see three frequency bands and see that many spectrums are plotted every 30ms. If you have a specifically question concerning my code, how it works, ask me in the comments.
I want every spectrum, at least from one frequency band, to plot it in a 3-dimensional plot. In short, what are the coordinates of the first spectrum and the 2nd, the 3rd, the 4th and so on.
My time segment on which is a fft applied, is 30 ms long. The first point on the x-axis is 30 ms, the next one 60ms and the next one 90ms and so on. What is the y-coordinate from the 30ms? This would be on the frequency axis or the y-axis. The z-axis would be the magnitude out of a frequency component at some point in time (or at a given sliding window frame). How can i do that? How do i write that? I am having big trouble with this matter. And since every explanation is in another language, it makes it much more harder for me.
As you may know, i have an audiofile (music) on which i compute a STFT. I want to visualise it. See the following explanation in my code. Read the comments!
My first idea to do this way, was using the function "mesh" or something similar.
Here is my mesh-code:
X=1:10;
Y=1:15;
Z = [];
% Here i would define the number of time segments
% See the next following code, to understand, what i mean.
for i = 1:length(X)
% Here in this line, i want to compute my short fft
%
% number of frequencies
for j = 1: length(Y)
Z(j,i) = 1.0/(i*j);
end
end
mesh(X,Y,Z)
This code plots me a mesh, i just wanted to know for myself, how this works. Anyway please be aware, that i am quite sure that i do not know, how the function "mesh" works to the fullest, but i think, i understood most of it.
Another thing i need to mention is, that i am defining frequency bands in my next following code. I did this, because i noticed, i have very high amplitudes in a range from 1 - 1000Hz, which is why, i defined 3 frequency bands. It is not necessary to plot all of them, but i want to visualise at least one. Not visualising the whole frequency range from the audio signal, but only the specificially chosen band.
%% MATLAB
%_________________________________________
[y,fs]=audioread('dontstopmenow.wav');
% audioread = Read WAV-file
% y = Vector, which contains audio signal
% fs = Sample Rate
% 'dontstopmenow' = WAV-file
%_________________________________________
%PARAMETER FOR STFT
%_________________________________________
t_seg=0.03; % Length of segment in ms
fftlen = 4096; %FFT-Points
%Defining the length of my frequency bands
f_LOW= 1:200; % contain lower frequencies
f_MEDIUM= 201:600; % contain medium frequencies
f_HIGH= 601:1000; % contain higher frequencies
%_______________________________________________________
segl =floor(t_seg*fs);
% Length of segment, on which we use the fft
% "floor" rounds off the result
windowshift=segl/2;
% size of window which goes to the next segment
window=hann(segl);
%hann function
window=window.';
% From a row vector to a column vector
si=1;
%Start index
ei=segl;
%End index
N= length(y)/windowshift - 1;
% Number of time segements in audio signal
f1=figure;
% New window
f=0:1:fftlen-1;
f=f/(fftlen-1)*fs;
% frequency vector
Ya=zeros(1,fftlen);
%Plotting time segments!
for m= 1:1:N
y_a = y(si:ei);
y_a= y_a.*window;
Ya=fft(y_a, fftlen);
Ya=abs(Ya(1:end/2));
%One-sided-spectrum
drawnow; %Updates graphical objects
figure(f1);
plot(f(1:end/2), 20*log10(Ya));
%STFT __ plots the whole audio signal after a stft, every 30ms
%% L,M,H - Bands
subplot(3,1,1)
y_low = Ya(f_LOW);
plot(f_LOW,y_low);
ylim([-20 60]);
title('Spektrum (LOW)');
xlabel('f(Hz)');
ylabel('dB');
grid on
subplot(3,1,2)
y_medium = Ya(f_MEDIUM);
plot(f_MEDIUM,y_medium);
ylim([-20 30]);
title('Spektrum (MEDIUM)');
xlabel('f(Hz)');
ylabel('dB');
grid on
subplot(3,1,3)
y_high = Ya(f_HIGH);
plot(f_HIGH,y_high);
ylim([-20 30]);
title('Spektrum (HIGH)');
xlabel('f(Hz)');
ylabel('dB');
grid on;
si=si+windowshift;
% start index updated
ei=ei+windowshift;
% end index updated
end
Here's the list of statements you could add to your code to generate the waterfall plot:
Let's store all STFT outputs in a matrix named Yb. Firstly, allocate the memory by adding this line before the for-loop.
Yb = NaN(N, fftlen/2);
Next, in the for-loop, save the fft result for each segment. This can be done by adding the following line after you have finished the computation of Ya (just before drawnow).
Yb(m,:) = Ya;
Now you're ready to generate the waterfall plot. This can be done by adding the following code after the end of the for-loop.
figure;
waterfall(f(f_LOW), (1:N)*windowshift/fs, Yb(:,f_LOW));
xlabel('Frequency (Hz)');
ylabel('Time (s)');
Hope this achieves what you want.
Following is not related to the main question: I also have the following suggestions to improve some other aspects of your code:
(1) The computation of the frequency grid f has a small scaling error. It should be:
f=f/fftlen*fs;
(2) Depending on the WAV file you use, your code may get fractional values in windowshift and N, but both of them need to be integers. So, use appropriate rounding methods while computing them. I'd suggest the following:
windowshift = round(segl/2);
N = floor(length(y)/windowshift);
(3) In the for-loop, you plot the whole fft only to overwrite that with the subplots immediately. That line should be removed.
I have a set of curves varying over time, that are stored in a MATLAB matrix. Each row of the matrix is one of those curves, unfolding over time. Those are repetitions of a random experiment.
I need to plot the mean of these curves over time, along with the 95% confidence intervals.
My understanding of statistics this is rather poor, but I was suggested to use bootstrap confidence intervals using MATLAB's bootci function.
I implemented a minimal example in MATLAB, but I have some doubts. I hope you can help me gaining a better grasp on this and avoiding dumb mistakes.
Here's the example:
NVARIABLES = 200;
NOBSERVATIONS = 1000;
RESAMPLING = 10000;
DATA = rand(NOBSERVATIONS, NVARIABLES);
[CI, STAT] = bootci(RESAMPLING, #mean, DATA);
MEAN = mean(DATA); % <------- [1]
x = 1:NVARIABLES;
figure;
hold on;
plot(x, MEAN, 'LineWidth', 2);
plot(x, CI(1,:), '--', 'LineWidth', 2); % [2]
plot(x, CI(2,:), '--', 'LineWidth', 2);
% plot(x, MEAN-CI(1,:)); % ?
% plot(x, MEAN+CI(2,:)); % ?
hold off;
Here are my questions:
Am I using the function properly?
When reporting/plotting the mean, is it correct to plot mean(DATA) (see line 1) or I should plot a mean derived by the bootstrapping procedure? I saw that STAT contains the mean for each bootstrap example, but I don't know whether I should use this information, and how
Is it correct to plot the confidence intervals the way I am doing (see line [2]), or I should plot MEAN-CI(1,:) and MEAN+CI(2,:)?
Please find attached the plot generated by the code.
I can answer Q1 and Q3.
Q1. The first argument needs to be the number of bootstrap samples used in the computation, the second, a function that returns the statistic for which you wish to find the confidence intervals, and the third is the dataset itself that you want to give as input to the function. You will have to ensure if the first argument is correct for you, the rest seems correct.
Q3. What you've done is right - CI gives the range, and not the variation from the mean. There's also another way to plot it, which might be better in certain scenarios, or just based on personal preferences. plot_ci is a function that lets you plot confidence intervals and shows clean patches for these intervals on the same plot. The plots look like this (this is a sample plot, not based on the dataset in the question):
Here's the command:
plot_ci(x,[MEAN,CI(1,:),CI(2,:)],'PatchColor', 'k', 'PatchAlpha', 0.1, 'MainLineWidth', 2, 'MainLineStyle', '-', 'MainLineColor', 'b','LineWidth', 1.5, 'LineStyle','--', 'LineColor', 'k');
I was trying to plot STFT using plot3 in MATLAB but failed. Can somebody guide me how to do that? My MWE is given below:
%% STFT Computataion
clear; clc; clf;
%% Get input and calculate frame size and overlap/shift
[Y,Fs]=wavread('D_NEHU_F0001_MN_10001');
frame_size=round(20*Fs/1000); % calculate frame size for 20ms
frame_shift=round(10*Fs/1000); % calculate frame shift for 10ms
%% Plot the input signal in time domain
t=1/Fs:1/Fs:(length(Y)/Fs);
subplot(2,1,1)
plot(t,Y);
title('Speech signal in time domain');
ylabel('Magnitude of samples');
xlabel('time in seconds');
%% Calculation of STFT
%NoOfFrames=floor((length(Y)/frame_shift)-1);
NoOfFrames=length(Y)-frame_size;
j=1;
%for i=1:frame_shift:(length(Y)-frame_size)
for i=1:frame_shift:((length(Y)-frame_size))%+frame_shift)
sp_frame=Y(i:(i+frame_size)).*hamming(frame_size+1);
sp_frame_dft=abs(fft(sp_frame)); % Compute STFT
sp_frame_array(:,j)=sp_frame_dft;
j=j+1;
end
%% Plot the STFT in 3D
[rows,cols]=size(sp_frame_array);
F=linspace(1/Fs,Fs/2000,cols);
T=1/Fs:(frame_shift*Fs/1000):(cols*(frame_shift*Fs/1000));
Z=1:frame_size+1;
subplot(2,1,2)
%mesh(sp_frame_array);
%surf(sp_frame_array,'EdgeColor','none');
plot3(T,F,sp_frame_array);
I am not sure what your question exactly is about, but I guess the problem is, with the provided code, that you do not get a plot similar to the one you'd get, say, with surf.
Furthermore, I am also not quite sure why you would want to use plot3, maybe to get the labels on the time and frequency right ? you could do that all the same with surf:
surf(T, F, sp_frame_array,'EdgeColor','none');
As a matter of fact, the reason why your plot3 does not give the same figure is because the arguments of plot3 must be three matrices of the same size (check it on help plot3). Your code should actually be broken on Matlab, which it's not, according to my test. Well, once again Matlab allowing people to mess around without warnings (go Python! :D)... Anyway, try to set the matrices more like the following:
F=linspace(1/Fs,Fs/2000, rows); % note: has to be rows, not cols here!
Fmat = F(:) * ones(1,cols); % or use repmat
T=1/Fs:(frame_shift*Fs/1000):(cols*(frame_shift*Fs/1000));
Tmat = ones(rows,1) * T(:)';
plot3(Tmat,Fmat,sp_frame_array);
While this will normally produce something more in line with what I would expect in drawing a spectrogram, I'd still make some remarks:
your F vector should go up to Fs, because of the way you filled sp_frame_dft in. More specifically, it should go from 0Hz to Fs - Fs/rows:
F = linspace(0,Fs*(1-1/rows)/1000,rows); % in kHz
you would probably like to draw the amplitudes in dBs:
plot3(Tmat,Fmat,db(sp_frame_array));
plot3 draws one line per column of the provided matrices. That means potentially lots of lines to draw! As #atul-ingle asked, are you sure this is what you want? Maybe waterfall would provide a better rendering at a lower cost?
waterfall(T,F,db(sp_frame_array));
Well, you'll get the lines for the rows, instead of the columns, so you might need to transpose if the latter is what you want.
You might also prefer to visualise only the first half of the matrix (because the frequencies higher than Fs/2 are only mirrors of the other half of the matrix).
Hope that helps!
This is about how MATLAB can take very different times to plot the same thing — and why.
I generate 10000 points in 3D space:
X = rand(10000, 1);
Y = rand(10000, 1);
Z = rand(10000, 1);
I then used one of four different methods to plot this, to create a plot like so:
I closed all figures and cleared the workspace between each run to try to ensure fairness.
Bulk plotting using scatter3:
>> tic; scatter3(X, Y, Z); drawnow; toc
Elapsed time is 0.815450 seconds.
Individual plotting using scatter3:
>> tic; hold on;
for i = 1:10000
scatter3(X(i), Y(i), Z(i), 'b');
end
hold off; drawnow; toc
Elapsed time is 51.469547 seconds.
Bulk plotting using plot3:
>> tic; plot3(X, Y, Z, 'o'); drawnow; toc
Elapsed time is 0.153480 seconds.
Individual plotting using plot3:
>> tic; hold on
for i = 1:10000
plot3(X(i), Y(i), Z(i), 'o');
end
drawnow; toc
Elapsed time is 5.854662 seconds.
What is it that MATLAB does behind the scenes in the 'longer' routines to take so long? What are the advantages and disadvantages of using each method?
Edit:
Thanks to advice from Ben Voigt (see answers), I have included drawnow commands in the timing — but this has made little difference to the times.
The main difference between the time required to run scatter3 and plot3 comes from the fact that plot3 is compiled, while scatter3 is interpreted (as you'll see when you edit the functions). If scatter3 was compiled as well, the speed difference would be small.
The main difference between the time required to plot in a loop versus plotting in one go is that you add the handle to the plot as a child to the axes (have a look at the output of get(gca,'Children')), and you're thus growing a complicated array inside a loop, which we all know to be slow. Furthermore, you're calling several functions often instead of just once and incur thus calls from the function overhead.
Recalculation of axes limits aren't an issue here. If you run
for i = 1:10000
plot3(X(i), Y(i), Z(i), 'o');
drawnow;
end
which forces Matlab to update the figure at every iteration (and which is A LOT slower), you'll see that the axes limits don't change at all (since the default axes limits are 0 and 1). However, even if the axes limits started out differently, it wouldn't take many iterations for them to converge with these data. Compare with omitting the hold on, which makes plotting take longer, because axes are recalculated at every step.
Why have these different functions? scatter3 allows you to plot points with different marker sizes, and colors under a single handle, while you'd need a loop and get a handle for each point using plot3, which is not only costly in terms of speed, but also in terms of memory. However, if you need to interact with different points (or groups of points) individually - maybe you want to add a separate legend entry for each, maybe you want to be able to turn them on and off separately etc - using plot3 in a loop may be the best (though slow) solution.
For a faster approach, consider this third option (directly uses the low-level function LINE):
line([X,X], [Y,Y], [Z,Z], 'LineStyle','none', 'Marker','o', 'Color','b')
view(3)
Here are some articles discussing plotting performance issues:
Performance: scatter vs. line
Plot performance
Well, if you wanted control over the color of each point, bulk scatter would be faster, because you'd need to call plot separately.
Also, I'm not sure your timing information is accurate because you haven't called drawnow, so the actual drawing could take place after toc.
In summary:
plot3 is fastest because it draws the same marker at many different locations
scatter3 draws many different markers, since size and color of the marker (are allowed to) vary with each point
calling in a loop is really slow, because argument parsing and so forth have to take place repeatedly, in addition as points are added to the plot the axes have to be recalculated