Related
I'm trying to create an animated plot but my code is very slow, perhaps the method I'm using is too naive. In the below example, I have 4 subplots each with 3 lines, which I update in a 'time' loop.
clc;clear;close all;
state = {'$x-Position$','$x-Velocity$','$y-Position$','$y-Velocity$'};
ylabels = {'$x$','$\dot{x}$','$y$','$\dot{y}$'};
options1 = {'interpreter','latex'};
options2 = {'interpreter','latex','fontsize',20};
maxT = 300;
for pp = 1:4
hh1(pp)=subplot(2,2,pp);
xlabel('$t$',options2{:});
ylabel(ylabels{pp},options2{:});
title(state{pp},options1{:})
xlim([0 maxT])
hold on
end
x = randn(4,300);
z = randn(4,300);
x_est = randn(4,300);
for k = 2:maxT
for p = 1:4
plot(hh1(p),k-1:k,x(p,k-1:k),'b','linewidth',2)
plot(hh1(p),k-1:k,z(p,k-1:k),'m')
plot(hh1(p),k-1:k,x_est(p,k-1:k),':k','linewidth',2)
end
drawnow;
end
As can be seen from the profiler output, the drawnow is killing the time. Is there any way I can be more efficient in creating this animation?
Because you want an animation, there is no alternative to using drawnow to update the frame. However, it's not drawnow in particular which is slowing you down - the profiler can be misleading... drawnow simply updates all of the graphics changes since the last re-draw, which in your case is a dozen new plots!
You'll find that hold is pretty slowing. For instance if you're wiser about your holding, remove the existing hold on and only hold when actually plotting
% ... above code the same but without 'hold on'
for p = 1:4
hold(hh1(p), 'on');
% plots
hold(hh1(p), 'off');
end
This saves ~10% time on my PC (12.3sec down to 11.3sec).
The real speed up comes from removing hold entirely, along with all of the individual plot calls! This method also doesn't touch the line formatting which will help with speed. See a previous question about updating plot data here.
Simply update the plot data instead of adding plots. This gives me a speedup of ~68% (12.3sec down to 4.0sec).
% ... your same setup
% Initialise plot data
x = randn(4,300);
z = randn(4,300);
x_est = randn(4,300);
plts = cell(4,3);
hh1 = cell(4,1);
% Loop over subplots and initialise plot lines
for p = 1:4
hh1{p}=subplot(2,2,p);
xlabel('$t$',options2{:});
ylabel(ylabels{p},options2{:});
title(state{p},options1{:})
xlim([0 maxT])
% Hold on to make 3 plots. Create initial points and set line styles.
% Store the plots in a cell array for later reference.
hold on
plts{p,1} = plot(hh1{p},1:2,x(p,1:2),'b','linewidth',2);
plts{p,2} = plot(hh1{p},1:2,z(p,1:2),'m');
plts{p,3} = plot(hh1{p},1:2,x_est(p,1:2),':k','linewidth',2);
hold off
end
% March through time. No replotting required, just update XData and YData
for k = 2:maxT
for p = 1:4
set(plts{p,1}, 'XData', 1:k, 'YData', x(p,1:k) );
set(plts{p,2}, 'XData', 1:k, 'YData', z(p,1:k) );
set(plts{p,3}, 'XData', 1:k, 'YData', x_est(p,1:k) );
end
drawnow;
end
Now the plotting is pretty optimised. If you want the animation to be even quicker then just plot every 2nd, 3rd, ..., nth timestep instead of every timestep by using for k = 2:n:maxT.
I want to produce a animated gif of a solution to a partial differential equation. That is the gif should show the solution at specific time.
Currently I can only make pictures in which all times are plotted.
Below is my entire program, with figure(3) being my attempt of making a gif.
clear all;
close all;
%%%%%%%%%%%%
% For slide 27 of Diffusion 1D
% The equation to be graphed in latex form is
% u(x,t)=\frac{1}{L}+\frac{2}{L}\sum^{\infty}_{n=1}cos(\frac{n\pi x_0}{L})cos(\frac{n\pi x}{L})e^{-k(\frac{n\pi}{L})^2t}
%%%%%%%%%%%%
%define constants
%note that the constants listed in the file are arbitrary
L = 2; %length of the rod
k= 0.01; % Diffusivity, which is assume to be constant but can be a function of x
x0 = 1; %location of the inital condition i.e. f(x)=delta(x-x0)
tmax= 50; %maximum amount of time the simulation runs
nmax = 200; % maximum value for n, increase to accuracy
tgrid = 21; %The number of points to be evaluated in the time domain
xgrid = 51; %The number of points to be evaluated in the space domain
%initialize variables
u=zeros(tgrid,xgrid); %preallocate array used for storing values of the solution
t=linspace(0,tmax,tgrid);%We assume that time is evenly distributed
x=linspace(0,L,xgrid); %We assume that space is evenly distributed
%Plotting variables
figure(1);
hold on;
axis([0 L -inf inf]);
xlabel('x');
ylabel('u(x,t)');
%Calculation,
for i=1:tgrid
for j=1:xgrid
seriesSum=0;
%Calculate the fourier series up to nmax for each point u(x,t)
for n= 1:nmax
seriesSum= seriesSum + cos(n*pi*x0/L)*cos(n*pi*x(j)/L)*exp(-k*t(i)*(n*pi/L)^2);
end
%Finish calcuation for solution at a specific point
u(i,j)= 1/L+(2/L)*seriesSum;
end
%After we have calculated all points at time t, we graph it for time t
plot(x,u(i,:),'linewidth',4);
end
saveas(gcf,'PDE_sol.png')%Save figure as png in current directory
%run a second loop that does not include the initial condition to get a
%better view of the long term behaviour.
%Plotting variables
figure(2);
hold on;
axis([0 L -inf inf]);
xlabel('x');
ylabel('u(x,t)');
for i=2:tgrid
plot(x,u(i,:),'linewidth',4);
end
saveas(gcf,'PDE_sol_without_inital.png')%Save figure as png in current directory
%Create a gif verison of figure 2
figure(3);
axis([0 L -inf inf]);
xlabel('x');
ylabel('u(x,t)');
filename = 'PDE_sol.gif';
for i=2:tgrid
plot(x,u(i,:),'linewidth',4);
drawnow
frame = getframe(1);
im = frame2im(frame);
[imind,cm] = rgb2ind(im,256);
if i == 2;
imwrite(imind,cm,filename,'gif', 'Loopcount',inf);
else
imwrite(imind,cm,filename,'gif','WriteMode','append');
end
end
The output gif that I get is
which is clearly not animated.
Note: If you think there is a better place to post this question please direct me to it. As my issue is with the MATLAB programming language and not the math involved I thought this would be the best place to post my question.
The first input to getframe is the handle of the figure that you'd like to take a screenshot of. As you have it written, you are grabbing figure 1 which is actually referring to the first figure that you create that you aren't updating within your loop.
You have assigned a numeric handle of 3 to the figure that you create right before your last loop so you'll want to tell getframe to use that figure instead.
Additionally, I would create one plot object and update the XData and YData rather than continuously creating new plot objects. The issue with calling plot continuously is that it's slow AND it completely resets all of your axes settings such as x and y labels as well as x and y limits.
% Store the handle to the figure in hfig
hfig = figure(3);
% Create the initial plot object
hplot = plot(NaN, NaN, 'LineWidth', 4);
axis([0 L 0 2]);
xlabel('x');
ylabel('u(x,t)');
filename = 'PDE_sol.gif';
for i=2:tgrid
% Update the plot appearance
set(hplot, 'XData', x, 'YData', u(i,:));
drawnow
% Get a screenshot of THIS figure
frame = getframe(hfig);
im = frame2im(frame);
[imind,cm] = rgb2ind(im,256);
if i == 2;
imwrite(imind,cm,filename,'gif', 'Loopcount',inf);
else
imwrite(imind,cm,filename,'gif','WriteMode','append');
end
end
Hi I'm trying to calculate mfcc for which i'm windowing. I have seen this one post I'm getting error in fftOneSide.
my code is
waveFile='test_preEmphasis.wav';
[y, fs]=wavread(waveFile);
n=512;
t=(1:n)'/fs;
startIndex=30418;
endIndex=startIndex+n-1;
original=y(startIndex:endIndex);
windowed=original.*hamming(n);
[mag1, phase1, freq1]=fftOneSide(original, fs);
[mag2, phase2, freq2]=fftOneSide(windowed, fs);
subplot(3,2,1); plot(original); grid on; axis([-inf inf -1 1]);
title('Original signal');
subplot(3,2,2); plot(windowed); grid on; axis([-inf inf -1 1]);
title('Windowedsignal');
subplot(3,2,3); plot(freq1, mag1); grid on;
title('Energy spectrum (linear scale)');
subplot(3,2,4); plot(freq2, mag2); grid on;
title('Energy spectrum (linear scale)');
subplot(3,2,5); plot(freq1, 20*log(mag1)); grid on;
axis([-inf inf -80 120]); title('Energy spectrum (db)');
subplot(3,2,6); plot(freq2, 20*log(mag2)); grid on; axis([-inf inf -80 120]);
title('Energy spectrum (db)');
the error i'm getting is
??? Undefined function or method 'fftOneSide' for input arguments of type 'double'.
any help is appreciated
thanks
This is a really old post, it'd be neat if someone still cared. I just provided what I believe to be the answer in the recent post below, which I arrived at after a fair bit of frustration: Undefined function 'fftOneSide' for input arguments of type 'double'.
It should be noted here there's a call to a file, which I'm not sure if the author had originally or not. I suspect all the problems are related to a similarly named file in the sourcecode.
If you look at my discussion in the other post, within the function definition there is a call to a method demo with a file - which isn't present if you just have the function definition, not the original file. Calling [mag1, phase1, freq1]=fftOneSide(original, fs,1), after you comment out the first line if nargin <1... and the demo routine worked fine on my machine with the code which I'll show below. Having the third argument equal to 1 guarantees that the code will run the print routines, which is important.
In case the other thread is closed, I just want to show the output, when the input is manually defined, and I call [mag1, phase1, freq1]=fftOneSide(original, fs,1) on the properly edited method, with the inputs as in the original post shown below (notice the call is to original in fftOneSide..in the other post it was like this as well.. I believe the call was was meant to be instead for windowed, but I don't have the signals toolbox with hamming anyways):
fs=8000;
t=(1:512)'/fs; %'// <-- prevents string markdown
f=306.396;
original=sin(2*pi*f*t)+0.2*randn(length(t),1);
% windowed=original.*hamming(length(t)); % defined in other post
[mag1,phase1,freq1]=fftOneSide(original,fs); % I call fftOneSide(original,fs,1);
The output is as follows (source code below!)
Anyways, here's the source code in case anyone wants to use this function
function [magSpec, phaseSpec, freq, powerSpecInDb]=fftOneSide(signal, fs, plotOpt)
% fftOneSide: One-sided FFT for real signals
% Usage: [magSpec, phaseSpec, freq, powerSpecInDb]=fftOneSide(signal, fs)
%
% For example:
% [y, fs]=wavread('welcome.wav');
% frameSize=512;
% startIndex=2047;
% signal=y(startIndex:startIndex+frameSize+1);
% signal=signal.*hamming(length(signal));
% plotOpt=1;
% [magSpec, phaseSpec, freq, powerSpecInDb]=fftOneSide(signal, fs, plotOpt);
% Roger Jang, 20060411, 20070506
if nargin<1, selfdemo; return; end %=== (MathBio: Comment this out!)
if nargin<2, fs=1; end
if nargin<3, plotOpt=0; end
N = length(signal); % Signal length
freqStep = fs/N; % Frequency resolution
time = (0:N-1)/fs; % Time vector
z = fft(signal); % Spectrum
freq = freqStep*(0:N/2); % Frequency vector
z = z(1:length(freq)); % One side
z(2:end-1)=2*z(2:end-1); % Assuming N is even, symmetric data is multiplied by 2
magSpec=abs(z); % Magnitude spectrum
phaseSpec=unwrap(angle(z)); % Phase spectrum
powerSpecInDb=20*log(magSpec+realmin); % Power in db
if plotOpt
% ====== Plot time-domain signals
subplot(3,1,1);
plot(time, signal, '.-');
title(sprintf('Input signals (fs=%d)', fs));
xlabel('Time (seconds)'); ylabel('Amplitude'); axis tight
% ====== Plot spectral power
subplot(3,1,2);
plot(freq, powerSpecInDb, '.-'); grid on
title('Power spectrum');
xlabel('Frequency (Hz)'); ylabel('Power (db)'); axis tight
% ====== Plot phase
subplot(3,1,3);
plot(freq, phaseSpec, '.-'); grid on
title('Phase');
xlabel('Frequency (Hz)'); ylabel('Phase (Radian)'); axis tight
end
% ====== Self demo (MathBio: Comment all of this out! )
function selfdemo
[y, fs]=wavread('welcome.wav');
frameSize=512;
startIndex=2047;
signal=y(startIndex:startIndex+frameSize+1);
signal=signal.*hamming(length(signal));
[magSpec, phaseSpec, freq, powerSpecInDb]=feval(mfilename, signal, fs, 1);
I have two distinct problems, but they're posted together because I believe the solutions are related. I'm testing Newton's and secant methods (each of which is implemented with a loop) and plotting the results versus computing time on the same axes to compare them. I want the (discrete) Newton's method results to be connected by a blue line and the secant method results by a red line. These lines, in turn, are annotated by a corresponding legend. This is not happening because each and every point on the plot seems to be considered at individual object because they were individually created. And the legend command brings up two blue asterisks instead a blue one and a red one (I wish I could post my plot here, but I don't have the image privilege yet.)
Here's my abbreviated code:
f = (x) % define function
figure
hold on
%% Newton
tic
while % terminating condition
% [Newtons method]
t = toc;
plot(t,log(abs(f(z)),'b*-')
end
%% Secant
tic
while % terminating condition
% [secant method]
t = toc;
plot(t,log(abs(f(z)),'r*-')
end
legend('Newton''s','Secant')
Needless to day, the '-' in the linespec doesn't do anything because only a point is being plotted, not a line. I know I could make a line plot with each iteration with something like plot([t_old t],[log(abs(f(z_old) log(abs(f(z)]), but that isn't ideal, not least because log(abs(f(z_old))) would have to be reevaluated each time. Besides, that would not solve the problem with the legend.
I think both problems will be solved if I can get MATLAB to understand that I'm trying to create just two objects on the axes, one blue line and one red line. Thank you.
If you don't want to store the x/y data in a vector and then replot the entire vector you could just add to the plotting line using code like this:
hNewton = [];
while % terminating condition
% [Newtons method]
t = toc;
if isempty(hNewton)
hNewton = plot(t,log(abs(f(z))),'b*-'); % First time through plot and save the line handle
else
% On all subsequent passes, just add to the lines X/Y data
set(hNewton,'XData',[get(hNewton,'XData') t]);
set(hNewton,'YData',[get(hNewton,'YData') log(abs(f(z)))]);
end
end
Since there are now only 2 lines, the legend works as expected.
Alternatively, you could put the code to add data to an existing line in a function
function hLineHandle = AddToLine( hLineHandle, xData, yData, lineStyle )
% AddToLine - Add data to a plotted line
if isempty(hLineHandle)
hLineHandle = plot(xData,yData, lineStyle);
else
set(hLineHandle,'XData',[get(hLineHandle,'XData') xData]);
set(hLineHandle,'YData',[get(hLineHandle,'YData') yData]);
end
end
Which makes the code in the main script/function a lot cleaner.
hNewton = [];
while % terminating condition
% [Newtons method]
t = toc;
hNewton = AddToLine(hNewton,t, log(abs(f(z))),'b*-' );
end
You can use line object, for example:
f = (x) % define function
figure
hold on
lHandle1 = line(nan, nan); %# Generate a blank line and return the line handle
lHandle2 = line(nan, nan); %# Generate a blank line and return the line handle
%% Newton
tic
while % terminating condition
% [Newtons method]
t = get(lHandle1, 'XData');
Y1 = get(lHandle1, 'YData');
t = toc;
Y1 = [Y1 log(abs(f(z)];
set(lHandle1, 'XData', t, 'YData', Y1, 'LineWidth', 2 ,'Color' , [0 1 0]);
end
%% Secant
tic
while % terminating condition
% [secant method]
t = get(lHandle2, 'XData');
Y2 = get(lHandle2, 'YData');
t = toc;
Y2 = [Y2 log(abs(f(z)];
set(lHandle2, 'XData', t, 'YData', Y2, 'LineWidth', 2 ,'Color' , [1 0 0]);
end
legend('Newton''s','Secant')
Good example of only showing the relevant parts of your code to ask a question. The others have explained tricks to have the legend behave as you want. I would go for a different solution, by saving your measurements in a vector and doing the plots after the loops. This has 2 advantages: you do not have to do the tricks with the legend, but more importantly, you are not doing a plot inside your loop, which potentially takes a lot of time. I would guess that your timing is dominated by the plotting, so the influence of your algorithm will hardly show up in the results. So change your code to something like this (untested):
f = (x) % define function
% preallocate plenty of space
[t_newton, t_secant, f_newton, f_secant] = deal(nan(1, 1000));
%% Newton
tic;
i = 1;
while % terminating condition
% [Newtons method]
f_newton(i) = current_result;
t_newton(i) = toc;
i = i + 1;
end
%% Secant
tic;
i = 1;
while % terminating condition
% [secant method]
f_secant(i) = current_result;
t_secant(i) = toc;
i = i + 1;
end
% trim NaNs (not really needed, not plotted anyhow)
t_newton = t_newton(isfinite(t_newton));
f_newton = f_newton(isfinite(f_newton));
t_secant = t_secant(isfinite(t_secant));
f_secant = f_secant(isfinite(f_secant));
% do the plot
semilogy(t_newton, abs(f_newton), t_secant, abs(f_secant))
legend('Newton''s','Secant')
I created a GUI program with MATLAB, with a menu bar and tabs, each containing a plot, a text box, etc. The problem is that when I select a tab from the menu bar and plot something, the axes objects from former plots don't disappear.
I tried to use cla reset unsuccessfully. clf worked, but my menu bar disappeared as well.
Here is my code:
function fel1_Callback(hObject, eventdata, handles) %% plot sin(x)
cla reset
clc
clear all
d = inputdlg('n:','Ertekadas',1);
n = str2double(d);
x=linspace(-3*pi,3*pi,1000);
y=sin(x);
plot(x,y,'k','LineWidth',4)
sz='ymcrgbkymcrgbkymcrgbkymcrgbk';
hold on
title('Sin(x) Taylor sora')
%n = str2num(N);
f=zeros(size(x));
for i=1:n
t=(-1)^(i-1)*x.^(2*i-1)/factorial(2*i-1);
f=f+t;
plot(x,f,sz(i),'LineWidth',2)
axis([-10 10 -10 10])
pause(0.1)
hold on
n=n+1;
end
function fel7_Callback(hObject, eventdata, handles) %%Sum 1/n^2
clear all
clc
cla reset
title('Suma 1/n^2','fontsize',20)
d = inputdlg('Epszilon:','Ertek',1);
epsz = str2double(d);
n=1;
x=0;
while 1/n^2>epsz
x=x+sum(1/n^2);
n=n+1;
end
A = uicontrol('style','text','units','pixels',...
'position',[550 550 120 40],'fontsize',20,'string','Epsz =');
B = uicontrol('style','text','units','pixels',...
'position',[670 550 120 40],'fontsize',20);
set(B,'String',epsz)
C = uicontrol('style','text','units','pixels', ...
'position',[550 400 120 40],'fontsize',20,'string','Osszeg =');
D = uicontrol('style','text','units','pixels',...
'position',[670 400 120 40],'fontsize',20);
set(D,'String',x)
I use only one main GUI figure. My menu bar contains a lot of plots and calculations, not only these two.
The problem is that hold on prevents anything from being erased and just keeps adding to the plot. Nowhere in your code do you turn hold off. If you want to keep using the hold command, your code needs to look like this:
function fel1_Callback(hObject, eventdata, handles) %% plot sin(x)
d = inputdlg('n:','Ertekadas',1);
n = str2double(d);
x=linspace(-3*pi,3*pi,1000);
y=sin(x);
hold off % The next plot command should now clear the old plot and create a new one**
plot(x,y,'k','LineWidth',4)
sz='ymcrgbkymcrgbkymcrgbkymcrgbk';
hold on
title('Sin(x) Taylor sora')
%n = str2num(N);
f=zeros(size(x));
for i=1:n
t=(-1)^(i-1)*x.^(2*i-1)/factorial(2*i-1);
f=f+t;
plot(x,f,sz(i),'LineWidth',2)
axis([-10 10 -10 10])
pause(0.1)
%hold on %not necessary, this was turned on before the loop
n=n+1;
end
hold off % return the figure to the normal (default) "hold off" state