I am trying to generate a 1D array in Matlab and calling another function to do it. However, I am getting an error when I try to find out the minimum element and its position within the array. I want to find out the minimum value in maxSS and then find its index position and use that to find the corresponding angle. Here's my code:
angle = linspace(0,pi/2,1000);
for i = 1:length(angle)
[maxSS] = GetMaxShearStress(strainMatrix, complianceMatrix, angle(i));
M = min(maxSS);
[M,I] = min(maxSS);
minimum_angle = angle();
end
disp(' The fibre angle that minimises the shear stress is 'num2str(minimum_angle) 'radians');
Does this work?
[M,I] = min(maxSS(:))
Related
I have this task to create a script that acts similarly to normcdf on matlab.
x=linspace(-5,5,1000); %values for x
p= 1/sqrt(2*pi) * exp((-x.^2)/2); % THE PDF for the standard normal
t=cumtrapz(x,p); % the CDF for the standard normal distribution
plot(x,t); %shows the graph of the CDF
The problem is when the t values are assigned to 1:1000 instead of -5:5 in increments. I want to know how to assign the correct x values, that is -5:5,1000 to the t values output? such as when I do t(n) I get the same result as normcdf(n).
Just to clarify: the problem is I cannot simply say t(-5) and get result =1 as I would in normcdf(1) because the cumtrapz calculated values are assigned to x=1:1000 instead of -5 to 5.
Updated answer
Ok, having read your comment; here is how to do what you want:
x = linspace(-5,5,1000);
p = 1/sqrt(2*pi) * exp((-x.^2)/2);
cdf = cumtrapz(x,p);
q = 3; % Query point
disp(normcdf(q)) % For reference
[~,I] = min(abs(x-q)); % Find closest index
disp(cdf(I)) % Show the value
Sadly, there is no matlab syntax which will do this nicely in one line, but if you abstract finding the closest index into a different function, you can do this:
cdf(findClosest(x,q))
function I = findClosest(x,q)
if q>max(x) || q<min(x)
warning('q outside the range of x');
end
[~,I] = min(abs(x-q));
end
Also; if you are certain that the exact value of the query point q exists in x, you can just do
cdf(x==q);
But beware of floating point errors though. You may think that a certain range outght to contain a certain value, but little did you know it was different by a tiny roundoff erorr. You can see that in action for example here:
x1 = linspace(0,1,1000); % Range
x2 = asin(sin(x1)); % Ought to be the same thing
plot((x1-x2)/eps); grid on; % But they differ by rougly 1 unit of machine precision
Old answer
As far as I can tell, running your code does reproduce the result of normcdf(x) well... If you want to do exactly what normcdf does them use erfc.
close all; clear; clc;
x = linspace(-5,5,1000);
cdf = normcdf(x); % Result of normcdf for comparison
%% 1 Trapezoidal integration of normal pd
p = 1/sqrt(2*pi) * exp((-x.^2)/2);
cdf1 = cumtrapz(x,p);
%% 2 But error function IS the integral of the normal pd
cdf2 = (1+erf(x/sqrt(2)))/2;
%% 3 Or, even better, use the error function complement (works better for large negative x)
cdf3 = erfc(-x/sqrt(2))/2;
fprintf('1: Mean error = %.2d\n',mean(abs(cdf1-cdf)));
fprintf('2: Mean error = %.2d\n',mean(abs(cdf2-cdf)));
fprintf('3: Mean error = %.2d\n',mean(abs(cdf3-cdf)));
plot(x,cdf1,x,cdf2,x,cdf3,x,cdf,'k--');
This gives me
1: Mean error = 7.83e-07
2: Mean error = 1.41e-17
3: Mean error = 00 <- Because that is literally what normcdf is doing
If your goal is not not to use predefined matlab funcitons, but instead to calculate the result numerically (i.e. calculate the error function) then it's an interesting challange which you can read about for example here or in this stats stackexchange post. Just as an example, the following piece of code calculates the error function by implementing eq. 2 form the first link:
nerf = #(x,n) (-1)^n*2/sqrt(pi)*x.^(2*n+1)./factorial(n)/(2*n+1);
figure(1); hold on;
temp = zeros(size(x)); p =[];
for n = 0:20
temp = temp + nerf(x/sqrt(2),n);
if~mod(n,3)
p(end+1) = plot(x,(1+temp)/2);
end
end
ylim([-1,2]);
title('\Sigma_{n=0}^{inf} ( 2/sqrt(pi) ) \times ( (-1)^n x^{2*n+1} ) \div ( n! (2*n+1) )');
p(end+1) = plot(x,cdf,'k--');
legend(p,'n = 0','\Sigma_{n} 0->3','\Sigma_{n} 0->6','\Sigma_{n} 0->9',...
'\Sigma_{n} 0->12','\Sigma_{n} 0->15','\Sigma_{n} 0->18','normcdf(x)',...
'location','southeast');
grid on; box on;
xlabel('x'); ylabel('norm. cdf approximations');
Marcin's answer suggests a way to find the nearest sample point. It is easier, IMO, to interpolate. Given x and t as defined in the question,
interp1(x,t,n)
returns the estimated value of the CDF at x==n, for whatever value of n. But note that, for values outside the computed range, it will extrapolate and produce unreliable values.
You can define an anonymous function that works like normcdf:
my_normcdf = #(n)interp1(x,t,n);
my_normcdf(-5)
Try replacing x with 0.01 when you call cumtrapz. You can either use a vector or a scalar spacing for cumtrapz (https://www.mathworks.com/help/matlab/ref/cumtrapz.html), and this might solve your problem. Also, have you checked the original x-values? Is the problem with linspace (i.e. you are not getting the correct x vector), or with cumtrapz?
I need some advice regarding a problem I encountered in MATLAB:
I have 4 variables, I'm not sure what is the best methodology to go about doing this. I initially thought about just computing the GreatCircle distance from each grid point to the specified location and return the corresponding row/column index that has the minimum distance. But doing it this way, I'm not sure how I can compute the interpolation.
I tried reshaping the data into a vector data of 4 columns and running meshgrid to possibly utilize interp2. But I ended up with this error:
Requested 109620x109620 (44.8GB) array exceeds maximum array size preference
What could be the most efficient way to do this?
You are working on large arrays. If interp2 cannot handle it, work on a subarray instead:
% Create data
format shortG
[Latitude,Longitude] = meshgrid(1:12,1:12);
Altitude = floor(1000+sortrows(rand(12,12))*1000);
Temperature = 10+20*rand(12,12);
Lat = 2.1;
Lon = 11.8;
% Find closest match point
[~,i_Lat] = min(abs(Latitude(1,:)-Lat));
[~,i_Lon] = min(abs(Longitude(:,1)-Lon));
% Select subarrays around this point.
% Minimum size of these matrices depend on the type of interpolation you perform
ia1 = max(1,i_Lat-5);
ia2 = min(size(Latitude,1),i_Lat+5);
io1 = max(1,i_Lon-5);
io2 = min(size(Latitude,2),i_Lon+5);
subLatitude = Latitude(io1:io2,ia1:ia2);
subLongitude = Longitude(io1:io2,ia1:ia2);
subAltitude = Altitude(io1:io2,ia1:ia2);
subTemperature = Temperature(io1:io2,ia1:ia2);
% Interpolate on these small arrays, and evaluate at target (Lat, Lon) point
A_out = interp2(subLatitude, subLongitude, subAltitude, Lat, Lon)
T_out = interp2(subLatitude, subLongitude, subTemperature, Lat, Lon)
I want to build a 3x3 block for a given matrix point with that point in the center of the block. This is my code :
function frmBlock = fetchNeighbors(frame, row, column)
%Create a 3x3 matrix contains the neighbors of the point(x, y)
%[n, m] = size(frame);
frmBlock = zeros(3, 3);
x = floor(row);
y = floor(column);
frmBlock(1) = frame(x-1, y-1);
frmBlock(2) = frame(x, y-1);
frmBlock(3) = frame(x+1, y+1);
frmBlock(4) = frame(x-1, y);
frmBlock(5) = frame(x, y);
frmBlock(6) = frame(x+1, y);
frmBlock(7) = frame(x-1, y+1);
frmBlock(8) = frame(x, y+1);
frmBlock(9) = frame(x+1, y-1);
end
As you can see, I create a 3x3 matrix initialized by 0. What I want to do is to fill that matrix with all the neighbors of the coordinate in input(row, column). If I can't get the neighbors for some reason I do nothing (i.e let that position in the 3x3 block as 0).
When I run this code I got an error saying:
Error using fetchNeighbors (line 12) Index exceeds matrix dimensions.
Can someone help ?
I'm guessing that the error is due to the fact that you are taking row and column to be on the boundaries of the matrix frame, and then when you try to access the element just right or left or below or above (depends on which boundary you are on), you are out of bounds and this raises the error. For example, if row equals 1, this means that at some point you are trying to access frame(0,column), which is illegal.
You can fix this by adding a check (using an if statement) before any access to the matrix, to make sure you are in bounds. I add here an alternative approach:
function frmBlock = fetchNeighbors(frame, row, column)
% Create a 3x3 matrix that contains the neighbors of the point (row,column)
[n,m] = size(frame);
neighbors_x = max(row-1,1):min(row+1,n);
neighbors_y = max(column-1,1):min(column+1,m);
frmBlock = zeros(3,3);
frmBlock(neighbors_x-row+2,neighbors_y-column+2) = frame(neighbors_x,neighbors_y);
end
I'm trying to perform STFT on an audio file. I need to get the fft of each window.
I used the follwing code.
[wave,fs] = wavread('40.wav');
w_length = 1024;
for v = 1:w_length:length(wave)
data_sub = wave(v:v+w_length);
subsection_fft = fft(data_sub);
figure(1)
plot(subsection_fft)
end
But i get the following error.
??? Index exceeds matrix dimensions.
Error in ==> chk at 7
data_sub = wave(v:v+w_length);
Can you tell me what I can do to rectify this.
As the error message says, you are trying to access a position in wave tat does not exist.
See this example:
a = rand(7,1);
step = 4;
1:step:7
ans =
1 5
when v = 5, you will try to access position v:v+step, i.e. 5 to 9, but a is only defined up to 7 elements.
In your case, wave is defined up to length(wave), but on the last iteration you will go out of bounds.
To avoid it, on approach would be to sample the end sequences and subtract the length of the sequence:
pos = (1+w_length:w_length:length(wave))-w_length
for v = pos
% do stuff
end
However, you will be left with some unprocessed part which you will have to do outside of the loop as last iteration.
Im extracting frames from video and plotting the slope value for the coordinates obtained in each line detected in each frame like below
Am plotting the "slope" value against "frames".
Extracting frames from video
for k = 1 :240 %no.of frames
%Here in loop am extracting the line from each frame then
[ycoord,xcoord]=find(line);%finding the coordinates of line
Ymax(k)=max(ycoord);
Ymin(k)=min(ycoord);
Xmax(k)=max(xcoord);
Xmin(k)=min(xcoord);
slope(k)=(Ymax(k)-Ymin(k)/Xmax(k)-Xmin(k));
end;
plot(slope,'-ro');%plotting slope values of frames
But when there is no line found in a frame then find(line) is giving empty arrays and there is no slope calculated showing error .
My requirement is when there is no line in the next frame then the slope value should be zero else it should calculate the slope value.
can some one please help on this
You can vectorize the code:
lines=[0,0,0,0,0,0; %# lines for example
0,0,1,2,3,0;
0,3,4,5,0,0];
lines(:,:,2)=[0,0,0,0,0,0;
0,0,0,0,0,0;
0,0,0,0,0,0];
bool_mask = double(lines ~= 0);
bool_mask(bool_mask == 0) = NaN; %# for later min function
[row_grid, col_grid] = ndgrid(1:size(lines,1), ...
1:size(lines,2), ....
1:size(lines,3));
min_row = squeeze(min(min(row_grid .* bool_mask,[],1)));
max_row = squeeze(max(max(row_grid .* bool_mask,[],1)));
min_col = squeeze(min(min(col_grid .* bool_mask,[],2)));
max_col = squeeze(max(max(col_grid .* bool_mask,[],2)));
slope = (max_row-min_row)./(max_col-min_col);
slope(isnan(slope)) = 0; %# x/0 is NaN, and absent line is NaN. Turn to 0.
slope
Gives output:
slope =
0.3333
0
I don't really understand your code, but in general, when find can't find something, it returns an empty matrix. You can use the isempty function to test if this is the case and manually set ycoord and xcoord to values that won't cause an error on.
isempty() MATLAB Documentation
Hope this helps!