I'm brand new to Julia (v1.7.1) and I've been using VSCode as an IDE. In VSCode (v1.64) I've installed the Julia Extension (v1.5.10). When plotting in VSCode, the plot shows up in the plot pane by default. I'm using the Plots (v1.25.7) package and the "gr" backend, as it's one of the "faster" options.
I'm trying to make a "live" time series plot, in which the series is updated in a loop. This seems to be a popular problem, as there are many questions addressing this, but I've found no "clean" solution yet. I should emphasize that I'm not trying to make an animation, which is fabricated upon termination of the loop. I want to update the plot as the loop is running. I've looked at SmoothLivePlot, but I think this requires that I know the series size before hand, which is not the case in my application. Then again, maybe I'm misinterpreting the package.
I'm going to present what I've done this far, with hopes for improvement. I first created a plotting function
function plt_update(p,time_series,var_series)
plot!(time_series, var_series,
label = "",
linecolor = :red)
display(p)
end
Then I initialized the plot
model_time = 100
p = plot([0.0],[0.0],
label = "",
linecolor = :red,
xlims = (0, model_time),
ylims = (0, 1),
display(p)
My loop is then called (NOTE: that all the code shown in this post is wrapped in a function and run in the RPEL, hence variables do not need to be defined with "global" inside the while loop. This is due to Julia's optimization and scope design...from what I've read. See another discussion on this for an example).
run_time = 0.0
time_series = [0.0]
var_series = [0.0]
while run_time < model_time
# Calculate new timestep
timestep = rand(Float64) # Be sure to add Random
run_time += timestep
# Computations
sleep(timestep/10)
# Build vector
push!(time_series,run_time)
push!(var_series,timestep)
# Live plots
plt_update(p,time_series,var_series)
end
I've encountered a few problems with this. First, I don't know if this is just an issue with VSCode or who to point the finger at, but putting display(p) inside the function to update the plot in the VSCode plot pane ends up creating a new plot for each iteration in the loop. Clearly this is not what is intended. I found that if I shut off the "plot in pane" option (File > Preferences > Settings > Extensions > Julia), then a single plot window is created. I'm not sure if "create new plot in pane" is expected or an issue (again, I'm new to this). Nevertheless, when plotting outside the VSCode, the above code works as I expected.
For the next issue, which I think is most important here, is that inside the plotting function, the call to plot! adds a new vector to p, while saving the previous one as well. In other words, p is not being updated with the new series, it is growing by appending a whole new vector. This is clear as the plotting comes to a grinding halt after many iterations. Also, if you remove the "color" attribute, you'll see the line changes color with each iteration. In effect, what is being plotted is many lines, all overlapping.
I then dove into p to look more closely at what is going on and made some changes to the plotting function
function plt_update(p,time_series,var_series)
push!(p.series_list[1].plotattributes[:x],time_series[:][end])
push!(p.series_list[1].plotattributes[:y],var_series[:][end])
display(p)
end
Above, instead of creating a new series_list (as was the case before w/ plot!), I'm now updating the series w/ the new data. This works much better than before and behaves as expected. While it's only a slight improvement, I've further modified the function and the function call by passing a scalar instead of a vecotr
function plt_update(p,run_time,variable)
push!(p.series_list[1].plotattributes[:x],run_time)
push!(p.series_list[1].plotattributes[:y],variable)
display(p)
end
in which the function call is now plt_update(p,run_time,timestep). As you can see, I sleep for a random time then divide that by 10, which I found to be about as much lag as I can afford before it loses it's "near realtime" appeal. Dividing by 100, for example, results in rather noticeable lag.
So my question is...is there a way to improve this, where the lag is reduced? Being new to Julia, I'm not aware of all the plotting options or how to access the "guts" to make improvements on my own.
EDIT:
I've just become aware of "Makie" and "Observables". I'm going to do a bit more research on those to see if this offers an improvement in the latency.
EDIT2:
In my research, I found a much cleaner way to express the last function (also see here for further confirmation of the approach)
function plt_update(p,run_time,variable)
push!(p,1,run_time,variable)
display(p)
end
The solution I found w/ Makie & observables is without a doubt the best! Between the YouTube video and code, I was able to apply it to my example above. Granted, my loop is only ~150 iterations, there is negligible lag (which was far from the case prior). Taking out the sleep function, the plot is instantaneous. I would encourage others to try this approach for "near real-time" plots.
The packages needed are
using GLMakie
using GeometryTypes
I'm not sure if GeometryTypes is needed explicitly (I thought GLMakie would bring in the necessary libs), but I was getting an error stating that Point2f0 was not found.
First, create the observable (note that it's a vector of type Point2f0)
pt_series = Observable([Point2f0(0, 0)])
Then initialize the plot
fig = Figure(); display(fig)
ax = Axis(fig[1,1])
lines!(ax, pt_series; linewidth = 4, color = :purple)
# Static elements
ax.title = "Time Series"
ax.xlabel = "Time (s)"
ax.ylabel = "Data"
xlims!(ax, 0, 100)
ylims!(ax, 0, 1)
Then run the loop
model_time = 100
run_time = 0.0
while run_time < model_time
# Calculate new timestep
timestep = rand(Float64)
run_time += timestep
# Computations
#sleep(timestep/1000)
# Live plots
push!(pt_series[], Point2f0(run_time, timestep))
pt_series[] = pt_series[]
end
As I stated in the question, all of the code above should be wrapped in a function to prevent scoping errors.
Related
I am working on pedestrian step detection (acceleration). I want to calculate statistical features from my filtered signal. I have already calculated some and now I want to calculate gradient.
My data is of 1x37205 double. I calculated features using for loop with moving window size=2samples and 50% overlap of previous window. Below I am attaching the code I tried to calculate the gradient.
I am not sure if it is the right way to calculate or not? In addition, I am also unable to understand that what is the purpose to use gradient, how it can be useful for step detection and how to work with gradient? Could some one guide me or provide any code help in matlab?
%%Here M is mean and V is variance i already calculated from filtered data
G = zeros(length(window:length(M)), 2);
for i = window:length(M)
temp = gradient(M(i+1-window:i),V(i+1-window:i));
G(i, 1) = temp(2, 1); % "c1"
G(i, 2) = temp(2, 1); % "c2"
end
One of the best features of Matlab is its documentation. If you are unfamiliar on how to get specific function documentation, enter the following in the command line:
doc functionName
Alternatively, for 'brief' documentation that displays in the command line, you can enter:
help functionName
Also see the documentation link here.
Your question is worded poorly, so I will summarize what I understand and answer accordingly:
You have a step detection data (1*37205) double, let us call it stepSignal
stepSignal is position data
You want your window to be 2 steps with 50% overlap. This is the default behavior for the gradient function.
You do not need a "for" loop to achieve your goal. According to the documentation, "gradient" can take one input.
See the code below, and if need be add clarifications to the original question.
%% Assume that stepSignal is already imported into the workspace
velocity = gradient(stepSignal);
One last note, when you give "gradient" two inputs, it automatically assumes the second input is a uniform spacing value.
TL;DR: How should custom simulation runs be managed in Matlab? Detailed Questions at the end.
I am working with matlab where i created some code to check the influence of various parameters on a simulated system. It has a lot of inputs and outputs but a MWE would be:
function [number2x,next_letter] = test(number, letter)
number2x = number * 2;
next_letter = letter + 1;
disp(['next letter is ' next_letter])
disp(['number times 2 is ' num2str(number2x)])
end
This works if this is all there is to test. However with time multiple new inputs and outputs had to be added. Also because of the growing number of paramters that have been test some sort of log had to be created:
xlswrite('testfile.xlsx',[num2str(number), letter,num2str(number2x),next_letter],'append');
Also because the calculation takes a few hours and should run over night multiple parameter sets had to be started at one point. This is easily done with [x1,y1] = test(1,'a');[x2,y2] = test(2,'b'); in one line or adding new tasks while the old still run. However this way you can't keep track on how many are still open.
So in total I need some sort of testing framework, that can keep up with changeging inpus and outputs, keeps track on already doen calculations and ideally also handles the open runs.
I feel like i can't be the only one who faces this issue, in fact I think so many people face this issue that Mathworks would already came up with a solution.
For Simulink this has been done in form of a Simluationmanager, but for Matlab functions the closest thing i found is the Testing framework (example below) which seems to be rather for software development and debugging and not at all for what i am trying. And somepoint there seem to be 3rd party solutions but they are no longer continued in favor of this Testing framework.
function solutions = sampleTest
solutions = functiontests({#paramtertest});
end
function paramtertest(vargin)
test(1,'a');
test(2,'b');
end
function [number2x,next_letter] = test(number, letter)
number2x = number * 2;
next_letter = letter + 1;
disp(['next letter is ' next_letter])
disp(['number times 2 is ' num2str(number2x)])
xlswrite('testfile.xlsx',[num2str(number), letter,num2str(number2x),next_letter],'append');
end
Alternatively I could create my test as a class, create an interface similar to the Simulationmanager, create numerous functions for managing inputs and outputs and visualize the progress and then spawn multiple instances of if i want to set up a new set of parameters while already running a simulation. Possible, yet a lot of work that does not involve the simulation directly.
In total following questions arise:
Is there a build in Matlab function for managing simulations that i totally missed so far?
Can the the Testing framework be used for this purpose?
Is there already some Framework (not from Mathworks) that can handle this?
If i create my own class, could multiple instances run individually and keep track of their own progress? And would those be handled simultaniously or would matlab end up running the in the order they started?
I know this question is somewhat in the off-topic: recommend or find a tool, library or favorite off-site resource area. If you feel it is too much so, please focus on the last question.
Thank you!
I've done similar tests using GUI elements. Basic part of simulation was inside while loop, for example in your case:
iter = 0;
iter_max = 5; %the number of your times, you will call script
accu_step = 2; %the accuracy of stored data
Alphabet = 'abcdefghijklmnopqrstuvwxyz'
while iter < iter_max
iter = iter+1;
[x1,y1] = test(i,Alphabet(i));
end
Now you should create a handle to progress bar inside your computation script. It will show you both on which step you are, and the progress of current step.
global h;
global iter_opt;
if isempty(h)
h=waitbar(0,'Solving...');
else
waitbar(t/t_end,h,sprintf('Solving... current step is:%d',iter));
end
You didn't specified which function you use, if it is for example time-depended the above t/t_end example is an estimation of current progress.
The solving of result also require to be changed on every execution of loop, for example:
global iter;
i_line = (t_end/accu_step+2)*(iter-1);
xlswrite('results.xlsx',{'ITERATION ', iter},sheet,strcat('A',num2str(i_line+5)))
xlswrite('results.xlsx',results_matrix(1:6),sheet,strcat('D',num2str(i_line+5)))
The above example were also with assumption that your results are time-related, so you store data every 2 units of time (day, hours, min, what you need), from t_0 to t_end, with additional 2 rows of separation, between steps. The number of columns is just exemplary, you can adjust it to your needs.
After the calculation is done, you can close waitbar with:
global h
close(h)
For an aerospace course aerelasticity I am doing an assignment with Nastran in Matlab (by using system(command) and bdf as input file).
I have attached a piece of my code as explanation. In this case the program Nastran produces a punch file (text) with displacements.
Currently the problem is that Matlab disregards the time Nastran needs for analysis to produce this punch file and continues on with the loop, however this punch file is not created yet so matlab turns out an error saying it does not exist and stops the loop.
I "have" a workaround for this by setting the pause times manually found from running it manually for increasing mesh sizes, this gives me at least some data on mesh convergence, however this is not a suitable method to use the rest of the assignment as it will take way too much time, therefore it must be automated.
I was thinking of setting a condition temporarily pausing the loop if the punch file does not exist and turning on again if it exists, however I got stuck with using a pause condition inside a while loop alltogether, it does not seem a solution to me.
Do you have any suggestions / ideas on what I could use / do how to get around this problem
or
know if there is a way to sent a callback from system(nastran) which i can use to create a condition to control the loop or something in that direction?
The following is a piece of code of the created function which turns out the Residual Mean squared error of the mesh which I use to see if the mesh converges:
%% Run Nastran
system('"C:\Users\$$$$\AppData\Roaming\MSC.Software\MSC_Nastran_Student_Edition\2014\Nastran\bin\nastranw.exe" nastranfile.bdf mem=1gb'); % Run the created bdf file
pause(15);
%% Read results and save all relevant results
fpc = fopen('nastranfile.pch','r')
line = 0;
for j=1:6;
line = line+1;
fgets(fpc);
end
line;
counter=0;
data = [];
while ~feof(fpc)
counter= counter+1;
str = fgets(fpc);
line=line+1;
str = str(61:73);
data(counter) = str2num(str)
fgets(fpc);
line=line+1;
end
line;
fclose(fpc);
% Find RMSE
mdl = fitlm(1:length(data),data);
RMEA = mdl.Rsquared.Adjusted;
RMSE = mdl.RMSE;
I have a Matlab project in which I need to make a GUI that receives two mathematical functions from the user. I then need to find their intersection point, and then plot the two functions.
So, I have several questions:
Do you know of any algorithm I can use to find the intersection point? Of course I prefer one to which I can already find a Matlab code for in the internet. Also, I prefer it wouldn't be the Newton-Raphson method.
I should point out I'm not allowed to use built in Matlab functions.
I'm having trouble plotting the functions. What I basically did is this:
fun_f = get(handles.Function_f,'string');
fun_g = get(handles.Function_g,'string');
cla % To clear axes when plotting new functions
ezplot(fun_f);
hold on
ezplot(fun_g);
axis ([-20 20 -10 10]);
The problem is that sometimes, the axes limits do not allow me to see the other function. This will happen, if, for example, I will have one function as log10(x) and the other as y=1, the y=1 will not be shown.
I have already tried using all the axis commands but to no avail. If I set the limits myself, the functions only exist in certain limits. I have no idea why.
3 . How do I display numbers in a static text? Or better yet, string with numbers?
I want to display something like x0 = [root1]; x1 = [root2]. The only solution I found was turning the roots I found into strings but I prefer not to.
As for the equation solver, this is the code I have so far. I know it is very amateurish but it seemed like the most "intuitive" way. Also keep in mind it is very very not finished (for example, it will show me only two solutions, I'm not so sure how to display multiple roots in one static text as they are strings, hence question #3).
function [Sol] = SolveEquation(handles)
fun_f = get(handles.Function_f,'string');
fun_g = get(handles.Function_g,'string');
f = inline(fun_f);
g = inline(fun_g);
i = 1;
Sol = 0;
for x = -10:0.1:10;
if (g(x) - f(x)) >= 0 && (g(x) - f(x)) < 0.01
Sol(i) = x;
i = i + 1;
end
end
solution1 = num2str(Sol(1));
solution2 = num2str(Sol(2));
set(handles.roots1,'string',solution1);
set(handles.roots2,'string',solution2);
The if condition is because the subtraction will never give me an absolute zero, and this seems to somewhat solve it, though it's really not perfect, sometimes it will give me more than two very similar solutions (e.g 1.9 and 2).
The range of x is arbitrary, chosen by me.
I know this is a long question, so I really appreciate your patience.
Thank you very much in advance!
Question 1
I think this is a more robust method for finding the roots given data at discrete points. Looking for when the difference between the functions changes sign, which corresponds to them crossing over.
S=sign(g(x)-f(x));
h=find(diff(S)~=0)
Sol=x(h);
If you can evaluate the function wherever you want there are more methods you can use, but it depends on the size of the domain and the accuracy you want as to what is best. For example, if you don't need a great deal of accurac, your f and g functions are simple to calculate, and you can't or don't want to use derivatives, you can get a more accurate root using the same idea as the first code snippet, but do it iteratively:
G=inline('sin(x)');
F=inline('1');
g=vectorize(G);
f=vectorize(F);
tol=1e-9;
tic()
x = -2*pi:.001:pi;
S=sign(g(x)-f(x));
h=find(diff(S)~=0); % Find where two lines cross over
Sol=zeros(size(h));
Err=zeros(size(h));
if ~isempty(h) % There are some cross-over points
for i=1:length(h) % For each point, improve the approximation
xN=x(h(i):h(i)+1);
err=1;
while(abs(err)>tol) % Iteratively improve aproximation
S=sign(g(xN)-f(xN));
hF=find(diff(S)~=0);
xN=xN(hF:hF+1);
[~,I]=min(abs(f(xN)-g(xN)));
xG=xN(I);
err=f(xG)-g(xG);
xN=linspace(xN(1),xN(2),15);
end
Sol(i)=xG;
Err(i)=f(xG)-g(xG);
end
else % No crossover points - lines could meet at tangents
[h,I]=findpeaks(-abs(g(x)-f(x)));
Sol=x(I(abs(f(x(I))-g(x(I)))<1e-5));
Err=f(Sol)-g(Sol)
end
% We also have to check each endpoint
if abs(f(x(end))-g(x(end)))<tol && abs(Sol(end)-x(end))>1e-12
Sol=[Sol x(end)];
Err=[Err g(x(end))-f(x(end))];
end
if abs(f(x(1))-g(x(1)))<tol && abs(Sol(1)-x(1))>1e-12
Sol=[x(1) Sol];
Err=[g(x(1))-f(x(1)) Err];
end
toc()
Sol
Err
This will "zoom" in to the region around each suspected root, and iteratively improve the accuracy. You can tweak the parameters to see whether they give better behaviour (the tolerance tol, the 15, number of new points to generate, could be higher probably).
Question 2
You would probably be best off avoiding ezplot, and using plot, which gives you greater control. You can vectorise inline functions so that you can evaluate them like anonymous functions, as I did in the previous code snippet, using
f=inline('x^2')
F=vectorize(f)
F(1:5)
and this should make plotting much easier:
plot(x,f(x),'b',Sol,f(Sol),'ro',x,g(x),'k',Sol,G(Sol),'ro')
Question 3
I'm not sure why you don't want to display your roots as strings, what's wrong with this:
text(xPos,yPos,['x0=' num2str(Sol(1))]);
This question is somewhat related to a previous question of mine, where I didn't quite get the right solution. Link: Earlier SO-thread
I am solving PDEs which are time variant with one spatial dimension (e.g. the heat equation - see link below). I'm using the numerical method of lines, i.e. discretizing the spatial derivatives yielding a system of ODEs which are readily solved in Modelica (using the Dymola tool). My problems arise when I simulate the system, or when I plot the results, to be precise. The equations themselves appear to be solved correctly, but I want to express the spatial changes in all the discretized state variables at specific points in time rather than the individual time-varying behavior of each discrete state.
The strategy leading up to my problems is illustrated in this Youtube tutorial, which by the way is not made by me. As you can see at the very end of the tutorial, the time-varying behavior of the temperature is plotted for all the discrete points in the rod, individually. What I would like is a plot showing the temperature through the rod at a specific time, that is the temperature as a function of the spatial coordinate. My strategy to achieve this, which I'm struggling with, is: Given a state vector of N entries:
Real[N] T "Temperature";
..I would use the plotArray Dymola function as shown below.
plotArray( {i for i in 1:N}, {T[i] for i in 1:N} )
Intuitively, this would yield a plot showing the temperature as a function of the spatial coordiate, or the number in the line of discrete units, to be precise. Although this command yields a result, all T-values appear to be 0 in the plot, which is definitely not the case. My question is: How can I successfully obtain and plot the temperatures at all the discrete points at a given time? Thanks in advance for your help.
The code for the problem is as indicated below.
model conduction
parameter Real rho = 1;
parameter Real Cp = 1;
parameter Real L = 1;
parameter Real k = 1;
parameter Real Tlo = 0;
parameter Real Thi = 100;
parameter Real Tinit = 30;
parameter Integer N = 10 "Number of discrete segments";
Real T[N-1] "Temperatures";
Real deltaX = L/N;
initial equation
for i in 1:N-1 loop
T[i] = Tinit;
end for;
equation
rho*Cp*der(T[1]) = k*( T[2] - 2*T[1] + Thi) /deltaX^2;
rho*Cp*der(T[N-1]) = k*( Tlo - 2*T[N-1] + T[N-2]) /deltaX^2;
for i in 2:N-2 loop
rho*Cp*der(T[i]) = k*( T[i+1] - 2*T[i] + T[i-1]) /deltaX^2;
end for
annotation (uses(Modelica(version="3.2")));
end conduction;
Additional edit: The simulations show clearly that for example T[3], that is the temperature of discrete segment no. 3, starts out from 30 and ends up at 70 degrees. When I write T[3] in my command window, however, I get T3 = 0.0 in return. Why is that? This is at the heart of the problem, because the plotArray function would be working if I managed to extract the actual variable values at specific times and not just 0.0.
Suggested solution: This is a rather tedious solution to achieve what I want, and I hope someone knows a better solution. When I run the simulation in Dymola, the software generates a .mat-file containing the values of the variables throughout the time of the simulation. I am able to load this file into MATLAB and manually extract the variables of my choice for plotting. For the problem above, I wrote the following command:
plot( [1:9]' , data_2(2:2:18 , 10)' )
This command will plot the temperatures (as the temperatures are stored together with their derivates in the data_2 array in the .mat-file) against the respetive number of the discrete segment/element. I was really hoping to do this inside Dymola, that is avoid using MATLAB for this. For this specific problem, the amount of variables was low on account of the simplicity of this problem, but I can easily image a .mat-file which is signifanctly harder to navigate through manually like I just did.
Although you do not mention it explicitly I assume that you enter your plotArray command in Dymola's command window. That won't work directly, since the variables you see there do not include your simulation results: If I simulate your model, and then enter T[:] in Dymola's command window, then the printed result is
T[:]
= {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}
I'm not a Dymola expert, and the only solution I've found (to actively store and load the desired simulation results) is quite cumbersome:
simulateModel("conduction", resultFile="conduction.mat")
n = readTrajectorySize("conduction.mat")
X = readTrajectory("conduction.mat", {"Time"}, n)
Y = readTrajectory("conduction.mat", {"T[1]", "T[2]", "T[3]"}, n)
plotArrays(X[1, :], transpose(Y))