Reputation: 265
I need to plot this function in Matlab:
Lines must be connected, I mean at end of decreasing line, increasing one must start etc. It looks like this:
Any idea? I need it on some wide interval, for example t goes from zero to 10
Upvotes: 0
Views: 313
Reputation: 104474
The reason why it isn't working as expected is because for each curve you are drawing between multiples of 0.1
seconds, the y
-intercept is not being properly calculated and so the curves are not placed in the right location. For the first part of your curve, y = -57.5t
, the y
-intercept is at the origin and so your curve is y = -57.5t
as expected. However, when you reach 0.1
seconds, you need to solve for the y
-intercept for this new line with the new slope, as it has shifted over. Specifically:
y = 42.5t + b
We know that at t = 0.1
seconds, y = -5.75
given the previous curve. Solving for the y
-intercept gives us:
-5.75 = (42.5)(0.1) + b
b = -10
As such, between 0.1s <= t <= 0.2s
, your equation of the line is actually:
y = 42.5t - 10
Now, repeating the same procedure at t = 0.2s
, we have a new equation of the line, even though it has the same slope as the origin:
y = -57.5t + b
From the previous curve, we know that at t = 0.2
seconds, y = (42.5)(0.2) - 10 = -1.5
. Therefore, the intercept for this new curve is:
-1.5 = -(57.5)(0.2) + b
b = 10
Therefore, y = -57.5t + 10
is the curve between 0.2s <= t <= 0.3s
. If you keep repeating these calculations, you'll see that the next y
-intercept is -20
, then for the next one it's 20
, then the next one after that is -30
and so on. You see a nice multiple of 10 pattern for these calculations, and you'll see that the curve with the positive slope always has a negative y
-intercept that is a multiple of 10
, and the curve with the negative slope has a positive slope with a y
-intercept that is a multiple of -10
.
This is the pattern we need to keep in mind when plotting this curve. Because when you're plotting in MATLAB, we have to plot points discretely, you'll want to define a sampling time that defines the time resolution between each point. Because these are linear curves, you don't need that small of a sampling time, but let's choose 0.01
seconds for the sake of simplicity. This means that we will have 10 points between each new curve.
Therefore, for every 10 points in our plot, we will draw a different curve with a different y
-intercept for each curve. Because you want to draw points between 0
to 10
seconds, this means we will need (100)(10) = 1000
points. However, this does not include the origin, so you actually need 1001 points. As such, you'd define your t
vector like this:
t = linspace(0,10,1001);
Now, for every 10 points, we need to keep changing our y
intercept. At the first segment, the y
intercept is 0, the second segment, the y
intercept is 10
and so on. Now, a lot of MATLAB purists are going to tell you that for
loops are taboo, but when it comes to indexing operations, for
loops are amongst the fastest in timing in comparison to other more vectorized solutions. As an example, take a look at this post, where I implement a solution with a for
loop and it was the fastest amongst the other proposed solutions.
First let's define an array of slopes where each element tells us the slope per segment. Because we have 10 seconds worth of segments, and each segment is 0.1
seconds in length, including the origin we have 101 segments. At the origin, we have a slope of -57.5
. After this, our slopes alternate between 42.5
and -57.5
. Actually, this alternates 50 times. To create this array, we do:
m = [-57.5 repmat([42.5 -57.5], 1, 50)];
I use repmat
to repeat the [42.5 -57.5]
array 50 times for a total of 100 times, plus the -57.5
at the origin.
Now, let's define a y
-intercept vector that tells us what the y
intercept is at each segment.
y = zeros(1,101);
y(2:2:101) = 1;
y = 10*cumsum(y);
y(2:2:101) = -y(2:2:101);
The above code will generate a y
-intercept vector such that it starts at 0
, then has coefficients of -10, 10
, then -20, 20
, etc. The trick with this code is that I first generate a sequence of [0 1 0 1 0 1 0 1 0 1...]
. After, I use cumsum
, which does a cumulative summation where for each point in your array, it adds values from the beginning up until that point. Therefore, if we did cumsum
on this binary sequence, it would give us [0 1 1 2 2 3 3 4 4...]
. When we multiply this by 10, we get [0 10 10 20 20 30 30 40 40...]
. Finally, to complete the slopes, we just negate every even location in this array, and so we finally get [0 -10 10 -20 20 -30 30 -40 40...]
.
Now, here's the code we're going to use to generate our curve. We are going to iterate through each segment, and generate our output values with the y
-intercept taken into account. We first need to allocate an output array that will store our values, then we will populate the values per segment. We also need to keep track of which time values we are going to access to compute our output values.
As such:
%// Define time vector
t = linspace(0,10,1001);
%// Define slopes
m = [-57.5 repmat([42.5 -57.5], 1, 50)];
%// Define y-intercepts
y = zeros(1,101);
y(2:2:101) = 1;
y = 10*cumsum(y);
y(2:2:101) = -y(2:2:101);
%// Calculate the output curves for each segment
out = zeros(1, numel(t));
for idx = 1 : numel(y)-1
%// Compute where in the time array and output array
%// we need to write to
vals_to_access = (idx - 1)*10 + 1 : idx*10;
%// Create the curve for this segment
out(vals_to_access) = m(idx)*t(vals_to_access) + y(idx);
end
%// Copy second last value over to last value
out(end) = out(end-1);
%// Plot the curve
plot(t,out);
axis tight;
The trick with the for
loop is to know where to access the time values for each segment, and where to write these values to. That's the purpose of vals_to_access
. Also, note that the for
loop only populated values in the array from the first index up to the 1000th
index, but did not compute the 1001th
element. To make things simple, we'll just copy the element from the second last point to the last point, which is why out(end) = out(end-1);
is there. The above code will also plot the curve and makes sure that the axes are tightly bound. As such, this is what I get:
Upvotes: 1