I have written the LorenzaAttractor class and have successfully plotted y and z against x in 2D. Is it possible to plot this in 3D?
model LorenzAttractor
parameter Real sigma = 10;
parameter Real rho = 28;
parameter Real beta = 8/3;
Real x (start=1);
Real y (start = 1);
Real z (start = 1);
equation
der(x) = sigma*(y-x);
der(y) = x * (rho-z) - y;
der(z) = x*y - beta*z;
end LorenzAttractor;
Not in OMEdit as far as I am aware.
However, one alternative is to use the.csv or .mat file and use some auxiliary tool such as GNUPlot or some other plotting tool.
You can change the output here:
The resulting file will be in the working directory of OMEdit:
Related
I want to plot the field distribution inside a circular structure with radius a.
What I expect to see are circular arrows that from the centre 0 go toward a in the radial direction like this
but I'm obtaining something far from this result. I wrote this
x_np = besselzero(n, p, 1); %toolbox from mathworks.com for the roots
R = 0.1:1:a; PHI = 0:pi/180:2*pi;
for r = 1:size(R,2)
for phi = 1:size(PHI,2)
u_R(r,phi) = -1/2*((besselj(n-1,x_np*R(1,r)/a)-besselj(n+1,x_np*R(1,r)/a))/a)*cos(n*PHI(1,phi));
u_PHI(r,phi) = n*(besselj(n,x_np*R(1,r)/a)/(x_np*R(1,r)))*sin(PHI(1,phi));
end
end
[X,Y] = meshgrid(R);
quiver(X,Y,u_R,u_PHI)
where u_R is supposed to be the radial component and u_PHI the angular component. Supposing the formulas that I'm writing are correct, do you think there is a problem with for cycles? Plus, since R and PHI are not with the same dimension (in this case R is 1x20 and PHI 1X361) I also get the error
The size of X must match the size of U or the number of columns of U.
that I hope to solve it if I figure out which is the problem with the cycles.
This is the plot that I get
The problem has to do with a difference in co-ordinate systems.
quiver expects inputs in a Cartesian co-ordinate system.
The rest of your code seems to be expressed in a polar co-ordinate system.
Here's a snippet that should do what you want. The initial parameters section is filled in with random values because I don't have besselzero or the other details of your problem.
% Define initial parameters
x_np = 3;
a = 1;
n = 1;
% Set up domain (Cartesian)
x = -a:0.1:a;
y = -a:0.1:a;
[X, Y] = meshgrid(x, y);
% Allocate output
U = zeros(size(X));
V = zeros(size(X));
% Loop over each point in domain
for ii = 1:length(x)
for jj = 1:length(y)
% Compute polar representation
r = norm([X(ii,jj), Y(ii,jj)]);
phi = atan2(Y(ii,jj), X(ii,jj));
% Compute polar unit vectors
rhat = [cos(phi); sin(phi)];
phihat = [-sin(phi); cos(phi)];
% Compute output (in polar co-ordinates)
u_R = -1/2*((besselj(n-1, x_np*r/a)-besselj(n+1, x_np*r/a))/a)*cos(n*phi);
u_PHI = n*(besselj(n, x_np*r/a)/(x_np*r))*sin(phi);
% Transform output to Cartesian co-ordinates
U(ii,jj) = u_R*rhat(1) + u_PHI*phihat(1);
V(ii,jj) = u_R*rhat(2) + u_PHI*phihat(2);
end
end
% Generate quiver plot
quiver(X, Y, U, V);
I have a function with three parameters and some data that I want to fit. How can I do this optimally? I am not even sure of the range of the three parameters in the equation.
The function has free parameters alpha, beta and gamma and is given by
y = (1 - alpha + alpha./sqrt(1 + 2*beta*(gamma*x).^2./alpha)).^(-1) - 1;
I have arrays of x and y data points (around 50 points in each set) to which I want to find the best fit (defined as minimizing least squares) using any alpha, beta and gamma.
The solutions online recommend the curve fitting toolbox, which I do not have on my machine and am unable to install. I only have the barebones MATLAB 2015b version.
You need an optimization algorithm for smooth, R^n -> R functions. Since you have only access to barebone Matlab, a good idea is to take an algorithm from File Exchange. For illustration I picked LMFnlsq, which should suffice since you have a small problem, although it seems to be more general and a little bit overkill here.
Download LMFnlsq and add to your Matlab path.
Example
For convenience make a function called regr_fun:
function y = regr_fun(par, x)
alpha = par(1);
beta = par(2);
gamma = par(3);
y = (1 - alpha + alpha./sqrt(1 + 2*beta*(gamma*x).^2./alpha)).^(-1) - 1;
end
Curve fitting (in the same folder as regr_fun):
%---------------------------------------------------------------------
% DUMMY DATA
%---------------------------------------------------------------------
% Generate data from known model contaminated with random noise
rng(333) % for reproducibility
alpha = 2;
beta = 0.1;
gamma = 0.1;
par = [alpha, beta, gamma];
xx = 1:50;
y_true = regr_fun(par, xx);
yy = y_true + normrnd(0,1,1,50);
%---------------------------------------------------------------------
% FIT MODEL
%---------------------------------------------------------------------
% intial point of solver
p0 = [1,1,1];
obj_fun = #(p) sum((regr_fun(p, xx) - yy).^2);
% optimization
p_fit = LMFnlsq(obj_fun, p0);
y_fit = regr_fun(p_fit, xx);
%---------------------------------------------------------------------
% PLOT
%---------------------------------------------------------------------
plot(xx, yy, 'o')
hold on
plot(xx, y_true)
plot(xx, y_fit, '--')
Note
Although matlab.codetools.requiredFilesAndProducts lists the symbolic toolbox as well, for this problem it is not needed and the function should run withouth that as well.
I actually want to use a linear model to fit a set of 'sin' data, but it turns out the loss function goes larger during each iteration. Is there any problem with my code below ? (gradient descent method)
Here is my code in Matlab
m=20;
rate = 0.1;
x = linspace(0,2*pi,20);
x = [ones(1,length(x));x]
y = sin(x);
w = rand(1,2);
for i=1:500
h = w*x;
loss = sum((h-y).^2)/m/2
total_loss = [total_loss loss];
**gradient = (h-y)*x'./m ;**
w = w - rate.*gradient;
end
Here is the data I want to fit
There isn't a problem with your code. With your current framework, if you can define data in the form of y = m*x + b, then this code is more than adequate. I actually ran it through a few tests where I define an equation of the line and add some Gaussian random noise to it (amplitude = 0.1, mean = 0, std. dev = 1).
However, one problem I will mention to you is that if you take a look at your sinusoidal data, you define a domain between [0,2*pi]. As you can see, you have multiple x values that get mapped to the same y value but of different magnitude. For example, at x = pi/2 we get 1 but at x = -3*pi/2 we get -1. This high variability will not bode well with linear regression, and so one suggestion I have is to restrict your domain... so something like [0, pi]. Another reason why it probably doesn't converge is the learning rate you chose is too high. I'd set it to something low like 0.01. As you mentioned in your comments, you already figured that out!
However, if you want to fit non-linear data using linear regression, you're going to have to include higher order terms to account for the variability. As such, try including second order and/or third order terms. This can simply be done by modifying your x matrix like so:
x = [ones(1,length(x)); x; x.^2; x.^3];
If you recall, the hypothesis function can be represented as a summation of linear terms:
h(x) = theta0 + theta1*x1 + theta2*x2 + ... + thetan*xn
In our case, each theta term would build a higher order term of our polynomial. x2 would be x^2 and x3 would be x^3. Therefore, we can still use the definition of gradient descent for linear regression here.
I'm also going to control the random generation seed (via rng) so that you can produce the same results I have gotten:
clear all;
close all;
rng(123123);
total_loss = [];
m = 20;
x = linspace(0,pi,m); %// Change
y = sin(x);
w = rand(1,4); %// Change
rate = 0.01; %// Change
x = [ones(1,length(x)); x; x.^2; x.^3]; %// Change - Second and third order terms
for i=1:500
h = w*x;
loss = sum((h-y).^2)/m/2;
total_loss = [total_loss loss];
% gradient is now in a different expression
gradient = (h-y)*x'./m ; % sum all in each iteration, it's a batch gradient
w = w - rate.*gradient;
end
If we try this, we get for w (your parameters):
>> format long g;
>> w
w =
Columns 1 through 3
0.128369521905694 0.819533906064327 -0.0944622478526915
Column 4
-0.0596638117151464
My final loss after this point is:
loss =
0.00154350916582836
This means that our equation of the line is:
y = 0.12 + 0.819x - 0.094x^2 - 0.059x^3
If we plot this equation of the line with your sinusoidal data, this is what we get:
xval = x(2,:);
plot(xval, y, xval, polyval(fliplr(w), xval))
legend('Original', 'Fitted');
I have a 3D density function q(x,y,z) that I am trying to plot in Matlab 8.3.0.532 (R2014a).
The domain of my function starts at a and ends at b, with uniform spacing ds. I want to plot the density on a ternary surface plot, where each dimension in the plot represents the proportion of x,y,z at a given point. For example, if I have a unit of density on the domain at q(1,1,1) and another unit of density on the domain at q(17,17,17), in both cases there is equal proportions of x,y,z and I will therefore have two units of density on my ternary surface plot at coordinates (1/3,1/3,1/3). I have code that works using ternsurf. The problem is that the number of proportion points grows exponentially fast with the size of the domain. At the moment I can only plot a domain of size 10 (in each dimension) with unit spacing (ds = 1). However, I need a much larger domain than this (size 100 in each dimension) and much smaller than unit spacing (ideally as small as 0.1) - this would lead to 100^3 * (1/0.1)^3 points on the grid, which Matlab just cannot handle. Does anyone have any ideas about how to somehow bin the density function by the 3D proportions to reduce the number of points?
My working code with example:
a = 0; % start of domain
b = 10; % end of domain
ds = 1; % spacing
[x, y, z] = ndgrid((a:ds:b)); % generate 3D independent variables
n = size(x);
q = zeros(n); % generate 3D dependent variable with some norm distributed density
for i = 1:n(1)
for j = 1:n(2)
for k = 1:n(2)
q(i,j,k) = exp(-(((x(i,j,k) - 10)^2 + (y(i,j,k) - 10)^2 + (z(i,j,k) - 10)^2) / 20));
end
end
end
Total = x + y + z; % calculate the total of x,y,z at every point in the domain
x = x ./ Total; % find the proportion of x at every point in the domain
y = y ./ Total; % find the proportion of y at every point in the domain
z = z ./ Total; % find the proportion of z at every point in the domain
x(isnan(x)) = 0; % set coordinate (0,0,0) to 0
y(isnan(y)) = 0; % set coordinate (0,0,0) to 0
z(isnan(z)) = 0; % set coordinate (0,0,0) to 0
xP = reshape(x,[1, numel(x)]); % create a vector of the proportions of x
yP = reshape(y,[1, numel(y)]); % create a vector of the proportions of y
zP = reshape(z,[1, numel(z)]); % create a vector of the proportions of z
q = reshape(q,[1, numel(q)]); % create a vector of the dependent variable q
ternsurf(xP, yP, q); % plot the ternary surface of q against proportions
shading(gca, 'interp');
colorbar
view(2)
I believe you meant n(3) in your innermost loop. Here are a few tips:
1) Loose the loops:
q = exp(- ((x - 10).^2 + (y - 10).^2 + (z - 10).^2) / 20);
2) Loose the reshapes:
xP = x(:); yP = y(:); zP = z(:);
3) Check Total once, instead of doing three checks on x,y,z:
Total = x + y + z; % calculate the total of x,y,z at every point in the domain
Total( abs(Total) < eps ) = 1;
x = x ./ Total; % find the proportion of x at every point in the domain
y = y ./ Total; % find the proportion of y at every point in the domain
z = z ./ Total; % find the proportion of z at every point in the domain
PS: I just recognized your name.. it's Jonathan ;)
Discretization method probably depends on use of your plot, maybe it make sense to clarify your question from this point of view.
Overall, you probably struggling with an "Out of memory" error, a couple of relevant tricks are described here http://www.mathworks.nl/help/matlab/matlab_prog/resolving-out-of-memory-errors.html?s_tid=doc_12b?refresh=true#brh72ex-52 . Of course, they work only up to certain size of arrays.
A more generic solution is too save parts of arrays on hard drive, it makes processing slower but it'll work. E.g., you can define several q functions with the scale-specific ngrids (e.g. ngridOrder0=[0:10:100], ngridOrder10=[1:1:9], ngridOrder11=[11:1:19], etc... ), and write an accessor function which will load/save the relevant grid and q function depending on the part of the plot you're looking.
I have an ellipse in 2 dimensions, defined by a positive definite matrix X as follows: a point x is in the ellipse if x'*X*x <= 1. How can I plot this ellipse in matlab? I've done a bit of searching while finding surprisingly little.
Figured out the answer actually: I'd post this as an answer, but it won't let me (new user):
Figured it out after a bit of tinkering. Basically, we express the points on the ellipse border (x'*X*x = 1) as a weighted combination of the eigenvectors of X, which makes some of the math to find the points easier. We can just write (au+bv)'X(au+bv)=1 and work out the relationship between a,b. Matlab code follows (sorry it's messy, just used the same notation that I was using with pen/paper):
function plot_ellipse(X, varargin)
% Plots an ellipse of the form x'*X*x <= 1
% plot vectors of the form a*u + b*v where u,v are eigenvectors of X
[V,D] = eig(X);
u = V(:,1);
v = V(:,2);
l1 = D(1,1);
l2 = D(2,2);
pts = [];
delta = .1;
for alpha = -1/sqrt(l1)-delta:delta:1/sqrt(l1)+delta
beta = sqrt((1 - alpha^2 * l1)/l2);
pts(:,end+1) = alpha*u + beta*v;
end
for alpha = 1/sqrt(l1)+delta:-delta:-1/sqrt(l1)-delta
beta = -sqrt((1 - alpha^2 * l1)/l2);
pts(:,end+1) = alpha*u + beta*v;
end
plot(pts(1,:), pts(2,:), varargin{:})
I stumbled across this post while searching for this topic, and even though it's settled, I thought I might provide another simpler solution, if the matrix is symmetric.
Another way of doing this is to use the Cholesky decomposition of the semi-definite positive matrix E implemented in Matlab as the chol function. It computes an upper triangular matrix R such that X = R' * R. Using this, x'*X*x = (R*x)'*(R*x) = z'*z, if we define z as R*x.
The curve to plot thus becomes such that z'*z=1, and that's a circle. A simple solution is thus z = (cos(t), sin(t)), for 0<=t<=2 pi. You then multiply by the inverse of R to get the ellipse.
This is pretty straightforward to translate into the following code:
function plot_ellipse(E)
% plots an ellipse of the form xEx = 1
R = chol(E);
t = linspace(0, 2*pi, 100); % or any high number to make curve smooth
z = [cos(t); sin(t)];
ellipse = inv(R) * z;
plot(ellipse(1,:), ellipse(2,:))
end
Hope this might help!