Related
This code tries to solve 6 ODEs with 6 state variables [horizontal position (x1 and x2), altitude (x3), the true airspeed (x4), the heading angle (x5) and the mass of the aircraft (x6)] and 3 control inputs [engine thrust (u1), the bank angle (u2) and the flight path angle (u3)] by using Euler's Method.
Different flight maneuvers are performed for the specified time intervals.
Velocities.m, Cruise_Vel.m, Des_Vel.m, Thr_cl.m, Thr_cr.m, Thr_des.m, fuel_cl.m, fuel_cr.m, fuel_des.m,den.m,den_cr.m,den_des.m,drag.m,drag_cr.m,drag_des.m,lift.m,lift_cr.m,lift_des.m are functions in seperate tabs.
Main code is:
% Climb from h1=1100 [m] to h2=1600 [m] with α=5 flight path angle.
% Perform cruise flight for t=60 minutes.
% Turn with β=30 bank angle until heading is changed by η=270◦.
% Descent from h2=1600 [m] to h1=1100 [m] with ζ=4◦ flight path angle.
% Complete a 360◦ turn (loiter) at level flight.
% Descent to h3=800 [m] with κ=4.5◦ flight path angle.
% Aircraft Properties
W = .44225E+06; % .44225E+03 tons = .44225E+06 kg
S = .51097E+03; % Surface Area [m^2]
g0 = 9.80665; % Gravitational acceleration [m/s2]
% solving 1st order ODE using numerical methods
t0=0;
tend=3960;
h=0.05;
N=(tend-t0)/h;
t=t0:h:tend;
% Preallocations
x = zeros(6,length(t));
x1 = zeros(1,length(t));
x2 = zeros(1,length(t));
x3 = zeros(1,length(t));
x4 = zeros(1,length(t));
x5 = zeros(1,length(t));
x6 = zeros(1,length(t));
u1 = zeros(1,length(t));
u2 = zeros(1,length(t));
u3 = zeros(1,length(t));
C_D= zeros(1,length(t));
p = zeros(1,length(t));
Cl = zeros(1,length(t));
f = zeros(1,length(t));
dx1dt = zeros(1,length(t));
dx2dt = zeros(1,length(t));
dx3dt = zeros(1,length(t));
dx4dt = zeros(1,length(t));
dx5dt = zeros(1,length(t));
dx6dt = zeros(1,length(t));
% Initial conditions
x(:,1)=[0;0;3608.92;1.0e+02 * 1.161544478045788;0;W];
for i=2:length(t)
if and (t(1,i-1) >= 0,t(1,i-1)<60) % Climb from h1=1100 [m] to h2=1600 [m] with α=5 flight path angle.
x3 = linspace(3608.92,5249.3,79201);
x4 = Velocities(x3); % Changing speed [m/s]
x5 = 0; % Changing head angle [deg]
f = fuel_cl(x3); % Changing fuel flow [kg/min]
u1 = Thr_cl(x3); % Changing thrust [N]
u2 = 0; % Changing bank angle [deg]
u3 = 5; % Changing flight path angle [deg]
V_ver = x4*sin(u3); % Changing vertical speed [m/s]
C_D = drag(x3,x4); % Changing drag coefficient
Cl = lift(x3,x4); % Changing lift coefficient
p = den(x3); % Changing density [kg/m3]
elseif and (t(1,i-1) >= 60,t(1,i-1)<3660) % Perform cruise flight for t=60 minutes.
x3 = 5249.3;
x4 = Cruise_Vel(x3); % Changing speed [m/s]
x5 = 0; % Changing head angle [deg]
f = fuel_cr(x3); % Changing fuel flow [kg/min]
u1 = Thr_cr(x3); % Changing thrust [N]
u2 = 0; % Changing bank angle [deg]
u3 = 0; % Changing flight path angle [deg]
V_ver = x4*sin(u3); % Changing vertical speed [m/s]
C_D = drag_cr(x3,x4); % Changing drag coefficient
Cl = lift_cr(x3,x4); % Changing lift coefficient
p = den_cr(x3); % Changing density [kg/m3]
elseif and (t(1,i-1) >= 3660,t(1,i-1)<3720) % Turn with β=30 bank angle until heading is changed by η=270◦.
x3 = 5249.3;
x4 = Cruise_Vel(x3); % Changing speed [m/s]
x5 = 0:30:270; % Changing head angle [deg]
f = fuel_cr(x3); % Changing fuel flow [kg/min]
u1 = Thr_cr(x3); % Changing thrust [N]
u2 = 30; % Changing bank angle [deg]
u3 = 0; % Changing flight path angle [deg]
V_ver = x4*sin(u3); % Changing vertical speed [m/s]
C_D = drag_cr(x3,x4); % Changing drag coefficient
Cl = lift_cr(x3,x4); % Changing lift coefficient
p = den_cr(x3); % Changing density [kg/m3]
elseif and (t(1,i-1) >= 3720,t(1,i-1)<3780) % Descent from h2=1600 [m] to h1=1100 [m] with ζ=4◦ flight path angle.
x3 = linspace(5249.3,3608.92,79201);
x4 = Des_Vel(x3); % Changing speed [m/s]
x5 = 270; % Changing head angle [deg]
f = fuel_des(x3); % Changing fuel flow [kg/min]
u1 = Thr_des(x3); % Changing thrust [N]
u2 = 0; % Changing bank angle [deg]
u3 = 4; % Changing flight path angle [deg]
V_ver = x4*sin(u3); % Changing vertical speed [m/s]
C_D = drag_des(x3,x4); % Changing drag coefficient
Cl = lift_des(x3,x4); % Changing lift coefficient
p = den_des(x3); % Changing density [kg/m3]
elseif and (t(1,i-1) >= 3780,t(1,i-1)<3900) % Complete a 360◦ turn (loiter) at level flight.
x3 = 3608.9;
x4 = Cruise_Vel(x3); % Changing speed [m/s]
lon = [270 300 360 60 120 180 240 270];
x5 = wrapTo360(lon); % Changing head angle [deg]
f = fuel_cr(x3); % Changing fuel flow [kg/min]
u1 = Thr_cr(x3); % Changing thrust [N]
u2 = 0; % Changing bank angle [deg]
u3 = 0; % Changing flight path angle [deg]
V_ver = x4*sin(u3); % Changing vertical speed [m/s]
C_D = drag_cr(x3,x4); % Changing drag coefficient
Cl = lift_cr(x3,x4); % Changing lift coefficient
p = den_cr(x3); % Changing density [kg/m3]
elseif and (t(1,i-1) >= 3900,t(1,i-1)<3960) % Descent to h3=800 [m] with κ=4.5◦ flight path angle.
x3 = linspace(3608.92,2624.67,79201);
x4 = Des_Vel(x3); % Changing speed [m/s]
x5 = 270; % Changing head angle [deg]
f = fuel_des(x3); % Changing fuel flow [kg/min]
u1 = Thr_des(x3); % Changing thrust [N]
u2 = 0; % Changing bank angle [deg]
u3 = 4.5; % Changing flight path angle [deg]
V_ver = x4*sin(u3); % Changing vertical speed [m/s]
C_D = drag_des(x3,x4); % Changing drag coefficient
Cl = lift_des(x3,x4); % Changing lift coefficient
p = den_des(x3); % Changing density [kg/m3]
else
fprintf("A problem occured.");
end
dx1dt = x4 .* cos(x5) .* cos(u3);
dx2dt = x4 .* sin(x5) .* cos(u3);
dx3dt = x4 .* sin(u3);
dx4dt = -C_D.*S.*p.*(x4.^2)./(2.*x6)-g0.*sin(u3)+u1./x6;
dx5dt = -Cl.*S.*p.*x4./(2.*x6).*sin(u2);
dx6dt = -f;
x(1,i)= x(1,i-1) + h * dx1dt(1,i-1); %%%%%%%%% line 138 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
x(2,i)= x(2,i-1) + h * dx2dt(1,i-1);
x(3,i)= x(3,i-1) + h * dx3dt(1,i-1);
x(4,i)= x(4,i-1) + h * dx4dt(1,i-1);
x(5,i)= x(5,i-1) + h * dx5dt(1,i-1);
x(6,i)= x(6,i-1) + h * dx6dt(1,i-1);
end
tot=cell2mat(f); % Total fuel consumption during mission [kg/min]
Tot_fuel=sum(tot);
figure(1)
plot3(x1(:),x2(:),x3(:)); % 3D position graph
figure(2)
plot(t,x4(:)); % Vtas − Time graph
figure(3)
plot(t,V_ver(:)); % V_vertical − Time graph
figure(4)
plot(t,x5(:)); % Heading − Time graph
figure(5)
plot(t,x6(:)); % Mass − Time graph
figure(6)
plot(t,u1(:)); % Thrust − Time graph
figure(7)
plot(t,u2(:)); % Bank Angle − Time graph
figure(8)
plot(t,u3(:)); % Flight Path Angle − Time graph
fprintf('Total fuel consumption during mission is %.2f [kg]',Tot_fuel*tend/60);
The reason why I used 79201 sized array is length(t) = 79201.
And when I run:
Index in position 2 exceeds array bounds (must not exceed 1).
Error in forum (line 138)
x(1,i)= x(1,i-1) + h * dx1dt(1,i-1);
What should I do?
One of the functions in separate tabs is below, the rest is similar:
function [Vtas_cl] = Velocities(x3)
%%%%%%%%%%%%%%%%%%%% Constants %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Vcl_1 = 335; % Standard calibrated airspeed [kt]
Vcl_2 = 172.3; % Standard calibrated airspeed [kt] -> [m/s] (To find the Mach transition altitude)
Vcl_2_in_knots = 335; % Standard calibrated airspeed [kt] (To find the result in knots, if altitude is between 10,000 ft and Mach transition altitude)
M_cl = 0.86; % Standard calibrated airspeed [kt]
K = 1.4; % Adiabatic index of air
R = 287.05287; % Real gas constant for air [m2/(K·s2)]
Bt = - 0.0065; % ISA temperature gradient with altitude below the tropopause [K/m]
T0 = 288.15; % Standard atmospheric temperature at MSL [K]
g0 = 9.80665; % Gravitational acceleration [m/s2]
a0= 340.294; % Speed of Sound [m/s]
Vd_CL1 = 5; % Climb speed increment below 1500 ft (jet)
Vd_CL2 = 10; % Climb speed increment below 3000 ft (jet)
Vd_CL3 = 30; % Climb speed increment below 4000 ft (jet)
Vd_CL4 = 60; % Climb speed increment below 5000 ft (jet)
Vd_CL5 = 80; % Climb speed increment below 6000 ft (jet)
CV_min = 1.3; % Minimum speed coefficient
Vstall_TO = .14200E+03; % Stall speed at take-off [KCAS]
CAS_climb = Vcl_2;
Mach_climb = M_cl;
delta_trans = (((1+((K-1)/2)*(CAS_climb/a0)^2)^(K/(K-1)))-1)/(((1+(K-1)/2*Mach_climb^2)^(K/(K-1)))-1); % Pressure ratio at the transition altitude
teta_trans = delta_trans ^ (-Bt*R/g0); % Temperature ratio at the transition altitude
H_p_trans_climb = (1000/0.348/6.5)*(T0*(1-teta_trans)); % Transition altitude for climb [ft]
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% End of constants
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
H_climb = x3; %%%%%% Input %%%%%%%%%%%%%%%%%%%
Vnom_climb_jet = zeros(1, length(H_climb));
for k1 = 1:length(H_climb)
if (0<=H_climb(k1)&&H_climb(k1)<1500)
Vnom_climb_jet(k1) = CV_min * Vstall_TO + Vd_CL1;
elseif (1500<=H_climb(k1)&&H_climb(k1)<3000)
Vnom_climb_jet(k1) = CV_min * Vstall_TO + Vd_CL2;
elseif (3000<=H_climb(k1)&&H_climb(k1)<4000)
Vnom_climb_jet (k1)= CV_min * Vstall_TO + Vd_CL3;
elseif (4000<=H_climb(k1)&&H_climb(k1)<5000)
Vnom_climb_jet (k1)= CV_min * Vstall_TO + Vd_CL4;
elseif (5000<=H_climb(k1)&&H_climb(k1)<6000)
Vnom_climb_jet(k1) = CV_min * Vstall_TO + Vd_CL5;
elseif (6000<=H_climb(k1)&&H_climb(k1)<10000)
Vnom_climb_jet (k1)= min(Vcl_1,250);
elseif (10000<=H_climb(k1)&&H_climb(k1)<=H_p_trans_climb)
Vnom_climb_jet(k1) = Vcl_2_in_knots;
elseif (H_p_trans_climb<H_climb(k1))
Vnom_climb_jet(k1) = M_cl;
end
Vcas_cl(k1) = Vnom_climb_jet(k1)* 0.514; % [kn] -> [m/s]
H_climb (k1)= H_climb(k1) * 0.3048; % [feet] -> [m]
K = 1.4; % Adiabatic index of air
R = 287.05287; % Real gas constant for air [m2/(K·s2)]
Bt = - 0.0065; % ISA temperature gradient with altitude below the tropopause [K/m]
deltaT = 0; % Value of the real temperature T in ISA conditions [K]
T0 = 288.15; % Standard atmospheric temperature at MSL [K]
P0 = 101325; % Standard atmospheric pressure at MSL [Pa]
g0 = 9.80665; % Gravitational acceleration [m/s2]
p0 = 1.225; % Standard atmospheric density at MSL [kg/m3]
visc = (K-1)./K;
T(k1) = T0 + deltaT + Bt * H_climb(k1); % Temperature [K]
P (k1)= P0*((T(k1)-deltaT)/T0).^((-g0)/(Bt*R)); % Pressure [Pa]
p (k1)= P(k1) ./ (R*T(k1)); % Density [kg/m^3]
Vtas_cl(k1) = (2*P(k1)/visc/p(k1)*((1 + P0/P(k1)*((1 + visc*p0*Vcas_cl(k1)*Vcas_cl(k1)/2/P0).^(1/visc)-1)).^(visc)-1)).^(1/2); % True Air Speed [m/s]
end
% Output
end
Index in position 2 exceeds array bounds (must not exceed 1).
This is an error that occurs when you are trying to access and element
that does not exist. For instance, if I initialize a variable of x
to be sized (3,1), then try to extract a value from index (4,4),
it will throw this error.
x = zeros(3,1)
y = x(4,4)+1; % ERROR
There is an issue with your indexing of the variable dx1dt at line 138. It is trying to access element (1,2) which does not exist when i=3.
At the beginning of your code, you have initialized the size of dx1dt to a size of (1, 79201):
dx1dt = zeros(1,length(t));
However, when you compute each value, you overwrite the size of this array to (1,1):
dx1dt = x4 .* cos(x5) .* cos(u3);
So when i=3, the following indexes are called, and dx1dt does not have any value placed in the (1,2) location. This will throw you an error that the index exceeds the bounds.
x(1,i)= x(1,i-1) + h * dx1dt(1,i-1);
x(1,3)= x(1,2) + h * dx1dt(1,2);
The question is: Is the variable of dx1dt supposed to be an array of size (1,79201) or simply a double?
I have to different struct arrays(In the same Matlab file), what I want is to take 1 parameter/vector from a variable in a struct array and subtract it with different parameters from another variable in another struct array, is this possible?
Here is a small part of my code:
Dist(1).name = 'Pristina'
Dist(1).KM_To_Fushe_ks = 13.7 % 199-13.7 =
Dist(1).KM_to_Lipjan = 8.7 % 199-8.7 =
Dist(1).KM_to_Sllatina = 4.2 % 199-4.2 =
Dist(1).KM_to_Hajvali = 3.5 % 199-3.5 =
Dist(1).KM_to_Mitrovica = 46.9 % 199-46.9 =
Dist(1).KM_to_Anija = 1.9 % 199-1.9 =
EV(1).name = 'Nissan Leaf 24 kWh pack'
EV(1).RangeInKM_By_Manufacturer = 199 %SUBTRACT this with parameters above:
EV(1).Battery_Capacity = 21.6
EV(1).Battery_Warranty_KM = 100000
EV(1).Battery_Warrany_Year = 5
EV(1).EnginePower_Kw = 80
EV(1).EnginePower_hK = 109
EV(1).Torque_in_NewtonMeter = 254
EV(1).QuickCharging_type = 'CHAdeMO'
EV(1).QuickChargingEffect_kW_DC = 50
EV(1).NormalCharging_OnBoard_kW_AC = 3.3
EV(1).Seats = 5
EV(1).Luggage_in_Liters = 370
EV(1).Consumption_Mixed_kWh_per_10km_NEDC = 1.5
EV(1).Weight_Without_Driver = 1475
EV(1).TopSpeed_KM_per_hour = 144
EV(1).Acceleration_0to100KM_per_hour = 11.5
EV(1).RangeInKM_By_Manufacturer_RANK = 10
What I want is to have the number off 199 as a vector, and substract it by all these numbers = [13.7, 8.7, 4.2, 3.5, 46.9, 1.9]
How to do this?
Maybe I misinterpret your question, but this seem to work:
EV(1).RangeInKM_By_Manufacturer = 199 - Dist(1).KM_To_Fushe_ks
In the line you quote in your question, you left the initialization of KM_To_Fushe_ks after the difference; in short, you cannot have to vaiable assignements in the same command.
Also, if you end your lines with semi-colons you will suppress the output to the command window. Like this:
Dist(1).name = 'Pristina';
Dist(1).KM_To_Fushe_ks = 13.7;
Dist(1).KM_to_Lipjan = 8.7;
% Etc...
Here is one solution to my problem:
distances = [KM_to_Fushe_KS, KM_to_Lipjan];
remainingrange = arrayfun(#(s) s.RangeInKM - distances, EV, 'UniformOutput', false)
Or I could do this:
remainingrange = cell(size(EV));
for evidx = 1:numel(EV)
remaingrange{evidx} = EV(evidx).RangeInKM - distances;
end
Another solution is doing is putting multiple distances in once matrix:
Example:
Towns = {'Town1', 'Town2', 'Town3', 'Town4'};
distances = [0 200 13.7 8.7;
200 0 13.3 9.3;
13.7 13.3 0 255;
8.7 9.3 255 0];
EVs = {'Nissan Leaf 24 kWh pack', 'Nissan Leaf 30 kWh pack'};
ranges = [199 250];
And then I can calculate distances as a 3D matrix:
remainingrange = permute(ranges, [1 3 2]) - distances;
remainingrange = bsxfun(#minus, permute(ranges, [1 3 2]), distances);
If I want to check if a EV has not enough range in KM, I could write:
tooFarForMyEV = find(remainingrange < 0)
[from, to, ev] = ind2sub(size(remainingrange), tooFarForMyEV);
lackingrange = table(Towns(from)', Towns(to)', EVs(ev)', remainingrange(tooFarForMyEV), 'VariableNames', {'From', 'To', 'EV', 'Deficit'})
I have matrix A and matrix B. Matrix A is 100*3. Matrix B is 10*3. I need to insert one row from matrix B each time in a sequence into matrix A after every 10th row. The result would be Matrix A with 110*3. How can I do this in Matlab?
Here's another indexing-based approach:
n = 10;
C = [A; B];
[~, ind] = sort([1:size(A,1) n*(1:size(B,1))+.5]);
C = C(ind,:);
For canonical purposes, here's how you'd do it via loops. This is a bit inefficient since you're mutating the array at each iteration, but it's really simple to read. Given that your two matrices are stored in A (100 x 3) and B (10 x 3), you would do:
out = [];
for idx = 1 : 10
out = [out; A((idx-1)*10 + 1 : 10*idx,:); B(idx,:)];
end
At each iteration, we pick out 10 rows of A and 1 row of B and we concatenate these 11 rows onto out. This happens 10 times, resulting in 330 rows with 3 columns.
Here's an index-based approach:
%//pre-allocate output matrix
matrixC = zeros(110, 3);
%//create index array for the locations in matrixC that would be populated by matrixB
idxArr = (1:10) * 11;
%//place matrixB into matrixC
matrixC(idxArr,:) = matrixB;
%//place matrixA into matrixC
%//setdiff is used to exclude indexes already populated by values from matrixB
matrixC(setdiff(1:110, idxArr),:) = matrixA;
And just for fun here's the same approach sans magic numbers:
%//define how many rows to take from matrixA at once
numRows = 10;
%//get dimensions of input matrices
lengthA = size(matrixA, 1);
lengthB = size(matrixB, 1);
matrixC = zeros(lengthA + lengthB, 3);
idxArr = (1:lengthB) * (numRows + 1);
matrixC(idxArr,:) = matrixB;
matrixC(setdiff(1:size(matrixC, 1), idxArr),:) = matrixA;
Just for fun... Now with more robust test matrices!
A = ones(3, 100);
A(:) = 1:300;
A = A.'
B = ones(3, 10);
B(:) = 1:30;
B = B.' + 1000
C = reshape(A.', 3, 10, []);
C(:,end+1,:) = permute(B, [2 3 1]);
D = permute(C, [2 3 1]);
E = reshape(D, 110, 3)
Input:
A =
1 2 3
4 5 6
7 8 9
10 11 12
13 14 15
16 17 18
19 20 21
22 23 24
25 26 27
28 29 30
31 32 33
34 35 36
...
B =
1001 1002 1003
1004 1005 1006
...
Output:
E =
1 2 3
4 5 6
7 8 9
10 11 12
13 14 15
16 17 18
19 20 21
22 23 24
25 26 27
28 29 30
1001 1002 1003
31 32 33
34 35 36
...
Thanks to #Divakar for pointing out my previous error.
Solution Code
Here's an implementation based on logical indexing also known as masking and must be pretty efficient when working with large arrays -
%// Get sizes of A and B
[M,d] = size(A);
N = size(B,1);
%// Mask of row indices where rows from A would be placed
mask_idx = reshape([true(A_cutrow,M/A_cutrow) ; false(1,N)],[],1);
%// Pre-allocate with zeros:
%// http://undocumentedmatlab.com/blog/preallocation-performance
out(M+N,d) = 0;
%// Insert A and B using mask and ~mask
out(mask_idx,:) = A;
out(~mask_idx,:) = B;
Benchmarking
%// Setup inputs
A = rand(100000,3);
B = rand(10000,3);
A_cutrow = 10;
num_iter = 200; %// Number of iterations to be run for each approach
%// Warm up tic/toc.
for k = 1:50000
tic(); elapsed = toc();
end
disp(' ------------------------------- With MASKING')
tic
for iter = 1:num_iter
[M,d] = size(A);
N = size(B,1);
mask_idx = reshape([true(A_cutrow,M/A_cutrow) ; false(1,N)],[],1);
out(M+N,d) = 0;
out(mask_idx,:) = A;
out(~mask_idx,:) = B;
clear out
end
toc, clear mask_idx N M d iter
disp(' ------------------------------- With SORT')
tic
for iter = 1:num_iter
C = [A; B];
[~, ind] = sort([1:size(A,1) A_cutrow*(1:size(B,1))+.5]);
C = C(ind,:);
end
toc, clear C ind iter
disp(' ------------------------------- With RESHAPE+PERMUTE')
tic
for iter = 1:num_iter
[M,d] = size(A);
N = size(B,1);
C = reshape(A.', d, A_cutrow , []);
C(:,end+1,:) = permute(B, [2 3 1]);
D = permute(C, [2 1 3]);
out = reshape(permute(D,[1 3 2]),M+N,[]);
end
toc, clear out D C N M d iter
disp(' ------------------------------- With SETDIFF')
tic
for iter = 1:num_iter
lengthA = size(A, 1);
lengthB = size(B, 1);
matrixC = zeros(lengthA + lengthB, 3);
idxArr = (1:lengthB) * (A_cutrow + 1);
matrixC(idxArr,:) = B;
matrixC(setdiff(1:size(matrixC, 1), idxArr),:) = A;
end
toc, clear matrixC idxArr lengthA lengthB
disp(' ------------------------------- With FOR-LOOP')
tic
for iter = 1:num_iter
[M,d] = size(A);
N = size(B,1);
Mc = M/A_cutrow;
out(M+N,d) = 0;
for idx = 1 : Mc
out( 1+(idx-1)*(A_cutrow +1): idx*(A_cutrow+1), :) = ...
[A( 1+(idx-1)*A_cutrow : idx*A_cutrow , : ) ; B(idx,:)];
end
clear out
end
toc
Runtimes
Case #1: A as 100 x 3 and B as 10 x 3
------------------------------- With MASKING
Elapsed time is 4.987088 seconds.
------------------------------- With SORT
Elapsed time is 5.056301 seconds.
------------------------------- With RESHAPE+PERMUTE
Elapsed time is 5.170416 seconds.
------------------------------- With SETDIFF
Elapsed time is 35.063020 seconds.
------------------------------- With FOR-LOOP
Elapsed time is 12.118992 seconds.
Case #2: A as 100000 x 3 and B as 10000 x 3
------------------------------- With MASKING
Elapsed time is 1.167707 seconds.
------------------------------- With SORT
Elapsed time is 2.667149 seconds.
------------------------------- With RESHAPE+PERMUTE
Elapsed time is 2.603110 seconds.
------------------------------- With SETDIFF
Elapsed time is 3.153900 seconds.
------------------------------- With FOR-LOOP
Elapsed time is 19.822912 seconds.
Please note that num_iter was different for these two cases, as the idea was to keep the runtimes > 1 sec mark to compensate for tic-toc overheads.
I am using MATLAB.
So I have 3 arrays; say a,b,c. a and b represent distances, and c represents a variable with a specific value at the point (a,b).
I have been trying to create a matrix which comprises of (b x a) cells, and the populate it with the values of c, in order to then image, heatmap it etc.
However the issue I have having is that there are many repeating values of a and b; a stays fixed and it then iterates across all values of b, then moves onto the next value of a, and so forth. The range of a and b is fixed and always iterate across equally spaced values though.
Below is the code I have created for this. So for it seems to not to work and I am out of ideas.
z_true_len = length(unique(a)); %number of z distances
r_true_len = length(unique(b)); %number of r disatances
data_matrix = zeros(r_true_len,z_true_len); %create r x z matrix, full of 0s
z_past = 0;
r_past = 0;
z_count = 1;
r_count = 1;
for count = 1: length(a)
z_current = a(count);
if z_past ~= z_current
data_matrix(1:z_count) = c(count);
z_past = z_current;
z_count = z_count + 1;
r_count = 1;
else
data_matrix(r_count:z_count) = c(count);
r_count = r_count + 1;
end
end
data_matrix
Any help would be appriciated
I included a mapping of the a and b arrays into a space of integers:
% Data
a = [ 0.5 0.5 2.5 0.5 2.5 2.5 4.5 4.5 4.5 2.5 4.5 0.5];
b = [-35 -25 -25 -15 -45 -35 -35 -45 -15 -15 -25 -45];
c = [2 1 -2 4 6 4 6 8 4 1 -5 2];
% Mapping from real to integers
a_unique = sort(unique(a));
b_unique = sort(unique(b));
a_idx = zeros(size(a));
b_idx = zeros(size(b));
for ii = 1:numel(a_unique),
a_idx(a_unique(ii)==a) = ii;
end
for ii = 1:numel(b_unique),
b_idx(b_unique(ii)==b) = ii;
end
% Create matrix
data_matrix = zeros(numel(b_unique),numel(a_unique));
for count = 1:length(a_idx),
data_matrix(b_idx(count),a_idx(count)) = c(count);
end
% Plot
figure;
imagesc(data_matrix);
You basically need to define data_matrix with the appropriate dimensions, and then fill values in using linear indexing (see sub2ind):
m = max(b); %// number of rows in result
n = max(a); %// number of columns in result
data_matrix = NaN(m,n); %// define result matrix with appropriate dimensions
data_matrix(sub2ind([m n], b, a)) = c; %// fill values using indexing
If a and b don't always contain integers: first transform into "integer labels" with the third output of unique, and then proceed as above:
[~, ~, bb] = unique(b); %// get integer labels for b
[~, ~, aa] = unique(a); %// get integer labels for a
m = max(bb); %// number of rows in result
n = max(aa); %// number of columns in result
data_matrix = NaN(m,n); %// define result matrix with appropriate dimensions
data_matrix(sub2ind([m n], bb, aa)) = c; %// fill values using indexing
I want to change a number of values in a 4D array M_ ijkl to NaN using MATLAB.
I use find to get the indices i and j that meet a certain condition for k = 2 and l = 4 (in my case it's the y component of a position at time t_4). I now want to set all the entries for these i and j combinations and for all k and l to NaN.
I used this method to do it (example by nkjt):
% initialise
M = zeros(10,10,2,4);
% set two points in (:,:,2,4) to be above threshold.
M(2,4,2,4)=5;
M(6,8,2,4)=5;
% find and set to NaN
[i,j] = find(M(:,:,2,4) > 4);
M(i,j,:,:)= NaN;
% count NaNs
sum(isnan(M(:))) % returns 32
This method is is very slow as this example illustrates:
M = rand(360,360,2,4);
threshold = 0.5;
% slow and wrong result
[i,j] = find(M(:,:,2,4) > threshold);
tic;
M(i,j,:,:) = NaN;
toc;
Elapsed time is 54.698449 seconds.
Note that the tic and toc don't time the find so that is not the problem.
With Rody's and njkt's help I also realized that my method doesn't actually do what I want. I only want to change entries with the combinations i and j i found with find (for all k and l), i.e. [2,4,:,:] and [6,8,:,:], but not [2,8,:,:] and [6,4,:,:]. In the first example sum(isnan(M(:))) should return 16.
Have you checked your results? Because I think they are wrong. For example, if you have
A = [...
1 2 3
4 5 6
7 8 9];
and you want to set element A(1,1) and A(2,3) to NaN. What you are doing is
A([1 2], [1 3]) = NaN
but that gives
A =
NaN 2 NaN
NaN 5 NaN
7 8 9
The easiest and fastest way around this is to not use find, but logical indexing:
M = rand(360,360,2,4);
maximum = 0.05;
tic;
M(M(:,:,2,4) > maximum) = NaN;
toc
Which gives on my PC:
Elapsed time is 0.003547 seconds.
Much faster for me by reshaping M:
M = rand(360,360,2,4);
M = reshape(M,[360*360,2,4]);
maximum = 0.05;
n = find(M(:,2,4) > maximum);
tic;
M(n,:,:) = NaN;
M = reshape(M,[360, 360, 2, 4]);
toc;
ETA:
M(i,j,:,:)= NaN; sets all combinations of i, j to NaN for all k,l (as explained in Rody's answer).
So for example:
% initialise
M = zeros(10,10,2,4);
% set two points in (:,:,2,4) to be above threshold.
M(2,4,2,4)=5;
M(6,8,2,4)=5;
% find and set to NaN
[i,j] = find(M(:,:,2,4) > 4);
M(i,j,:,:)= NaN;
% count NaNs
sum(isnan(M(:))) % returns 32
e.g. '(2,4,l,k) = NaN' but also '(4,2,l,k) = NaN'.
If this is what you want, reduce the size of i,j with unique after find.
In terms of logical indexing, basically, it's often better to do something like A(A>2)=NaN; instead of n = find(A>2); A(n)=NaN;. In the reshaped case you could do M(M(:,2,4)>maximum,:,:) = NaN;. I didn't tic/toc it so I don't know if it would be faster in this case.