I'm trying to plot a piece-wise function (of the form y = αx + β) on a single plot, such that for different regions on the x-axis, I have different values of α and β for the function.
I want to make the locations (on the x-axis) of these steps modifiable at will instead of having a predetermined number of such piece-functions. When plotted, it should ideally look like set of lines of different slopes and intercepts, each separated by a spacing. So if my spacing vector has 10 elements, I wrote my code such that I will correspondingly have 10 different piece-functions for different regions on the x-axis.
Here is the code that I wrote.
x = linspace(0,100,10000);
y = zeros(1,10000);
spacing = 0:10:100;
alpha = linspace(1,3,length(spacing)); %setting arbitrary upper lim
beta = linspace(1,5,length(spacing));
for j = 1:length(spacing)
for i=1:10000
if x(i) <= spacing(j)
y(i) = alpha(j)*x(i) + beta(j);
i = i + 1;
else
j = j + 1;
end
end
end
plot(x,y)
However, when I plot this, I get a single slope. It doesn't seem to be recognizing a change in spacing(j) due to the j = j + 1 iterator in the else statement
Any suggestions or help on how I should approach this would be much appreciated!
You should first iterate over x and then over spacing. Because for every element in x you are trying to find the correct interval. Then once you found that interval you should move to the next element of x and stop the iteration over spacing. You can do that using brake. If you don't do that then it will always choose the last interval, since x(i) <= spacing(end). See the code below:
x = linspace(0,100,10000);
y = zeros(1,10000);
spacing = 0:10:100;
alpha = linspace(1,3,length(spacing)); %setting arbitrary upper lim
beta = linspace(1,5,length(spacing));
for i=1:10000
for j = 1:length(spacing)
if x(i) <= spacing(j)
y(i) = alpha(j)*x(i) + beta(j);
break
end
end
end
plot(x,y)
ylim([0 max(y)])
The last line is to set y to start from 0.
Related
This code is meant to calculate the deflection of a beam with the principal of superposition, where for every given position og a beam, all the individual influences of forces are calculated, and then summed together.
function deflection = beamSuperposition(positions, beamLength,loadPositions, loadForces, beamSupport)
%If several loads are applied, calculate each one individually and end with sum
x = positions;
l = beamLength;
a = loadPositions;
W = loadForces;
E = 200*10^9;
I = 0.001;
%For every position(x) element calculate the expression for all
%loadPositions(a) and their respective loadForce(W)
%Make sure a and W are of same size
%Make sure neither x or a ever surpass l
%Go trhough each element of x
for i = 1:length(x)
%For beamSupport = 1 only
while beamSupport == 1
%Go through each element of 'a' and calculate the deflection
for n = 1:length(a)
%There are two different equations to calculating the deflection depending on the position of the loadForce compared to the position of interest
while true
if x(i) < a(n)
y = (W(n)*(l-a(n))*x(i))*(l^2-x(i)^2-(l-a(n))^2)/(6*E*I*l);
end
if x(i) >= a(i)
y = (W(n)*a(n)*(l-x(i)))*(l^2-(l-x(i))^2-a(n)^2)/(6*E*I*l);
end
break
end
end
break
end
%Sum the values for each y element?!?
deflection = y
end
How can I make this work as intended? The output should be a vector y with the same size as x with the summed deflections for each x value.
In use;
beamSuperposition([1,2,5],10,[6,5,3],[10,15,20],1)
Will return, if deflection = y is not supressed,
deflection =
5.8333e-07
deflection =
1.0967e-06
deflection =
1.6500e-06
ans =
1.6500e-06
But should return values as a vector instead of the last value only
I've made some small changes. Firstly I've changed the central two if statements to a single if else statement. This removed an error you had
if x(i) >= a(i)
which should have probably read
if x(i) >= a(n)
Whilst there I also removed some of your while break control flows which I didn't quite see the purpose of. You might want to compare.
Secondly I saved your outputs to the i-th entry of y. I also preallocated it so it doesn't change size in the loop.
Finally, as suggested by #StackPlayer I used ii for the loop variable instead of i. There is some discussion on the question Using i and j as variables in Matlab.
function deflection = beamSuperposition(positions, beamLength,loadPositions, loadForces, beamSupport)
%If several loads are applied, calculate each one individually and end with sum
x = positions;
l = beamLength;
a = loadPositions;
W = loadForces;
E = 200*10^9;
I = 0.001;
%For every position(x) element calculate the expression for all
%loadPositions(a) and their respective loadForce(W)
%Make sure a and W are of same size
%Make sure neither x or a ever surpass l
y = zeros(size(x));
%Go through each element of x
for ii = 1:length(x)
%For beamSupport = 1 only
if ( beamSupport == 1 )
%Go through each element of 'a' and calculate the deflection
for n = 1:length(a)
%There are two different equations to calculating the deflection depending on the position of the loadForce compared to the position of interest
if x(ii) < a(n)
y(ii) = (W(n)*(l-a(n))*x(ii))*(l^2-x(ii)^2-(l-a(n))^2)/(6*E*I*l);
else
y(ii) = (W(n)*a(n)*(l-x(ii)))*(l^2-(l-x(ii))^2-a(n)^2)/(6*E*I*l);
end
end
end
end
%Sum the values for each y element?!?
deflection = y;
end
Example use:
>> beamSuperposition([1,2,5],10,[6,5,3],[10,15,20],1)
ans =
1.0e-05 *
0.0583 0.1097 0.1650
First things first, avoid using i and j in MATLAB (they are used for the imaginary number).
In your second while loop, you have if conditions on "x" instead of "x(i)"
I have a three dimensional array of points.
I need to plot them on a 2D [x,z] grid, where every line is based on the value of Y inside a range.
es. the first line is made by points with 0 < y < 1, the second with 1 < y < 2, etc..
I can plot points just fine using this script(to have a better looking graph i'm also changing the color for every set of point by moving inside an rgb triplet).
set is the range of the line (in my case Y is time and i need to plot every 0.1 seconds). i is the index for my array of points.
w= 0;
yend = 100;
set = 0.1;
numberOfColors = 1/2*(Yinterval)*(1/set);
incrementOfColor = 1/numberOfColors;
red = 0;
green = 0;
blue = 1;
color=[red green blue];
while w < yend
while y(i)>w&&y(i)<w+set
figure(1)
hold on
plot(x(i),z(i),'.','Color',color);
hold on
i=i+1;
end
w=w+set;
if red < 1-incrementOfColor && blue > 0
red = red + incrementOfColor;
blue = blue - incrementOfColor;
end
if red > incrementOfColor && blue < incrementOfColor
red = red-incrementOfColor;
green = green + incrementOfColor;
blue = 0;
end
color = [red green blue];
end
And this is the result:
http://i.imgur.com/HTyzWai.png
When there's too much data the plot becomes cumbersome to read, and with too little data isolated points don't really tell much.
I've tried converting the points inside a "set" interval into an array but it really didn't work out:
while w < yend
while y(i)>w&&y(i)<w+set
vX(a,:)=x(i);
vZ(a,:)=z(i);
i=i+1;
a=a+1;
end
figure(2)
hold on
plot(vX,vZ,'-','Color',color);
Gave this result: imgur.com/S7OasUn.jpg
Is my conversion wrong or arrays are just not the proper way to handle this? If so, what should I use?
I'm rather new to matlab so if this is really obvious or i'm asking something in the wrong way, please excuse me.
edit:
This is the result i want to achieve:
imgur.com/jPZTO8E.png
and it was obtained with Origin's contour profile tool.
I guess you mean this with functional example:
myPoints[i]:
i=0, x = 1, y= 0.03, z = 1
i=1, x = 2, y= 0.06, z = 3
i=2, x = 2.5, y = 0.09, z = 4
i=3, x = 1.2, y = 1.01, z = 3.1
i=4, x = 1.3, y = 1.04, z = 1.1
i=5, x = 1.2, y = 1.06, z = 2.5
i=6, x = 2, y = 1.09, z = 3.1
i=7, x = 1.2, y = 2.02, z = 3.1
etc..
i want the points i 0,1,2 plotted as one line, i 3,4,5 as another line and i 7 etc.. plotted as a third line. In my data i have a lot of points.
this is one example of the data i'm using.
https://drive.google.com/file/d/0B9GHAkIYepQcRXdBdy03dFJtT1k/view?usp=sharing
where:
x = myPoints(:,1);
y = myPoints(:,2);
z = myPoints(:,3);
In this specific case, i only care about the points with y value between 85.85 and 90.85, and i want to "place an edge" (?) every 0.1
x = myPoints(:,1);
y = myPoints(:,2);
z = myPoints(:,3);
ymin = 85.85;
ymax = 90.85;
set = 0.1;
nbins = (ymax-ymin)/set;
binedge = linspace(ymin, ymax, (nbins + 1));
I think I'm understanding what you're attempting to accomplish and I believe you can accomplish your task with a vectorized use of plot rather than having to loop through each of your points.
Given your example data we can give this method a shot:
load('mypoints.mat');
x = myPoints(:,1);
y = myPoints(:,2);
z = myPoints(:,3);
% Bin your data by y values
ymin = 85.85;
ymax = 90.85;
set = 0.1;
nbins = (ymax-ymin)/set;
binedge = linspace(ymin, ymax, (nbins + 1));
[~, ~, binidx] = histcounts(y, binedge);
binloop = unique(binidx);
% Fix for error with unique. If you try to use a for loop with a column
% vector it passes the whole vector as your iterator, so you need to
% transpose it to a row vector.
temp = size(binloop);
if temp(1) ~= 1
binloop = binloop';
end
% Plot
figure
hold on
for ii = binloop
if ii == 0
% These fall outside of our bins, don't plot them
continue
else
dataidx = find(binidx == ii);
% Plot has its own color cycle, or you can add your color changing logic to this loop
plot(x(dataidx), z(dataidx), '-', 'LineWidth', 0.25);
end
end
hold off
What I've done here is to utilize the third output of histcounts to bin your y data and return a bin index for each value in your y vector.
To break the code down a bit:
Define your bin boundaries:
ymin = 85.85;
ymax = 90.85;
set = 0.1;
nbins = (ymax-ymin)/set;
binedge = linspace(ymin, ymax, (nbins + 1));
The linspace call returns the edges of each data bin. Given your example data we get binedge = [86.85, 86.95, 86.05, ..., 90.85]. We then plug in these edges and your y vector to histcounts to obtain our bin indices:
[~, ~, binidx] = histcounts(y, binedge);
Where the bins are defined per the documentation:
The value X(i) is in the kth bin if edges(k) ≤ X(i) < edges(k+1). The
last bin also includes the right bin edge, so that it contains X(i) if
edges(end-1) ≤ X(i) ≤ edges(end).
We can use unique to loop through all of the bins that are present. We can utilize find with MATLAB's logical indexing to plot all data from a single bin in each loop iteration. I ignore where ii == 0 as it indicates where data does not fall under one of the bins (and 0 index is meaningless in MATLAB).
I also played around a bit with the line sizes to try and make the plot a bit easier to read. There's a lot of data to visualize here but it helps a bit. You'll need to do a bit of pruning of your data since your x values wrap back, but that should be trivial.
I am actually attempting to write code for the cubic spline interpolation. Cubic spline boils down to a series of n-1 segments where n is the number of original coordinates given initially and the segments are each represented by some cubic function.
I have figured out how to get all the coefficients and values for each segment, stored in vectors a,b,c,d, but I don't know how to plot the function as a piecewise function on different intervals. Here is my code so far. The very last for loop is where I have attempted to plot each segment.
%initializations
x = [1 1.3 1.9 2.1 2.6 3.0 3.9 4.4 4.7 5.0 6 7 8 9.2 10.5 11.3 11.6 12 12.6 13 13.3].';
y = [1.3 1.5 1.85 2.1 2.6 2.7 2.4 2.15 2.05 2.1 2.25 2.3 2.25 1.95 1.4 0.9 0.7 0.6 0.5 0.4 0.25].';
%n is the amount of coordinates
n = length(x);
%solving for a-d for all n-1 segments
a = zeros(n,1);
b = zeros(n,1);
d = zeros(n,1);
%%%%%%%%%%%%%% SOLVE FOR a's %%%%%%%%%%%%%
%Condition (b) in Definition 3.10 on pg 146
%Sj(xj) = f(xj) aka yj
for j = 1: n
a(j) = y(j);
end
%initialize hj
h = zeros(n-1,1);
for j = 1: n-1
h(j) = x(j+1) - x(j);
end
A = zeros(n,n);
bv = zeros(n,1); %bv = b vector
%initialize corners to 1
A(1,1) = 1;
A(n,n) = 1;
%set main diagonal
for k = 2: n-1
A(k,k) = 2*(h(k-1) + h(k));
end
%set upper and then lower diagonals
for k = 2 : n-1
A(k,k+1) = h(k); %h2, h3, h4...hn-1
A(k,k-1) = h(k-1); %h1, h2, h3...hn
end
%fill up the b vector using equation in notes
%first and last spots are 0
for j = 2 : n-1
bv(j) = 3*(((a(j+1)-a(j)) / h(j)) - ((a(j) - a(j-1)) / h(j-1)));
end
%augmented matrix
A = [A bv];
%%%%%%%%%%%% BEGIN GAUSSIAN ELIMINATION %%%%%%%%%%%%%%%
offset = 1;
%will only need n-1 iterations since "first" pivot row is unchanged
for k = 1: n-1
%Searching from row p to row n for non-zero pivot
for p = k : n
if A(p,k) ~= 0;
break;
end
end
%row swapping using temp variable
if p ~= k
temp = A(p,:);
A(p,:) = A(k,:);
A(k,:) = temp;
end
%Eliminations to create Upper Triangular Form
for j = k+1:n
A(j,offset:n+1) = A(j,offset:n+1) - ((A(k, offset:n+1) * A(j,k)) / A(k,k));
end
offset = offset + 1;
end
c = zeros(n,1); %initializes vector of data of n rows, 1 column
%Backward Subsitution
%First, solve the nth equation
c(n) = A(n,n+1) / A(n,n);
%%%%%%%%%%%%%%%%% SOLVE FOR C's %%%%%%%%%%%%%%%%%%
%now solve the n-1 : 1 equations (the rest of them going backwards
for j = n-1:-1:1 %-1 means decrement
c(j) = A(j,n+1);
for k = j+1:n
c(j) = c(j) - A(j,k)*c(k);
end
c(j) = c(j)/A(j,j);
end
%%%%%%%%%%%%% SOLVE FOR B's and D's %%%%%%%%%%%%%%%%%%%%
for j = n-1 : -1 : 1
b(j) = ((a(j+1)-a(j)) / h(j)) - (h(j)*(2*c(j) + c(j+1)) / 3);
d(j) = (c(j+1) - c(j)) / 3*h(j);
end
%series of equation segments
for j = 1 : n-1
f = #(x) a(j) + b(j)*(x-x(j)) + c(j)*(x-x(j))^2 + d(j)*(x-x(j))^3;
end
plot(x,y,'o');
Let's assume that I have calculated vectors a,b,c,d correctly for each segment. How do I plot each cubic segment such that they all appear graphed on a single plot?
I appreciate the help.
That's pretty easy. You've already done half of the work by defining an anonymous function that is for the cubic spline in between each interval. However, you need to make sure that the operations in the function are element-wise. You currently have it operating on scalars, or assuming that we are using matrix operations. Don't do that. Use .* instead of * and .^ instead of ^. The reason why you need to do this is to make generating the points on the spline a lot easier, where my next point follows.
All you have to do next is define a bunch of x points within the interval defined by the neighbouring x key points and substitute them into your function, then plot the result.... so something like this:
figure;
hold on;
for j = 1 : n-1
f = #(x) a(j) + b(j).*(x-x(j)) + c(j).*(x-x(j)).^2 + d(j)*(x-x(j)).^3; %// Change function to element-wise operations - be careful
x0 = linspace(x(j), x(j+1)); %// Define set of points
y0 = f(x0); %// Find output points
plot(x0, y0, 'r'); %// Plot the line in between the key points
end
plot(x, y, 'bo');
We spawn a new figure, then use hold on so that when we call plot multiple times, we append the results to the same figure. Next, for each set of cubic spline coefficients we have, define a spline function, then generate a bunch of x values with linspace that are between the current x key point and the one beside it. By default, linspace generates 100 points between a start point (i.e. x(j)) and end point (i.e. x(j+1)). You can control how many points you want to generate by specifying a third parameter (so something like linspace(x(j), x(j+1), 25); to generate 25 points). We use these x values and substitute them into our spline equation to get our y values. We then plot this result on the figure using a red line. Once we're done, we plot the key points as blue open circles on top of the curve.
As a bonus, I ran your code with the above plotting mechanism, and this is what I get:
I have x[n] = {1,2,2,1,4} and −1 ≤ n ≤ 5
How do I plot y[n] = x[n] + y[n-1]?
I am new to matlab, and am not sure how to go about this.
This question does not seem well posed. Your vector for n in your first statement makes no sense (to me) in the context of your second statement.
If we ignore the first statement for n, your second statement appears to tell us how to build up a new value of y given x and given the previous previous of y. That's fine. You can easily solve for y with a for loop.
x = [1,2,2,1,4]; % this is your given input data
y = []; % this is your output
for I=1:length(x) % loop over each value of x
if (I==1) % the first time through is a special case
%assume that the previous value of y is zero
y(I) = x(I);
else
%your given equation
y(I) = x(I) + y(I-1);
end
end
y(:) %display y to the screen
The function y[n] = x[n] + y[n-1] is the sum (or discrete integration) of the signal x[n]. You can therefore remove the loop using the MATLAB command cumsum and come up with
x = [1,2,2,1,4];
y = cumsum(x);
stem(y); % plot y
I want to draw this figure on Matlab (without the bubbles)!
I wrote following code :
figure
hold on
axis equal
axis([0 20 0 10])
n = 20
n = n - 1
for y = 0:10
for x = (y+1):n
rectangle('Position',[x y 1 1],'curvature',[0 0],'facecolor',(rand(1,3)))
pause(0.05)
end
end
I get the following figure on executing this code :
I need help in writing part of the code where the correct figure can be drawn.
Your loop on x start at the right point but goes to the maximum at every iteration.
Just modify the loop definition for x = (y+1):n to for x = (y+1):n-y and you'll get the desired result:
for y = 0:10
for x = (y+1):n-y
rectangle('Position',[x y 1 1],'curvature',[0 0],'facecolor',(rand(1,3)))
pause(0.05)
end
end
edit: according to your comment, you wanted to achieve that by controling n, this is also possible but you have to decrement n at each iteration of the outer loop, like so:
for y = 0:10
for x = (y+1):n
rectangle('Position',[x y 1 1],'curvature',[0 0],'facecolor',(rand(1,3)))
pause(0.001)
end
n=n-1 ;
end