I am trying to transcribe one of my scripts into App Designer in Matlab so that I easily distribute it to students. The idea is to show forces and moments acting in 6 degrees of freedom on a vehicle in real time (based on user input through a joystick). I am using a very simplistic animation made of multiple 3D arrow plots at the moment (which refreshes every 0.1 s), but it does the job. What I would like to get is shown in the first figure, whereas the second figure shows what I actually get in App Designer.
The relevant lines of code in App Designer which I use for the plotting are as follows:
function plot_ROV(app)
% Plot the forces and moments acting on the ROV in the correct graph:
quiver3(app.UIAxes,0,0,0,1,0,0);
hold(app.UIAxes);
quiver3(app.UIAxes,0,0,0,0,1,0);
hold(app.UIAxes);
quiver3(app.UIAxes,0,0,0,0,0,1);
hold(app.UIAxes);
quiver3(app.UIAxes,0,0,0,app.Surge,0,0,'LineWidth',5,'Color',app.Colors(1,:));
hold(app.UIAxes);
quiver3(app.UIAxes,0,0,0,0,app.Sway,0,'LineWidth',5,'Color',app.Colors(2,:));
hold(app.UIAxes);
quiver3(app.UIAxes,0,0,0,0,0,app.Heave,'LineWidth',5,'Color',app.Colors(3,:));
hold(app.UIAxes);
app.circular_arrow3([1,0,0],app.Roll,0.2,app.Colors(4,:));
hold(app.UIAxes);
app.circular_arrow3([0,1,0],app.Pitch,0.2,app.Colors(5,:));
hold(app.UIAxes);
app.circular_arrow3([0,0,1],app.Yaw,0.2,app.Colors(6,:));
hold(app.UIAxes);
legend(app.UIAxes,'x-axis','y-axis','z-axis','surge','sway','heave','roll','roll',...
'pitch','pitch','yaw','yaw','Location','BestOutside');
end
function circular_arrow3(app,axis,angle,radius,color)
% Generate the data for the circle in 2D space:
np = 10; % no. points
a = linspace(0,angle*pi,np);
p = [radius.*cos(a);radius.*sin(a);zeros(1,np)];
% Select the correct rotation matrix depending on the axis:
if sum((axis-[1,0,0]).^2)==0
R = [0,0,1;0,1,0;-1,0,0];
elseif sum((axis-[0,1,0]).^2)==0
R = [1,0,0;0,0,-1;0,1,0];
p(2,:) = - p(2,:);
elseif sum((axis-[0,0,1]).^2)==0
R = eye(3);
else
error('Only rotations about the x-, y- and z-axes are supported');
end
% Rotate the points:
pr = zeros(size(p));
for i=1:np
pr(:,i) = R*p(:,i);
end
% Calculate the difference between the last two points:
x = pr(1,end);
y = pr(2,end);
z = pr(3,end);
u = pr(1,end)-pr(1,end-1);
v = pr(2,end)-pr(2,end-1);
w = pr(3,end)-pr(3,end-1);
% Plot the points:
plot3(app.UIAxes,pr(1,:),pr(2,:),pr(3,:),'LineWidth',4,'Color',color);
hold(app.UIAxes);
quiver3(app.UIAxes,x,y,z,u,v,w,'LineWidth',6,'Color',color);
end
Now, by comparing the two figures, I think my problem is that the hold command is not working, at least not the way I intend it to: only the points from the last circular arrow are shown. Since I do not have much experience with App Designer, my feeling is I must have done a basic mistake.
Thanks in advance for the help!
In the plot_ROV function you call hold several times providing only one input parameter (namely the handle of the axes) that is without specifying the on property (hold(app.UIAxes);.
If the hold function is called in such a way, its effect is to toggle the property on / off in each call.
You can fix the issue either:
removing all the calls to hold butg the first one: just on call is enough to "add" subsequents items in the axes through the plotting functions
you can keep all the calls, but you have to specify the on property
hold(app.UIAxes,'on');
For more information about the hold function you can refer to the hold on-line documentation
Related
I want to simulate the movements of 3 robots/agents in space and I would like to generate 3 different trajectories which have one constraint: in a certain time T the all the trajectories must have the same tangent.
I want something like in the following picture:
I need to do it through MATLAB and/or SIMULINK.
Thanks a lot for your help.
I do not know if this is enough for what I need or not but I probably figured out something.
What I did is to fit a polynomial to some points and constraining the derivative of the polynomial in a certain point to be equal to 0.
I used the following function:
http://www.mathworks.com/matlabcentral/fileexchange/54207-polyfix-x-y-n-xfix-yfix-xder-dydx-
It is pretty easy, but it saved me some work.
And, if you try the following:
% point you want your functions to pass
p1 = [1 1];
p2 = [1 3];
% First function
x1 = linspace(0,4);
y1 = linspace(0,4);
p = polyfix(x1,y1,degreePoly,p1(1),p1(2),[1],[0]);
% p = [-0.0767 0.8290 -1.4277 1.6755];
figure
plot(x1,polyval(p,x1))
xlim([0 3])
ylim([0 3])
grid on
hold on
% Second function
x2 = linspace(0,4);
y2 = linspace(0,4);
p = polyfix(x2,y2,degreePoly,[1],[3],[1],[0])
% p = [0.4984 -2.7132 3.9312 1.2836];
plot(x2,polyval(p,x2))
xlim([0 3])
ylim([0 3])
grid on
If you don't have the polyfix function and you don't want to download it you can try the same code commenting the polyfix lines:
p = polyfix(x1,y1,degreePoly,p1(1),p1(2),[1],[0]);
p = polyfix(x2,y2,degreePoly,p2(1),p2(1),[1],[0]);
And uncommenting the lines:
% p = [-0.0767 0.8290 -1.4277 1.6755];
% p = [0.4984 -2.7132 3.9312 1.2836];
You will get this:
Now I will use this polynomial as a position (x,y) over time of my robots and I think I should be done. The x of the polynomial will be also the time, in this way I am sure that the robots will arrive in the 0-derivative point at the same time.
What do you think? Does it make sense?
Thanks again.
To have tangents same all the time, curves (or trajectories) needs to be always parallel. Generate trajectory for one object and keep other objects at fixed distance apart and following master trajectory.
In image provides if we take time next to three dots trajectories will not be same (or parallel) as objects moved in different directions. So i guess you've to keep then always parallel
I have to generate a series of 2D grid in matlab in some local coordinate systems, e.g:
xC = 0:0.2:10;
yC = 0:0.1:1;
[xlocal,ylocal] = meshgrid(xC,yC);
Over the local coordinates a scalarfield is defined, for instance:
scalarField = xlocal.^2+ylocal.^2;
contourf(xlocal,ylocal,scalarField);
Now I would to plot the "scalarField" in a global reference system X,Y. So I should take every coordinate pair and apply an (in plane) rotation+translation. The only idea I have is a "for" loop over all the coordinates, but it seems to be quite slow (I have many grids).
May you devise a better code?
I figured out by myself. Instead of rotating the whole grid I simply regenerate a new one that assures the mapping. The code itself is a way more readable than by using loops. I'm posting for whom may have the same issues.
In any case further and faster contributions are welcome!!
[xloc,yloc] = meshgrid(s,t); %mesh in local coordiantes
%% get grid in global coordiantes
getX = #(coord1,coord2) R(1,:)*[coord1; coord2] + c(1);
getY = #(coord1,coord2) R(2,:)*[coord1; coord2] + c(2);
Xgrid = arrayfun(getX,xloc,yloc);
Ygrid = arrayfun(getY,xloc,yloc);
I'm very new to Matlab.
I have a script using ode45 and arrow.m to show the motion of a swinging spring with a mass on Matlab as it moves through 3-D space. The program is almost doing what I want it to. Right now the density of the diamonds is showing the speed of the spring in effect (except for when ode45 takes it personal favorite number samples) and the velocity is almost accurately accounted for with the step size of the function (at least with the speed that my computer is running the code). What I want to do with this is have the position vector that I commented out in the code only show up at the instantaneous position of the mass, that is the endpoint of the curve, and not at every point that the diamonds show up at. I've looked around for help, but everything I try seems to cause errors. If somebody could point me in the right direction it would be much appreciated. Please try running the program and you will see what I mean, also play around with the parameters of the function.
function elasticPendulum(totalTime)
time=1;
totalTime=20
X=1
Vx=0
Y=0
Vy=0
Z=1.1
Vz=0
w=3;
g=9;
l=1;
while (time<totalTime)
tspan=[0,time];
x0=[X,Vx,Y,Vy,Z,Vz];
[t,x]=ode45(#F,tspan,x0);
plot3(x(:,1),x(:,3),x(:,5),'dk'), axis([-2 2 -2 2 -10 2]);
grid on;
o=[0, 0, 0];
Xeq=[0, 0, -(g/(w^2)+l)];
arrow(o,Xeq,'Length',5);
%{
Xt=[x(:,1) x(:,3) x(:,5)]
arrow(o,Xt,'Length',5);
%}
time=time+.1*(((x(2))^2+(x(4))^2+(x(6))^2)^(1/2))
pause(.1);
end
function xprime=F(t,x)
r=sqrt(x(1)^2+x(3)^2+x(5)^2);
xprime=[x(2);-w*(r-l)/r*x(1);x(4);-w*(r-l)/r*x(3);x(6);-w*(r-l)/r*x(5)-g];
end
end
I think that you can accomplish what you want simply by setting Xt to this so that only the last vector is plotted on each iteration:
Xt = [x(end,1) x(end,3) x(end,5)];
Also, you mention that things are working "except for when ode45 takes it personal favorite number samples." You can can tell ode45 to use fixed step output simply by changing tspan:
tspan = 0:dt:time;
where dt = 1/time (or you could use linspace). This is not the same thing as using a fixed step solver – read my answer to this question to maybe gain some understanding on this.
I don't think that you're updating your animation properly. You update time, but not the initial conditions. Therefore, you integrate over the same path on each iteration of the while loop. Is there a reason that you're adjusting the end time on each iteration? Are you trying to find the oscillation period or something?
Also, your method of animation is rather crude/inefficient. You should read about the output options that can be set via odeset for Matlab's ODE solvers. In particular 'OutputFcn'. You might even be able to use and/or look at the code for some of the built in output functions – for example, type edit odeplot or edit odephas3 in your command window. Here is a simple output function I created for your case:
function elasticPendulum
totalTime = 20;
stepsPerSec = 10;
X = 1; Vx = 0;
Y = 0; Vy = 0;
Z = 1.1; Vz = 0;
w = 3; g = 9; l = 1;
opts = odeset('OutputFcn',#(t,x,flag)arrowplot(t,x,flag,w,l,g));
tspan = linspace(0,totalTime,totalTime*stepsPerSec);
x0 = [X,Vx,Y,Vy,Z,Vz];
ode45(#(t,x)F(t,x,w,l,g),tspan,x0,opts);
function xprime=F(t,x,w,l,g) %#ok<INUSL>
r=sqrt(x(1)^2+x(3)^2+x(5)^2);
xprime=[x(2);-w*(r-l)/r*x(1);x(4);-w*(r-l)/r*x(3);x(6);-w*(r-l)/r*x(5)-g];
function status=arrowplot(t,x,flag,w,l,g) %#ok<INUSL>
persistent h; % Handle for moving arrow
status = 0;
o = [0, 0, 0];
switch flag
case 'init'
axis([-2 2 -2 2 -10 2]); grid on; hold on;
Xeq = [0, 0, -(g/(w^2)+l)];
arrow(o,Xeq,'Length',5);
plot3(x(1,:),x(3,:),x(5,:),'dk'); % Initial position
Xt = [x(1,end) x(3,end) x(5,end)];
h = arrow(o,Xt,'Length',5); % Initial arrow, get handle
case 'done'
hold off; status = 1;
otherwise
plot3(x(1,:),x(3,:),x(5,:),'dk'); % Plot new positions
Xt = [x(1,end) x(3,end) x(5,end)];
arrow(h,'Start',o,'Stop',Xt,'Length',5); % Update arrow
pause(0.1);
end
The call to plot3 on every iteration (the otherwise case in arrowplot) is still inefficient as it adds new high level plot objects, taking up more memory. The better/faster way is to get a handle from the first call to plot3 and use set and get to add the new data points. See the code for odeplot and odephas3 for how you might do this (it's a bit advanced).
Note how I also pass parameters via anonymous functions rather than by creating sub-functions. This is a bit of a matter of style.
I am having difficulty with calculating 2D area of contours produced from a Kernel Density Estimation (KDE) in Matlab. I have three variables:
X and Y = meshgrid which variable 'density' is computed over (256x256)
density = density computed from the KDE (256x256)
I run the code
contour(X,Y,density,10)
This produces the plot that is attached. For each of the 10 contour levels I would like to calculate the area. I have done this in some other platforms such as R but am having trouble figuring out the correct method / syntax in Matlab.
C = contourc(density)
I believe the above line would store all of the values of the contours allowing me to calculate the areas but I do not fully understand how these values are stored nor how to get them properly.
This little script will help you. Its general for contour. Probably working for contour3 and contourf as well, with adjustments of course.
[X,Y,Z] = peaks; %example data
% specify certain levels
clevels = [1 2 3];
C = contour(X,Y,Z,clevels);
xdata = C(1,:); %not really useful, in most cases delimters are not clear
ydata = C(2,:); %therefore further steps to determine the actual curves:
%find curves
n(1) = 1; %n: indices where the certain curves start
d(1) = ydata(1); %d: distance to the next index
ii = 1;
while true
n(ii+1) = n(ii)+d(ii)+1; %calculate index of next startpoint
if n(ii+1) > numel(xdata) %breaking condition
n(end) = []; %delete breaking point
break
end
d(ii+1) = ydata(n(ii+1)); %get next distance
ii = ii+1;
end
%which contourlevel to calculate?
value = 2; %must be member of clevels
sel = find(ismember(xdata(n),value));
idx = n(sel); %indices belonging to choice
L = ydata( n(sel) ); %length of curve array
% calculate area and plot all contours of the same level
for ii = 1:numel(idx)
x{ii} = xdata(idx(ii)+1:idx(ii)+L(ii));
y{ii} = ydata(idx(ii)+1:idx(ii)+L(ii));
figure(ii)
patch(x{ii},y{ii},'red'); %just for displaying purposes
%partial areas of all contours of the same plot
areas(ii) = polyarea(x{ii},y{ii});
end
% calculate total area of all contours of same level
totalarea = sum(areas)
Example: peaks (by Matlab)
Level value=2 are the green contours, the first loop gets all contour lines and the second loop calculates the area of all green polygons. Finally sum it up.
If you want to get all total areas of all levels I'd rather write some little functions, than using another loop. You could also consider, to plot just the level you want for each calculation. This way the contourmatrix would be much easier and you could simplify the process. If you don't have multiple shapes, I'd just specify the level with a scalar and use contour to get C for only this level, delete the first value of xdata and ydata and directly calculate the area with polyarea
Here is a similar question I posted regarding the usage of Matlab contour(...) function.
The main ideas is to properly manipulate the return variable. In your example
c = contour(X,Y,density,10)
the variable c can be returned and used for any calculation over the isolines, including area.
I wish to visualize the movement of a data point throughout space across a period of time within MATLAB. However, the way I want my figure to display is such that only a single instant is plotted at any given time. That was easy, I simply created a for loop to update my 3D plot display for every set of coordinates (x,y,z) in my data. However, I wish to display 4 different viewing angles of this plot at all times. I am well aware of how to setup subplots within MATLAB, that is not the issue. My issue is getting all 4 of these subplots to execute simultaneously so that all 4 subplots are always displaying the same point in time.
How to handle this issue?
As requested, my code for a figure with a single plot is shown below:
datan = DATA; %data in form of x,y,z,a,b,c by column for row# of time points
tib=zeros(size(datan,1),12);
tib(:,1:3) = datan(:,1:3);
tib_ref=tib(1,1:3);
for i=1:size(datan,1)
tib(i,1:3)=tib(i,1:3)-tib_ref;
end
angle_to_dircos
close all
figure('Name','Directions (Individual Cycles)','NumberTitle','off')
for cc=1:2
hold off
for bb=1:10:size(tib,1);
scatter3(tib(bb,1),tib(bb,2),tib(bb,3),'green','filled'); %z and y axes are flipped in polhemus system
hold on
p0 = [tib(bb,1),tib(bb,2),tib(bb,3)];
p1 = [tib(bb,1)+10*tib(bb,4),tib(bb,2)+10*tib(bb,5),tib(bb,3)+10*tib(bb,6)];
p2 = [tib(bb,1)+10*tib(bb,7),tib(bb,2)+10*tib(bb,8),tib(bb,3)+10*tib(bb,9)];
p3 = [-(tib(bb,1)+100*tib(bb,10)),-(tib(bb,2)+100*tib(bb,11)),-(tib(bb,3)+100*tib(bb,12))];
vectarrow(p0,p1,1,0,0)
hold on
vectarrow(p0,p2,0,1,0)
hold on
vectarrow(p0,p3,0,0,1)
hold on
az = 90;
el = 0;
view(az, el);
xlim([-50,50]);
ylim([-50,50]);
zlim([-50,50]);
xlabel('distance from center in X');
ylabel('distance from center in Y');
zlabel('distance from center in Z');
title('XYZ Scatter Plots of Tracker Position');
hold on
plot3(0,0,0,'sk','markerfacecolor',[0,0,0]);
p0 = [0,0,0];
p1 = [10,0,0];
p2 = [0,10,0];
p3 = [0,0,100];
vectarrow(p0,p1,1,0,0)
hold on
vectarrow(p0,p2,0,1,0)
hold on
vectarrow(p0,p3,1,0,1)
drawnow;
end
end
If you use set to update the x and y-data of your points, rather than recreating the plot entirely every time, the update will be simultaneous thanks to Matlab waiting for drawnow.
Here's an example
figure,
subplot(1,2,1),plot(rand(10,1),rand(10,1),'.'),hold on,p1=plot(rand(1),rand(1),'.r')
subplot(1,2,2),plot(rand(10,1),rand(10,1),'.'),hold on,p2=plot(rand(1),rand(1),'.r')
%# read the red coordinates - I should have stored them before plotting :)
x(1) = get(p1,'xdata');y(1)=get(p1,'ydata');x(2)=get(p2,'xdata');y(2)=get(p2,'ydata');
%# animate
for i=1:100,
delta = randn(1,2)*0.01;
x=x+delta(1);
y=y+delta(2);
set(p1,'xdata',x(1),'ydata',y(1));
set(p2,'xdata',x(2),'ydata',y(2));
pause(0.1),
drawnow, %# I put this in case you take out the pause
end