Plotting equation in Matlab using for loop - matlab

I want to plot an equation using a for-loop. I have tried several different ways, but keep getting the apparently common error "Subscript indices must either be real positive integers or logicals". The equation I want to plot is y(x) = (x^4)-(4*x^3)-(6*x^2)+15.
The last code I tried was the following:
y(0) = 15;
for x = [-3 -2 -1 0 1 2 3 4 5 6];
y(x) = (x^4)-(4*x^3)-(6*x^2)+15;
end
plot(x,y)

To start from the beginning,
y(0) = 15;
will give you the following error:
Subscript indices must either be real positive integers or logicals.
This is because Matlab's indexing starts at 1. Other languages like C and Python start at 0.
Matlab can work directly with vectors. So in your code, there is no need for a loop at all.
You can do it like this:
x = [-3 -2 -1 0 1 2 3 4 5 6];
y = (x.^4) - (4*x.^3) - (6*x.^2) + 15;
plot(x, y);
Note that we need to use element-wise operators like .* and .^ to calculate the values vectorized for every element. Therefore a point . is written in front of the operator.
Additionally, we can improve the code substantially by using the colon operator to generate x:
x = -3:6; % produces the same as [-3 -2 -1 0 1 2 3 4 5 6]
y = (x.^4) - (4*x.^3) - (6*x.^2) + 15;
plot(x, y);
If you want finer details for your graph, use linspace as suggested by #Yvon:
x = linspace(-3, 6, 100); % produces a vector with 100 points between -3 and 6.
y = x.^4-4*x.^3-6*x.^2+15;
plot(x,y)

x = linspace(-3, 6, 100);
y = x.^4-4*x.^3-6*x.^2+15;
plot(x,y)

Related

Shifting time of a signal

Considering a signal x = t.*(2*t + 4)
In case I want to time shift the signal -let's say 2 time-values to the right- is it possible to do something like
x = x(t-2)
In order to shift all the values ?
I stumbled across circshift but I didn't find any use for my case
EDIT: I'm searching for a solution where it will work for every signal, as an example if I reflect x (or do anything on it) and store it on Y, how should I time shift Y?
You can define the signal as a function, so that you can then shift it as you wish.
For instance,
x = #(t) t.*(2*t + 4); % A function x(t)
y = #(t) x(-t); % A reflected version of the function
z = #(t,a) x(t-a); % A delayed version of the function
t = -5:0.01:5; % Sampling instants
X = x(t); % A vector of samples of the original signal
Y = x(t-2); % A vector of samples of the delayed signal
Note that if you want to define operators that can reflect and shift any function, you can e.g. write
Rop = #(s,t) s(-t);
Sop = #(s,a,t) s(t-a);
And you can use them on the x signal as
Rop(x,[-2 -1 0 1 2]) % Calculates x([2 1 0 -1 -2])
Sop(x,5,[1 2 3 4 5]) % Calculates x([-4 -3 -2 -1 0])
If you want to combine shifting and reflection, you can do like this:
Rop(#(t) Sop(x,2,t),[1 2 3 4 5]) % First shifts x by 2, then reflects
Sop(#(t) Rop(x,t),2,[1 2 3 4 5]) % First reflects x, and then shifts by 2
If you run the above code you will see that reflection and shift are not commutative because the resulting vectors are different.

Matlab generate smooth curve between scatter points

I need to generate a curve between scatter points then identify the unit normal of the curve at each point. Here is an example of a point cloud
figure
x = [1 2 0 0 1 1 2 3 4 2];
y = [4 6 9 1 1 2 4 9 2 3];
scatter(x,y)
hold on
line(x,y)
xlim([0 4])
ylim([0 10])
NOTE: the 2 points along the y-axis are connected
Instead of a line between the points, I'd like to create a smooth curve. I'm not sure how to do this when points in x and y repeat. An attempt using spline fails. After I know the curve, I need to find the unit normals at each point. How do I go about this?
EDIT:
Basically I want to do what is show here for polyfit in the matlab docs. Assuming that x was unique in my case, this wouldn't be an issue. I could identify the polynomial and then, I believe, determine the unit normals from the polynomial function evaluated at that point. But in my case, the x and y data repeat so a straight forward application doesn't work.
One way to get a smooth path is to treat this as a parametric function and interpolate x and y separately.
x = [1 2 0 0 1 1 2 3 4 2];
y = [4 6 9 1 1 2 4 9 2 3];
t = 1:numel(x);
tq = 1:0.1:t(end);
xq = interp1(t,x,tq,'v5cubic');
yq = interp1(t,y,tq,'v5cubic');
plot(x,y,' ob',xq,yq,'-r');
To estimate the normals you can take the average normal of the two line segments around the sample points. This code is a bit ugly but it gets the job done.
n = zeros(2,numel(x));
for tidx = 1:numel(t)
tt = t(tidx);
idx1 = find(tq <= tt,1,'last');
idx0 = idx1 - 1;
idx2 = idx1 + 1;
if idx0 > 0
n1 = [yq(idx1) - yq(idx0); xq(idx0) - xq(idx1)];
n(:,tidx) = n(:,tidx) + n1/norm(n1);
end
if idx2 <= numel(tq)
n2 = [yq(idx2) - yq(idx1); xq(idx1) - xq(idx2)];
n(:,tidx) = n(:,tidx) + n2/norm(n2);
end
n(:,tidx) = n(:,tidx) / norm(n(:,tidx));
end
plot(x,y,' ob',xq,yq,'-r',[x.' x.'+n(1,:).'].', [y.' y.'+n(2,:).'].',' -k');
axis equal;
If you use pchip instead of v5cubic for the interpolation method then you get more symmetry around the sample points. However, it appears that any sharp turns (90 degrees or greater) are not smoothed.

Clampled cubic splines with flat extrapolation

I am trying to implement a clamped cubic spline with a zero slope (flat extrapolation) at the boundary knots, but I am unable to obtain the desired results.
For instance setting:
x = [3 4 7 9];
y = [2 1 2 0.5];
I can use the CSAPE function to obtain the piecewise polynomial
pp = csape(x,y,'variational');
Next, evaluating the pp in the range [0-10] yields,
xx = 0:0.1:10;
yy =ppval(pp,xx);
plot(xx,yy)
However, this method do not achieve a flat extrapolation outside the [3-9] range (i.e for x<3 all values for y should be 2, and for x>9 all values for y should be 0.5)
Is there any way to achieve the desired result?
Edit: Continuity at the boundary knot should be preserved
I don't think there's any need to use csape, you can just use spline. From the documentation for spline:
If Y is a vector that contains two more values than x has entries, the
first and last value in Y are used as the endslopes for the cubic
spline.
Also, spline allows you to obtain the interpolated yy values directly, so:
x = [3 4 7 9];
y = [2 1 2 0.5];
xx = 0:0.1:10;
yy = spline(x,[0 y 0], xx);
plot(xx,yy)
This gives me the plot below.
Looking at this, the slope is zero at the boundaries (x=3 and x=9), which is what we are asking of a 'clamped' spline with zero gradient at the boundaries. If you wish to have zero gradient beyond the boundaries, I would recommend just doing the following:
yy(xx<x(1)) = y(1);
yy(xx>x(length(x))) = y(length(y));
Giving:
Edit
This gives a continuous y function at the end-knots, but y' is not smooth at the end-knots. If you would like y' to be smooth you could pad your input arrays and use this as the input to your spline function. This would give you some oscillations as shown below, though, which may or may not be what you want.
% Spline on padded input arrays
x = [0 1 2 3 4 7 9 10 11 12];
y = [2 2 2 2 1 2 0.5 0.5 0.5 0.5];
yy = spline(x,y, xx);

Get list of Y's on linspace from X's and Y's arrays in Matlab

I have two arrays - X points and Y points. X array have some spaces (e. g. [0 1 2 6 7 8]), and Y array contains only values for that Xes. I've got that array as a local maxima from wavelet transform. I can plot it with plot(X,Y)
Now I want to get Y's on linspace - Y must contain values for any X from 0 to 8. I want to have the same plot plot(Y) as the previous plot(X, Y).
How can I do this?
It looks like you want to perform interpolation
xPts = [0 1 2 6 7 8];
yPts = ...
xPlot = 0:1:8;
yPlot = interp1(xPts,yPts,xPlot,'cubic')
plot(xPlot,yPlot)
Check the documentation for interp1 for the different interpolation schemes.
If there are repeated x-values, you can average the corresponding y-values
xPtsRep = [0 0 1 2 6 7 7 8]
yPtsRep = ...
[xPts,~,xIdx] = unique(xPtsRep);
yPts = accumarray(xIdx,yPtsRep,[],#mean);

Gurobi solver in matlab

I want to use Gurobi solver in Matlab, but I don't know how to calculate the required matrices (qrow and qcol).
For your reference I am copying the example provided in documentation.
0.5 x^2 - xy + y^2 - 2x - 6y
subject to
x + y <= 2
-x + 2y <= 2, 2x + y <= 3, x >= 0, y >= 0
c = [-2 -6]; % objective linear term
objtype = 1; % minimization
A = sparse([1 1; -1 2; 2 1]); % constraint coefficients
b = [2; 2; 3]; % constraint right-hand side
lb = []; % [ ] means 0 lower bound
ub = []; % [ ] means inf upper bound
contypes = '$<<
vtypes = [ ]; % [ ] means all variables are continuous
QP.qrow = int32([0 0 1]); % indices of x, x, y as in (0.5 x^2 - xy + y^2); use int64 if sizeof(int) is 8 for you system
QP.qcol = int32([0 1 1]); % indices of x, y, y as in (0.5 x^2 - xy + y^2); use int64 if sizeof(int) is 8 for you system
QP.qval = [0.5 -1 1]; % coefficients of (0.5 x^2 - xy + y^2)
Does it mean that if I have 4 decision variables than i should use 0,1,2,3 as indices for my decision variables x_1, x_2, x_3, x_4.?
Thanks
Note: I tried to use mathurl.com but I don't get how to write in proper format show that it will appear as latex text. Sorry for the notation.
This seems to be your reference. However your question seems to relate different example. You may need to show that one.
Anyway according Gurobi documentation:
The quadratic terms in the objective function should be specified by opts.QP.qrow, opts.QP.qcol, and opts.QP.qval, which correspond to the input arguments qrow, qcol, and qval of function GRBaddqpterms. They are all 1D arrays. The first two arguments, qrow and qcol, specify the row and column indices (starting from 0) of 2nd-order terms such as and . The third argument, qval, gives their coefficients.
So the answer is yes use indicies [0 1 2 3] for your decision variables x0, x1, x2, x3.