so i want to generate an eqution like theta= asind(x), then i make a program like this:
x=0.5:5
theta=asind(x)
if x>1
theta = out of range
otherwise x=<1
end
fprintf('theta')
but it gives an error:
xrdError: File: xrd.m Line: 4 Column: 17
Unexpected MATLAB expression.
please help me
A sensible thing to do is to set values which are invalid or missing to NaN (not a number). This can easily be done without a loop:
x=0.5:0.1:5; % changed spacing so there is more than one valid x
theta=asind(x);
theta(x>1)=NaN;
plot(x,theta); % will plot only the valid values
You said that you wanted the elements of theta to say "out of range" when the corresponding value of x is out of range, and otherwise to display the inverse sine of x.
This is a little odd in Matlab, because data in Matlab tends to be either arrays of numbers, or arrays of characters, but not a mixture of numbers and characters.
There is a way to mix numbers and characters by using what is called a cell array. A cell array can be created like this
cell1 = {};
cell2 = cell(5, 1);
and you assign and access the elements like this
cell1{1} = 'Hello';
cell1{2} = 7;
disp(cell{1})
So the program that (I think) you want to write would look something like
x = (0.5 : 5)';
theta = cell(size(x));
for i = 1:length(x)
if x(i) < -1 || x(i) > 1
theta{i} = 'Out of range';
else
theta{i} = asind(x(i));
end
end
x, theta
which outputs
x =
0.5000
1.5000
2.5000
3.5000
4.5000
theta =
[30.0000]
'Out of range'
'Out of range'
'Out of range'
'Out of range'
However, you should probably reconsider what it is you want your program to do, because a cell array is not a particularly easy data type to work with in Matlab.
Related
I have created code that does a Newton's Method approximation. It prints in a table-like format the approximation at each step and the associated error. I want to add a column that shows an integer value that represents the number of correct digits in approximation against the true value.
I am attempting to convert each cell of approximation into a string and counting how many digits are accurate. Example, approx. = 3.14555, true = 3.1555. The number of accurate digits will be 2. Although I have this idea in my head, I am doing it all wrong in my code below. Do you know how to create a proper loop to achieve this? I have less than a year of MATLAB experience; my mental toolbox is limited.
% Program Code of Newton's Method to find root
% This program will not produce a result if initial guess is too far from
% true value
clear;clc;format('long','g')
% Can work for various functions
%FUNCTION: 2*x*log(x)-2*log(x)*x^(3)+2*x^(2)*log(x)-x^(2)+1
%INTIAL GUESS: .01
%ERROR: 1.e-8
a=input('Enter the function in the form of variable x:','s');
x(1)=input('Enter Initial Guess:');
error=input('Enter allowed Error:');
% Passing through the function and calculating the derivative
f=inline(a);
dif=diff(str2sym(a));
d=inline(dif);
% Looping through Newton's Method
for i=1:100
x(i+1)=x(i)-((f(x(i))/d(x(i))));
err(i)=abs(x(i+1)-x(i));
% The loop is broken if acceptable error magnitude is reached
if err(i)<error
break
end
end
root=x(i);
Root = (x(:,1:(end-1)))';
Error = err';
disp('The final approximation is:')
disp(root)
%BELOW IS ALL WRONG, I AM TRYING TO ADD A COLUMN TO 'table'
%THAT SHOWS HOW MANY DIGITS IN APPROXIMATION IS ACCURATE
iter = 0;
y = zeros(1,length(x));
plot(x,y,'+')
zero1 = ('0.327967785331818'); %ACTUAL VALUE
for i = 1:length(Root)
chr = mat2str(Root(i))
for j = 1:length(chr(i))
if chr(i)~=zero1(i)
iter = 0;
return
elseif chr(i)==zero1(i)
iter = iter + 1;
acc(i) = iter
end
end
end
table(Root, Error) %ADD ACCURACY COLUMN HERE
Perhaps something like multiplying both numbers by powers of 10 and then flooring them until the answers are no longer equal:
approx=3.14555;
truth=3.1555;
approx1=0;
truth1=0;
i=0;
while approx1==truth1
approx1=floor(approx*10^i);
truth1=floor(truth*10^i);
i=i+1;
end
acc=i-1;
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 do not know what this error means or how to fix it. I am trying to perform an image rotation in a separate space of coordinates. When defining the reference space of the matrix to be at zero, I am getting the error that integers can only be comibined with integers of the same class or scalar doubles. the line is
WZcentered = WZ - [x0;yo]*ones(1,Ncols);
WZ is classified as a 400x299x3 unit 8, in the workspace. It is an image. x0 and y0 are set to 0 when the function is called. How can I fix this issue/what exactly is happening here?
Also, when I do the same thing yet make WZ to be equal to double(WZ) I get the error that 'matrix dimensions must agree.' I am not sure what the double function does however. Here is the whole code.
function [out_flag, WZout, x_final, y_final] = adopted_moveWZ(WZ, x0, y0);
%Initial Test of plot
[Nrows,Ncols]=size(WZ);
if Nrows ~= 2
if Ncols ==2
WZ=transpose(WZ); %take transpose
[Nrows,Ncols]=size(WZ); %reset the number of rows and columns
else
fprintf('ERROR: Input file should have 2-vectors for the input points.\n');
end
end
plot(WZ(1,:),WZ(2,:),'.')
title('These are the original points in the image');
pause(2.0)
%WZorig = WZ;
%centering
WZcentered = WZ - ([x0;y0] * ones(1,Ncols));
FigScale=400;
axis([-FigScale 2*FigScale -FigScale 2*FigScale])
disp('Hit any key to start the animation');
pause;
SceneCenter = zeros(Nrows,Ncols);
WZnew = WZcentered;
for ii=0:20
%rotate
R = [cos(pi/ii) -sin(pi/ii) 0; sin(pi/ii) cos(pi/ii) 0; 0 0 1];
WZnew = R * WZnew;
plot(WZnew(1,:),WZnew(2,:),'.')
%place WZnew at a different place in the scene
SceneCenter = (ii*[30;40])*ones(1,Ncols);
plot(SceneCenter(1,:) + WZnew(1,:), SceneCenter(2,:) + WZnew(2,:),'.')
axis([-FigScale 2*FigScale -FigScale 2*FigScale])
pause(1.0);
end
%Set final values for output at end of program
x_final = SceneCenter(1,1);
y_final = SceneCenter(2,1);
PPout = PPnew + SceneCenter;
This happens due to WZ and ([x0;y0] * ones(1,Ncols)) being of different data types. You might think MATLAB is loosely typed, and hence should do the right thing when you have a floating point type operated with an integer type, but this rule breaks every once in a while. A simpler example to demonstrate this is here:
X = uint8(magic(5))
Y = zeros(5)
X - Y
This breaks with the same error that you are reporting. One way to fix this is to force cast one of the operands to the other, typically up-casted to make sure the math works. When you do this, both the numbers you are working on are floating point (double precision), and so they are represented in the same byte formatting sequence in memory. This way, the '-' sign is valid, in the same way that you can say 3 apples + 4 apples = 7 apples, but 3 oranges (uint8) + 4 apples (double) = ?. The double(X) makes it clear that you really mean to use double precision arithmetic, and hence fixes the error. This is how it looks now:
double(X) - Y
After having identified this, the new error is 'matrix dimensions do not match'. This means exactly what it says. WZ is a 400x299x3 matrix, and the right hand side matrix is 2xnCols. Now can you subtract a 2D matrix from a 3D matrix of different sizes meaningfully?
Depending on what your code is really intending to do, you can pad the RHS matrix, or find out other ways to make the sizes equal.
All of this is why MATLAB includes routines to do image rotation, namely http://www.mathworks.com/help/images/ref/imrotate.html . This is part of the Image Processing Toolbox, though.
I want to compute using MATLAB all the integers x such that x^2-2x<2000, but I am having problems in the displaying part because when I run my code MATLAB seems not to finish. My code is as follows:
x=100;
while x^2+2x-2000>=10^-6
x=x-20;
if x^2+2x-2000<10^-6
disp(x)
end
end
I think the wrong part is when I type disp(x) in the while loop, but I don't know how to fix it.
NOTE: I am using the 10^-6 to avoid rounding errors
Can someone help me to fix this code please?
Computationally, finding all integers that satisfy this condition will need some help from a quick insight into this problem. Otherwise, you'll have to test all the integers, which is impossible since there is infinite number of integers. Analytically, finding all the integers that satisfy the condition x^2-2x < 2000 means finding the integers that lies within the intersection of the curve x^2 - 2x and y = 2000.
Let's first take a look at the problem by plotting it:
x = -500:.1:500;
y = x.^2 - 2*x;
plot(x, y, 'color', 'g')
hold on
line([-200 200], [2000 2000], 'color', 'r')
You can easily see that you can limit your search to at least between -100 and 100. You can store the value in an array
results = [] % Declare empty array first and append value later.
for x = -100:100
if x^2 - 2*x < 2000
disp(x)
results = [results,x]; % Using a bracket to append value to the array.
end
end
And a faster way to get results using logical indexing.
x = -100:100
results = x(x.^2 - 2*x<2000)
In the above code, x.^2 - 2*x < 2000 generates a logical array that has the same size as x. Each element stores the logical value that comes from the evaluating each element in x with the expression. You then use this as a mask to pick out only elements in x that satisfy this condition.
If you add in some parentheses and use the correct syntax for 2*x, it works.
x=100;
while (x^2+2*x-2000)>= (10^-6)
x=(x-20);
if (x^2+2*x-2000) <10^-6
disp(x)
end
end
Building upon #User3667217's solution, you can also vectorise this:
x = -100:100;
y = x.^2-2*x;
tmp = y<2000;
results = y(tmp);
this will give you a speed up over the for-loop solution.
I'm trying to quantize a set of double type samples with 128 level uniform quantizer and I want my output to be double type aswell. When I try to use "quantize" matlab gives an error: Inputs of class 'double' are not supported. I tried "uencode" as well but its answer was nonsense. I'm quite new to matlab and I've been working on this for hours. Any help appriciated. Thanks
uencode is supposed to give integer results. Thats the point of it. but the key point is that it assumes a symmetric range. going from -x to +x where x is the largest or smallest value in your data set. So if your data is from 0-10 your result looks like nonsense because it quantizes the values on the range -10 to 10.
In any event, you actually want the encoded value and the quantized value. I wrote a simple function to do this. It even has little help instructions (really just type "help ValueQuantizer"). I also made it very flexible so it should work with any data size (assuming you have enough memory) it can be a vector, 2d array, 3d, 4d....etc
here is an example to see how it works. Our number is a Uniform distribution from -0.5 to 3.5 this shows that unlike uencode, my function works with nonsymmetric data, and that it works with negative values
a = 4*rand(2,4,2) - .5
[encoded_vals, quant_values] = ValueQuantizer(a, 3)
produces
a(:,:,1) =
0.6041 2.1204 -0.0240 3.3390
2.2188 0.1504 1.4935 0.8615
a(:,:,2) =
1.8411 2.5051 1.5238 3.0636
0.3952 0.5204 2.2963 3.3372
encoded_vals(:,:,1) =
1 4 0 7
5 0 3 2
encoded_vals(:,:,2) =
4 5 3 6
1 1 5 7
quant_values(:,:,1) =
0.4564 1.8977 -0.0240 3.3390
2.3781 -0.0240 1.4173 0.9368
quant_values(:,:,2) =
1.8977 2.3781 1.4173 2.8585
0.4564 0.4564 2.3781 3.3390
so you can see it returns the encoded values as integers (just like uencode but without the weird symmetric assumption). Unlike uencode, this just returns everything as doubles rather than converting to uint8/16/32. The important part is it also returns the quantized values, which is what you wanted
here is the function
function [encoded_vals, quant_values] = ValueQuantizer(U, N)
% ValueQuantizer uniformly quantizes and encodes the input into N-bits
% it then returns the unsigned integer encoded values and the actual
% quantized values
%
% encoded_vals = ValueQuantizer(U,N) uniformly quantizes and encodes data
% in U. The output range is integer values in the range [0 2^N-1]
%
% [encoded_vals, quant_values] = ValueQuantizer(U, N) uniformly quantizes
% and encodes data in U. encoded_vals range is integer values [0 2^N-1]
% quant_values shows the original data U converted to the quantized level
% representing the number
if (N<2)
disp('N is out of range. N must be > 2')
return;
end
quant_values = double(U(:));
max_val = max(quant_values);
min_val = min(quant_values);
%quantizes the data
quanta_size = (max_val-min_val) / (2^N -1);
quant_values = (quant_values-min_val) ./ quanta_size;
%reshapes the data
quant_values = reshape(quant_values, size(U));
encoded_vals = round(quant_values);
%returns the original numbers in their new quantized form
quant_values = (encoded_vals .* quanta_size) + min_val;
end
As far as I can tell this should always work, but I haven't done extensive testing, good luck