Percentiles either side of the mean across a matrix - MATLAB - matlab

I have a matrix of data in this form:
5400 5700 6200 5200 6100 5500
5500 5900 7000 5900 6200 6000
6100 10300 7500 6200 6500 6600
6800 10900 7900 9400 9600 6600
7300 12500 10600 13000 10000 7900
7300 15700 10600 13200 14000 9200
11700 16200 11000 14900 14600 10800
12500 16500 11800 18100 14600 12900
13400 17000 19200 19300 16900 17100
14000 18700 20900 19700 17700 17700
14600 18800 22900 20200 17900 18500
15000 20800 24400 20800 19900 18700
15700 21100 25400 21500 22300 19700
16800 22000 26400 21700 22300 23300
The actual matrix is much larger.
I want to calculate two values for each row that describe the range of variation from the mean in terms of a percentile i.e. "95% of all values above the mean fall below X, and 95% of all value below the mean fall above Y".
What is the best method to do this?
Something like:
a = prctile(tcIED',0.90)
Produces only one value - which also appear to be inaccurate (lower than expected).

Your approach is correct , but prctile expects percentages (between 0 and 100). So:
a = prctile(tcIED.', 90);
Or, equivalently, use quantile with proportions (between 0 and 1):
a = quantile(tcIED.', 0.9);
For example, with your data you get
>> a(1)
ans =
6190
which means that about 90% of the values row 1 of your data matrix are less than or equal to 6190.

Related

Lap Time Simulator Car (MATLAB)

I'm currently trying to make a lap time simulator for point mass acceleration of a car. I've made a model for the engine and its speed as shown below. However I'm coming across a problem where the rpm(engine_speed) doesn't drop down once it's above 14000 where there would be a gear change. How can I improve this
car.torque = [4 7 10 12.5 14.5 25 30.5 30.5 35.5 45.6 44.8 39.4 33.8 34 13 4];
car.engine_speed = [1 1000 2000 3000 4000 5000 6000 7000 8000 9000 10000 11000 12000 13000 14000 15000] .* 2 * pi / 60;
car.torque_spline = spline(car.engine_speed, car.torque);
%This is within a while loop
model.wheel_speed = model.vx(idx-1) ./ car.wheel_radius;
model.engine_speed = model.wheel_speed .* (car.gearbox .* car.gear_ratio);
model.engine_speed = min(14000 * (2 * pi / 60), max(0, model.engine_speed));
From your code snippet, it appears that as wheel_speed increases, engine_speed can only decrease if gear_ratio or gear_box change. Where are the gear variables set or modeled?
comment: I don't think you need .* or ./ in lines 2 or 4. .* and ./ are only required when multiplying/dividing arrays element-wise. In this case you're multiplying/divding each element of an array by a number.

Marking values from the previous N number of days in KDB based on criteria?

Initial Table
company time value
-------------------------
a 00:00:15.000 100
a 00:00:30.000 100
b 00:01:00.000 100
a 00:01:10.000 100
a 00:01:15.000 100
a 00:01:20.000 300
a 00:01:25.000 100
b 00:01:30.000 400
a 00:01:50.000 100
a 00:02:00.000 100
a 00:00:03.000 200
Let t = 1 hour.
For each row, I would like to look back t time.
Entries falling in t will form a time window. I would like to get max(time window) - min (time window) / number of events).
For example, if it is 12:00 now, and there are a total of five events, 12:00, 11:50, 11:40, 11:30, 10:30, four of which falls in the window of t i.e. 12:00, 11:50, 11:40, 11:30, the result will be 12:00 - 11:30 / 4.
Additionally, the window should only account for rows with the same value and company name.
Resultant Table
company time value x
--------------------------------
a 00:00:15.000 100 0 (First event A).
a 00:00:30.000 100 15 (30 - 15 / 2 events).
b 00:01:00.000 100 0 (First event of company B).
a 00:01:10.000 100 55/3 = 18.33 (1:10 - 0:15 / 3 events).
a 00:01:15.000 100 60/4 = 15 (1:15 - 0:15 / 4 events).
a 00:01:20.000 300 0 (Different value).
a 00:01:25.000 100 55/4 = 13.75 (01:25 - 0:30 / 4 events).
b 00:01:30.000 400 0 (Different value and company).
a 00:01:50.000 100 40/4 = 10 (01:50 - 01:10 / 4 events).
a 00:02:00.000 100 50/5 = 10 (02:00 - 01:10 / 5 events).
a 00:03:00.000 200 0 (Different value).
Any help will be greatly appreciated. If it helps, I asked a similar question, which worked splendidly: Sum values from the previous N number of days in KDB?
Table Query
([] company:`a`a`b`a`a`a`a`b`a`a`a; time: 00:00:15.000 00:00:30.000 00:01:00.000 00:01:10.000 00:01:15.000 00:01:20.000 00:01:25.000 00:01:30.000 00:01:50.000 00:02:00.000 00:03:00.000; v: 100 100 100 100 100 300 100 400 100 100 200)
You may wish to use the following;
q)update x:((time-time[time binr time-01:00:00])%60000)%count each v where each time within/:flip(time-01:00:00;time) by company,v from t
company time v x
---------------------------------
a 00:15:00.000 100 0
a 00:30:00.000 100 7.5
b 01:00:00.000 100 0
a 01:10:00.000 100 18.33333
a 01:15:00.000 100 15
a 01:20:00.000 300 0
a 01:25:00.000 100 13.75
b 01:30:00.000 400 0
a 01:50:00.000 100 10
a 02:00:00.000 100 10
a 03:00:00.000 200 0
It uses time binr time-01:00:00 to get the index of the min time for the previous 1 hour of each time.
Then (time-time[time binr time-01:00:00])%60000 gives the respective time range (i.e., time - min time) for each time in minutes.
count each v where each time within/:flip(time-01:00:00;time) gives the number of rows within this range.
Dividing the two and implementing by company,v applies it all only to those that have the same company and v values.
Hope this helps.
Kevin
If your table is ordered by time then below solution will give you the required result. You can also order your table by time if it is not already using xasc.
I have also modified the table to have time with different hour values.
q) t:([] company:`a`a`b`a`a`a`a`b`a`a`a; time: 00:15:00.000 00:30:00.000 01:00:00.000 01:10:00.000 01:15:00.000 01:20:00.000 01:25:00.000 01:30:00.000 01:50:00.000 02:00:00.000 03:00:00.000; v: 100 100 100 100 100 300 100 400 100 100 200)
q) f:{(`int$x-x i) % 60000*1+til[count x]-i:x binr x-01:00:00}
q) update res:f time by company,v from t
Output
company time v res
---------------------------------
a 00:15:00.000 100 0
a 00:30:00.000 100 7.5
b 01:00:00.000 100 0
a 01:10:00.000 100 18.33333
a 01:15:00.000 100 15
a 01:20:00.000 300 0
a 01:25:00.000 100 13.75
b 01:30:00.000 400 0
a 01:50:00.000 100 10
a 02:00:00.000 100 10
a 03:00:00.000 200 0
You can modify the function f to change time window value. Or change f to accept that as an input parameter.
Explanation:
We pass time vector by company, value to a function f. It deducts 1 hour from each time value and then uses binr to get the index of the first time entry within 1-hour window range from the input time vector.
q) i:x binr x-01:00:00
q) 0 0 0 0 1 2 2
After that, it uses the indexes of the output to calculate the total count. Here I am multiplying the count by 60000 as time differences are in milliseconds because it is casting it to int.
q) 60000*1+til[count x]-i
q) 60000 120000 180000 240000 240000 240000 300000
Then finally we subtract the min and max time for each value and divide them by the above counts. Since time vector is ordered(ascending), the input time vector can be used as the max value and min values are at indexes referred by i.
q) (`int$x-x i) % 60000*1+til[count x]-i

Cubic spline implementation in Matlab

I have two vectors, x and y that are defined(at random) as follows:
x1=[1000 3000 5000 6000 4000 2000 500 0 -1000 -3000 -5000 -6000 -4000 -2000 -500 1 999 2999 4999];
y1=[5000 4999 4990 3500 2500 2499 2498 2497 2496 2495 2494 1000 -1000 -999 -998 -997 -996 -995 -994];
Following is the plot I obtained by simply typing in plot(x1,y1):
Is there a way to produce a smooth curve from the above data using the interp1 command? I have been told that I should use cubic splines to achieve the desired plot, however, since I am new to Matlab I am unaware of how to implement such a solution. Thanks in advance!
Edit: I have tried to implement it as follows, but I am getting a hideous looking plot!
x1_temp=-6000:100:6000;
pc=pchip(x1,y1,x1_temp);
plot(x1,y1,'o',x1_temp,pc,'-');
How should I modify this code to produce the right plot?
I think you are confused about what you are interpolating. You should interpolate x1 and y1 separately, and afterwards plot them against each other. The following example produces a smooth curve:
x1=[1000 3000 5000 6000 4000 2000 500 0 -1000 -3000 -5000 -6000 -4000 -2000 -500 1 999 2999 4999];
y1=[5000 4999 4990 3500 2500 2499 2498 2497 2496 2495 2494 1000 -1000 -999 -998 -997 -996 -995 -994];
s = [0,cumsum(sqrt(diff(x1).^2+diff(y1).^2))]
N = length(s);
figure();
plot(x1,y1);
hold on
s_fine = interp1(linspace(0,1,N),s,linspace(0,1,5*N));
pcx=interp1(s,x1,s_fine,'spline');
pcy=interp1(s,y1,s_fine,'spline');
plot(pcx,pcy,'r-');

How to write matrices from matlab to .xlsx with special formatting tables

I have one problem with exporting matrices from Matlab to Excel. This is not a problem, but I need some formatting.
I made matrices A and B and I printed them to .xlsx document.
filename = 'example.xlsx';
A;
sheet = 1;
xlRange = 'A9';
xlswrite(filename,A,sheet,xlRange)
B;
xlRange2= 'B9';
xlswrite(filename,B,sheet,xlRange2)
And i get the example.xlsx file with this formating:
400 4.56
500 5.12
600 6.76
700 7.98
800 8.21
900 9.21
1000 10.12
1100 11.23
1200 12.43
1300 13.89
1400 14.54
1500 15.21
1600 16.23
1700 17.53
I need this kind of formating:
400 4.56
500 5.12
600 6.76
700 7.98
800 8.21
900 9.21
1000 10.12
100 11.23
200 12.43
300 13.89
400 14.54
500 15.21
600 16.23
700 17.53
Steps are on 500, 1000, 1500, 2000, 2500... How to put one empty row and how to make this kind of formating?
This code provides the cell as required for xlswrite:
M=[400 4.56
500 5.12
600 6.76
700 7.98
800 8.21
900 9.21
1000 10.12
1100 11.23
1200 12.43
1300 13.89
1400 14.54
1500 15.21
1600 16.23
1700 17.53
900 9.21
1000 10.12
1100 11.23
1200 12.43
1300 13.89
1400 14.54
1500 15.21
1600 16.23
1700 17.53];
gaps=[500, 1000, 1500, 2000, 2500];
%calculates a group indx. 0 is below first gap, 1 between first and second etc..
group=sum(bsxfun(#ge,M(:,1),gaps),2);
%whenever group increases a line must be jumped, calculate indices
index=cumsum(ones(size(M,1),1)+[0;diff(group)>0]);
%allocate empty cell
X=cell(max(index),size(M,2));
%fill data
X(index,:)=num2cell(M);
xlswrite('a.xlsx',X)

Limited Sum in Matlab

Hi lets say that i have matrix size 5x5.
B=[1 2 3 4 5; 10 20 30 40 50; 100 200 300 400 500; 1000 2000 3000 4000 5000; 10000 20000 30000 40000 50000];
How do i use function sum, to sum rows between 2 and 4 and have result:
A = [1110;2220;3330;4440]
You'll find some useful information about matrix indexing in the documentation at http://www.mathworks.co.uk/help/matlab/math/matrix-indexing.html
To illustrate your example, you can use B(2:4,:) to retreive the following:
ans =
10 20 30 40 50
100 200 300 400 500
1000 2000 3000 4000 5000
You can then use the sum function as follows to achieve your desired result:
A = sum(B(2:4,:))
I hope this helps!
All the best,
Matt
MATLAB>> sum(B(2:4,1:4))
ans =
1110 2220 3330 4440
If you want to transpose the result, add ' at the end.