I have n vectors which i want to "stretch" into a start- and stopvalues.
Like this: Example of linear mapping. In this example n=4 where "in" is the original values and "ut" is the desired values.
What would be the best way to go about doing this?
Example:
I have a vector of 35535 elements sorted in ascending order. The lowest value is 0.09 and the highest 0.36. I also have two start and stop values, 0 and 0.5, (n is 2, 2 segments).
What i want is to "stretch" the values in my vector to reach from 0.09-0.36 to 0.5 while keeping their relative distance to eachother.
Edit:
Another image to try and make it clearer
n is 2,
n is 4,
Edit 2:
Another image
After spending some time thinking of my problem I realized I was getting distracted by "Linear mapping" and that the solution to what i wanted to do was simply using
Y = kx+m. Where i calculate Y and keep my "x" value.
For example:
If my startvalue is 0/stopvalue is 0.5 and lowest value is 0.09/highest value is 0.36. Then k = (0.5-0)/(0.36-0.09), m = 0-k*0.09.
Then y = k * x + m. If we put in 0.09 in x we get very close to 0. If x is 0.36, y is 0.5.
I was working with images and for me it was important to remember to keep the y AND x values so that i could reassemble the image after the operation.
Related
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:
I am charting the following data:
a=[...
0.1, 0.7, 0.00284643369242828;...
0.1, 0.71, 0.00284643369242828;...]
such that column 1 never surpasses approximately 10
also such that column 2 goes from .7 to 1.
Column 3 seems ok
When i chart my surface using surf(a) it looks like this:
it appears not to be properly considering what should be x and y.
anything seem weird there?
I think you need to try one of two things: either break out your height column into its own rectangular matrix Z and use surf(Z) to plot each point relative to its location in the matrix (so your x- and y-axes will not be scaled the way you want), or you can put your desired x- and y-coordinates in their own vectors, and plot the matrix Z (defined at every point (xi, yj) for all i in N and j in M where x is N elements long and y is M elements long) with surf(x,y,Z).
x = 0.1:0.1:10; % or whatever increment you need
y = 0.7:0.01:1; % or whatever increment you need
Z = zeros(length(x),length(y); % initialized to the correct size, fill with data
I think you are going to have to regenerate your Z-data so that it is in a rectangular matrix that is (elements in x) by (elements in y) in dimension.
EDIT: You do not need to recreate your data. If you know that you have n unique elements in x and m unique elements in y, then you can use:
X = reshape(data(:,1),m,n);
Y = reshape(data(:,2),m,n);
Z = reshape(data(:,3),m,n);
surf(X,Y,Z);
And that should give you what you are looking for.
I have measured a variable x in equidistant long intervals (every 10 min) and a variable y in non-equidistant short intervals (somewhere between every 30 s and 90 s). Timestamps (datenum) for both x and y are available, but they are never equal, so intersect doesn't work. How can I aggregate y (e.g. mean(y(...)) in interval x(i+1) - x(i)) so I can compare the two (e.g. plot them against each other or plot them with the same time-vector)?
/edit 1: Confused x and y in my last but one sentence.
/edit 2: I feel like I didn't give you enough information in the original question, sorry for that.
Many of you suggest interpolation. x is an average wind speed over a period of 10 minutes, not a distinct measurement. So if I say time = 07:10 and x = 3 m/s, that means mean(x) = 3 m/s for the period from 07:00 to 07:10. This is why I think it's probably not the best idea to interpolate it. y is one of many (very noisy) other variables and I want to find out the influence of (mean) x on y. So I would either like to assign many values of y to one measurement of x (in that 10 minute period), or assign a mean(y) to that one measurement of x. I assume that the solutions are quite similar, code wise.
Reading the edited (2x) question:
You are trying to estimate the value of x at some point that you don't have the measurement for. You have measurements before and after. The only thing you can do is to interpolate. What method you choose is somewhat harder to decide.
Your options are:
piecewise constant interpolation (what I think you are suggesting)
linear interpolation
spline
others
/edit: If you just want to get an average value of y between two x measurements, I suggest the following:
new_y = zeros(size(x));
new_y(1) = mean(y(ty<=tx(1)));
for ii=2:length(x):
new_y(ii) = mean(y(and(ty>tx(ii-1),ty<=tx(ii))));
end
Maybe an even better solution would be using hist:
n = hist(ty,tx)
Vector n contains the number of values of ty that are closest to values in tx. Since both are monotonous, n tells you how to group values in y. Then you can use mat2cell to put y into a cell array where each cell corresponds to one measurement of x. The second parameter n now specifies how many values to put in each cell.
new_y = mat2cell(y,n)
To aggregate values, use accumarray:
accumarray(fix(ty(:) / T) + 1, y, [], #mean)
Here y is the sampled signal, ty is the timestamp array and T is the time interval of the aggregated values (for example, T = 10 / (24 * 60) = 0.0069 for a 10-minute interval).
You can interpolate data from x to non-equidistant timestamps (or vice versa) (see interp1 function) and compare results.
Plot:
plot(Time_x, x, Time_y, y)
Here's a simple example of using the 1-d interpolation.
# make two example functions on different x bases.
x1 = [0:.023:10];
x2 = [0:1:10];
y1 = x1.^2/10;
y2 = 10 - x2.^1.3;
# convert both to a common x base (x1 in this case).
y2i = interp1(x2,y2,x1);
plot(x1,y1,x1,y2i)
Use linear interpolation!
Its easy & fun to do yourself. The idea is: Since you know the timestamps for x, the values for x, and the values for y, (but the timestamps for y don't match that of x), you can use linear interpolation (or of higher order if you need) to interpolate/"update" values for y as if they occured at the timestamps of x. After that you can plot both x and interpolated y values against the same x timestamp vector.
see: http://en.wikipedia.org/wiki/Linear_interpolation
I have a bunch of values in a 3-dimensional matrix, and I am finding the mean value of them:
mean(mean(mat))
Now, of different reasons I have to append some rows and elements to the matrix. But I want the mean value to stay the same - as if the added elements are neutral and do not inflict in the result.
Like when you multiply a bunch of values, you can multiply additional 1's without changing the result. And with addition you can add further 0's with no inflict.
What kind of value in Matlab can I assign to the new elements in the matrix to make the elements neutral when using the mean()?
Note added
The point is, when I am calculating the mean value I only have the new resized matrix to do it from. Therefore the added elements must be neutral.
I am thinking of something like NaN, but I had no luck with that since the mean value then also end up as NaN.
Adding values equal to the mean of the matrix without the added values will leave the new mean the same. (I hope that makes sense!). Point is to fill in and not change the new mean, use the current mean.
Alternatively, you can fill in with NaN and use the nanmean function.
Add zeros to the matrix and rescale your mean to be the correct value.
i.e. if your original matrix A is n x m and you resize to B which is N x M then :
mean(mean(A)) = sum(sum(A)) / n x m
mean(mean(B)) = sum(sum(B)) / N x M
= sum(sum(A)) / N x M --- since we padded with zeros
Rearranging gives
mean(mean(A)) = mean(mean(B)) * ( ( N x M )/(n x m) )
I have a vector of coordinates called x. I want to get the element(s) with the min y coordinate:
a = find(x(:,2)==min(x(:,2))); % Contains indices
This returns the indexes of the elements with the smallest y coordinates. I say element*s* because sometimes this would return more than 1 value (e.g. (10,2) and (24,2) both have 2 as y coordinate and if 2 is the min y coordinate...).
Anyway, my next step is to sort (ascending) the elements with the min y coordinates according to their x coordinates. First I do:
b = sort(x(a,1));
The above operation might rearrange the elements with min y coordinates so I want to apply this rearrangement to a as well. So I do:
[v i] = ismember(b, x(:, 1));
Unfortunately, if there are elements with the same x value but different y values and one of these elements turns out to be a member of a (i.e. b) then the above matrix chooses it. For example if (10,2) and (24,2) are the elements with smallest y coordinates and there is a 3rd element (24, 13) then it will mess up the above operation. Is there a better way? I wrote my script using loops and everything was fine but in line with Matlab's methodology I rewrote it and I fear my unfamiliarity with matlab is causing this error.
Sorry, I might have misunderstood your question but lemme rephrase what I think you want here:
You have a set of 2D coordinates:
x = [24,2; 10,2; 24,13];
You want the pairs of coordinates to stay together (24,2) (10,2) and (24,13). And you want to find the pairs of coordinates that has the min y-coordinate and if there are multiples, then you want to sort them by x-coordinate. And you want the row indices of what those coordinate pairs were in the original matrix x. So in other words, you want a final answer of:
v = [10,2; 24,2];
i = [2,1];
If I understood correctly, then this is how you can do it:
(Note: I changed x to have one more pair (40,13) to illustrate the difference between idx(i) and i)
>> x = [40,13; 24,2; 10,2; 24,13];
>> idx = find(x(:,2)==min(x(:,2))) %Same as what you've done before.
idx =
2
3
>> [v,i] = sortrows(x(idx,:)) %Use sortrows to sort by x-coord while preserving pairings
v =
10 2
24 2
i = % The indices in x(idx,:)
2
1
>> idx(i) %The row indices in the original matrix x
ans =
3
2
And finally, if this is not what you wanted, can you indicate what you think your answer [v,i] should be in the example you gave?