Plot of function in Matlab - matlab

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

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:

Related

How to make multiple graphs with varying x-axis?

I need to plot multiple graphs in the same y-axis, but the x-axis is a bit tricky for me:
Assuming it goes from 0 to a, increasing by one, it needs to have an overall of a-1 different intervals.
Each one of them should finish at a, but it also has to have a different initialisation point. Only the first starts at 0, while each next one, starts by the previous plus one, as in the shape below. The two dashed lines, I used to visualise my thoughts as clear as I could, are not necessary.
I would appreciate any help!
Replicate your original interval 0 ... a a times (from my understanding, you'll have a intervals, not a-1), such that you get a matrix X of size [a x a+1]. Set the lower left triangle of X to NaN, so that the rows now represent your (shortening) intervals. Do your calculations on X. Pay attention, these have to support/neglect NaN values properly.
After that, you need to adjust the values in X properly, so that the intervals are plotted subsequently. Basically, we add some fixed value to each row.
Last, we need the proper xticks and xticklabels. Therefore, we extract all values from X and the modified X and get rid of the NaN values.
Here's a complete code snippet:
% Parameter
a = 7;
% Initialize intervals
X = repmat(0:a, a, 1);
X = X .* (ones(size(X)) + tril(nan(size(X)), -1));
% Calculation on these intervals; attention: there are NaN in X
Y = sin(X / a * 2 * pi);
% Modify X for plotting
X_plot = X;
X_plot(2:end, :) = X_plot(2:end, :) + cumsum(a:-1:2).';
% Get xticks
xt = X_plot.';
xt = xt(:);
xt(isnan(xt)) = [];
% Get xticklabels
xtl = X.';
xtl = xtl(:);
xtl(isnan(xtl)) = [];
% Plot
plot(X_plot.', Y.');
xticks(xt);
xticklabels(xtl);
The output (Octave 5.1.0, also tested with MATLAB Online) looks like this:
If you only want for example the start and end of each interval, you must further pre-process xt and xtl.
Hope that helps!

Change limits of a time signal at matlab

i am a beginner an have an easy question. I have a signal on y-axis and time signal on x-axis. I need to change boundaries of the time signal. It's between 0 and 18 seconds, but i want to change in between 5 and 10. I used already "xlim", it work for plot but actually i want to create a new time signal.
Any idea? Thank you!
Since you didn't post your code I'll need to make some assumptions. I'll assume you have your data stored in row vectors x and y and that x is uniform and monotonically increasing.
1. Construct a truncated signal using logical indexing.
index = x >= 5 & x <= 10;
x_new = x(index);
y_new = y(index);
plot(x_new, y_new);
The above only takes a subset of the data, if x doesn't contain 5 and 10 then the plot will be truncated. If you're dealing with time series data this is probably the most reasonable approach since it doesn't change the sampling rate.
2. Re-sampling the signal between 5 and 10 using interpolation.
num_samples = 100;
x_new = linspace(5, 10, num_samples);
y_new = interp1(x, y, x_new);
plot(x_new, y_new);
This may not exactly match the original plot since the original samples aren't guaranteed to be included. However it will exactly span the desired domain.
3. If you don't care that x is uniform but want to create a plot that exactly matches the original then you can append the bounds of x to the subset from method 1 and use interp1 to sample y.
x_min = 5; x_max = 10;
index = x > x_min & x < x_max;
x_new = [x_min, x(index), x_max];
y_new = interp1(x, y, x_new);
plot(x_new, y_new);
Example
Example demonstrating the differences between the different methods, plotted with additional offset and markings at samples for clarity.
If you want to delete the elements n from the back of a vector y and store the result in y_cut, you should be able to do that with:
y_cut = y(1:end-n);
It would be important to know in which form you stored the time signal.
If you have one value for each second the solution would be:
y_cut = y(5:10);
But I assume you're storing your y-values as samples with a given sample rate fs
One second would then be equal to fs (for example 44100 for a CD audio file, resulting in 44100 samples per second) and the solution would be:
y_cut = y(5*fs:10*fs);
I hope I could help.
Cheers,
Simon

Plotting a linear decision boundary

I have a set of data points (40 x 2), and I've derived the formula for the decision boundary which ends up like this :
wk*X + w0 = 0
wk is a 1 x 2 vector and X is a 2 x 1 point from the data point set; essentially X = (xi,yi), where i = 1,2,...,40. I have the values for wk and w0.
I'm trying to plot the line wk*X + w0 = 0 but I have no idea how to plot the actual line. In the past, I've done this by finding the minimum and maximum of the data points and just connecting them together but that's definitely not the right approach.
wk*X is simply the dot product between two vectors, and so the equation becomes:
w1*x + w2*y + w0 = 0
... assuming a general point (x,y). If we rearrange this equation and solve for y, we get:
y = -(w1/w2)*x - (w0/w2)
As such, this defines an equation of the line where the slope is -(w1/w2) with an intercept -(w0/w2). All you have to do is define a bunch of linearly spaced points within a certain range, take each point and substitute this into the above equation and get an output. You'd plot all of these output points in the figure as well as the actual points themselves. You make the space or resolution between points small enough so that we are visualizing a line when we connect all of the points together.
To determine the range or limits of this line, figure out what the smallest and largest x value is in your data, define a set of linearly spaced points between these and plot your line using the equation of the line we just talked about.
Something like this could work assuming that you have a matrix of points stored in X as you have mentioned, and w1 and w2 are defined in the vector wk and w0 is defined separately:
x = linspace(min(X(:,1)), max(X(:,1)));
y = -(wk(1)/wk(2))*x - (w0/wk(2));
plot(X(:,1), X(:,2), 'b.', x, y);
linspace determines a linearly spaced array of points from a beginning to an end, and by default 100 points are generated. We then create the output values of the line given these points and we plot the individual points in blue as well as the line itself on top of these points.

How do I track when multiple objects touch in MATLAB?

I have x,y pixel coordinates of multiple objects that have been tracked from an image (3744x5616). The coordinates are stored in a structure called objects, e.g.
objects(1).centre = [1868 1236]
The objects are each uniquely identified by a numerical code, e.g.
objects(i).code = 33
I want to be able to record each time any two objects come within a radius of 300 pixels each other. What would be the best way to check through if any objects are touching and then record the identity of both objects involved in the interaction, like object 33 interacts with object 34.
Thanks!
Best thing I can think of right now is a brute force approach. Simply check the distances from one object's centre with the rest of the other objects and manually check if the distances are < 300 pixels.
If you want this fast, we should probably do this without any toolboxes. You can intelligently do this with vanilla MATLAB using bsxfun. First, create separate arrays for the X and Y coordinates of each object:
points = reshape([objects.centre], 2, []);
X = points(1,:);
Y = points(2,:);
[objects.centre] accesses the individual coordinates of each centre field in your structure and unpacks them into a comma-separated list. I reshape this array so that it is 2 rows where the first row is the X coordinate and the second row is the Y coordinate. I extract out the rows and place them into separate arrays.
Next, create two difference matrices for each X and Y where the rows denote one unique coordinate and the columns denote another unique coordinate. The values inside this matrix are the differences between the point i at row i and point j at column j:
Xdiff = bsxfun(#minus, X.', X);
Ydiff = bsxfun(#minus, Y.', Y);
bsxfun stands for Binary Singleton EXpansion FUNction. If you're familiar with the repmat function, it essentially replicates matrices and vectors under the hood so that both inputs you're operating on have the same size. In this case, what I'm doing is specifying X or Y as both of the inputs. One is the transposed version of the other. By doing this bsxfun automatically broadcasts each input so that the inputs match in dimension. Specifically, the first input is a column vector of X and so this gets repeated and stacked horizontally for as many times as there are values in X.
Similarly this is done for the Y value. After you do this, you perform an element-wise subtraction for both outputs and you get the component wise subtraction between one point and another point for X and Y where the row gives you the first point, and the column gives you the second point. As a toy example, imagine we had X = [1 2 3]. Doing a bsxfun call using the above code gives:
>> Xdiff = bsxfun(#minus, [1 2 3].', [1 2 3])
Xdiff =
## | 1 2 3
----------------------
1 | 0 -1 -2
2 | 1 0 -1
3 | 2 1 0
There are some additional characters I placed in the output, but these are used solely for illustration and to give you a point of reference. By taking a row value from the ## column and subtracting from a column value from the ## row gives you the desired subtract. For example, the first row second column illustrates 1 - 2 = -1. The second row, third column illustrates 2 - 3 = -1. If you do this for both the X and Y points, you get the component-wise distances for one point against all of the other points in a symmetric matrix.
You'll notice that this is an anti-symmetric matrix where the diagonal is all 0 ... makes sense since the distance of one dimension of one point with respect to itself should be 0. The bottom left triangular portion of the matrix is the opposite sign of the right... because of the order of subtraction. If you subtracted point 1 with point 2, doing the opposite subtraction gives you the opposite sign. However, let's assume that the rows denote the first object and the columns denote the second object, so you'd want to concentrate on the lower half.
Now, compute the distance, and make sure you set either the upper or lower triangular half to NaN because when computing the distance, the sign gets ignored. If you don't ignore this, we'd find duplicate objects that interact, so object 3 and object 1 would be a different interaction than object 1 and object 3. You obviously don't care about the order, so set either the upper or lower triangular half to NaN for the next step. Assuming Euclidean distance:
dists = sqrt(Xdiff.^2 + Ydiff.^2);
dists(tril(ones(numel(objects))==1)) = NaN;
The first line computes the Euclidean distance of all pairs of points and we use tril to extract the lower triangular portion of a matrix that consists of all logical 1. Extracting this matrix, we use this to set the lower half of the matrix to NaN. This allows us to skip entries we're not interested in. Note that I also set the diagonal to 0, because we're not interested in distances of one object to itself.
Now that you're finally here, search for those objects that are < 300 pixels:
[I,J] = find(dists < 300);
I and J are row/column pairs that determine which rows and columns in the matrix have values < 300, so in our case, each pair of I and J in the array gives you the object locations that are close to each other.
To finally figure out the right object codes, you can do:
codes = [[objects(I).code].' [objects(J).code].'];
This uses I and J to access the corresponding codes of those objects that were similar in a comma-separated list and places them side by side into a N x 2 matrix. As such, each row of codes gives you unique pairs of objects that satisfied the distance requirements.
For copying and pasting:
points = reshape([objects.centre], 2, []);
X = points(1,:);
Y = points(2,:);
Xdiff = bsxfun(#minus, X.', X);
Ydiff = bsxfun(#minus, Y.', Y);
dists = sqrt(Xdiff.^2 + Ydiff.^2);
dists(tril(ones(numel(objects))==1)) = NaN;
[I,J] = find(dists < 300);
codes = [[objects(I).code].' [objects(J).code].'];
Toy Example
Here's an example that we can use to verify if what we have is correct:
objects(1).centre = [1868 1236];
objects(2).centre = [2000 1000];
objects(3).centre = [1900 1300];
objects(4).centre = [3000 2000];
objects(1).code = 33;
objects(2).code = 34;
objects(3).code = 35;
objects(4).code = 99;
I initialized 4 objects with different centroids and different codes. Let's see what the dists array gives us after we compute it:
>> format long g
>> dists
dists =
NaN 270.407100498489 71.5541752799933 1365.69396278961
NaN NaN 316.227766016838 1414.2135623731
NaN NaN NaN 1303.84048104053
NaN NaN NaN NaN
I intentionally made the last point farther than any of the other three points to ensure that we can show cases where there are points not near other ones.
As you can see, points (1,2) and (1,3) are all near each other, which is what we get when we complete the rest of the code. This corresponds to objects 33, 34 and 35 with pairings of (33,34) and (33,35). Points with codes 34 and 35 I made slightly smaller, but they are still greater than the 300 pixel threshold, so they don't count either:
>> codes
codes =
33 34
33 35
Now, if you want to display this in a prettified format, perhaps use a for loop:
for vec = codes.'
fprintf('Object with code %d interacted with object with code %d\n', vec(1), vec(2));
end
This for loop is a bit tricky. It's a little known fact that for loops can also accept matrices and the index variable gives you one column of each matrix at a time from left to right. Therefore, I transposed the codes array so that each pair of unique codes becomes a column. I just access the first and second element of each column and print it out.
We get:
Object with code 33 interacted with object with code 34
Object with code 33 interacted with object with code 35

Logic of this FWHM script?

Could someone explain the logic of this program.
I dont understand why the y=y/max(y)
and,
interp = (0.5-y(i-1)) / (y(i)-y(i-1));
tlead = x(i-1) + interp*(x(i)-x(i-1));
The script:
function width = fwhm(x,y)
y = y / max(y);
N = length(y);
MicroscopeMag=10;
PixelWidth=7.8; % Pixel Pitch is 7.8 Microns.
%------- find index of center (max or min) of pulse---------------%
[~,centerindex] = max(y);% 479 S10 find center peak and coordinate
%------- find index of center (max or min) of pulse-----------------%
i = 2;
while sign(y(i)-0.5) == sign(y(i-1)-0.5) %trying to see the curve raise
i = i+1; %474 S10
end %first crossing is between v(i-1) & v(i)
interp = (0.5-y(i-1)) / (y(i)-y(i-1));
tlead = x(i-1) + interp*(x(i)-x(i-1));
i=centerindex+1; %471
%------- start search for next crossing at center--------------------%
while ((sign(y(i)-0.5) == sign(y(i-1)-0.5)) && (i <= N-1))
i = i+1;
end
if i ~= N
interp = (0.5-y(i-1)) / (y(i)-y(i-1));
ttrail = x(i-1) + interp*(x(i)-x(i-1));
%width = ttrail - tlead; % FWHM
width=((ttrail - tlead)/MicroscopeMag)*PixelWidth;
% Lateral Magnification x Pixel pitch of 7.8 microns.
end
Thanks.
The two segments of code you specifically mention are both housekeeping: it's more about the compsci of it than the optics.
So the first line
y = y/max(y);
is normalising it to 1, i.e. dividing the whole series through by the maximum value. This is a fairly common practice and it's sensible to do it here, it saves the programmer from having to divide through by it later.
The next part,
interp = (0.5-y(i-1)) / (y(i)-y(i-1));
tlead = x(i-1) + interp*(x(i)-x(i-1));
and the corresponding block later on for ttrail, are about trying to interpolate the exact point(s) where the signal's value would be 0.5. Earlier it identifies the centre of the peak and the last index position before half-maximum, so now we have a range containing the leading edge of the signal.
The 'half-maximum' criterion requires us to find the point where that leading edge's value is 0.5 (we normalised to 1, so the half-maximum is by definition 0.5). The data probably won't have a sample at exactly that value - it'll go [... 0.4856 0.5024 ...] or something similar.
So these two lines are an attempt to determine in fractions of an index exactly where the line would cross the 0.5 value. It does this by simple linear interpolation:
y(i)-y(i-1)
gives us the delta_y between the two values either side, and
0.5-y(i-1)
gives us the shortfall. By taking the ratio we can linearly interpolate how far between the two index positions we should go to hit exactly 0.5.
The next line then works out the corresponding delta_x, which gives you the actual distance in terms of the timebase.
It does the same thing for the trailing edge, then uses these two interpolated values to give you a more precise value for the full-width.
To visualise this I would put a breakpoint at the i = 2 line and step through it, noting or plotting the values of y(i) as you go. stem is helpful for visualising discrete data, especially when you're working between index positions.
The program computes the resolution of a microscope using the Full Width at Half Maximum (FWHM) of the Point Spread Function (PSF) characterizing the microscope with a given objective/optics/etc.
The PSF normally looks like a gaussian:
and the FWHM tells you how good is your microscope system to discern small objects (i.e. the resolution). Let's say you are looking at 2 point objects, then the resolution (indirectly FWHM) is the minimum size those objects need to be if you are indeed to tell that there are 2 objects close to one another instead of one big object.
Now for the above function, it looks like it first compute the maximum of the PSF and then progressively goes down along the curve until it approximately reaches the half maximum. Then it's possible to compute the FWHM from the distribution of the PSF.
Hope that makes things a bit clearer!