matlab can't use dot operator on object - matlab

I came across a weird problem today while practicing using classes in MATLAB. It seems like MATLAB can't parse parentheses around an object.
I created a user-defined class named vector that has various attributes: magnitude, angle, length in the x and y directions. I overloaded the unary minus operator so that I can have
a = vector(5,50) % creates a vector with magnitude 5 and angle 50 (in degrees)
a.ang % prints the angle
b = -a
b.ang % 230 degrees
This is all fine and good, but say that I want to find the angle of the -a in one line. You'd expect something like
(-a).ang
to work but instead I get
(-a).ang
|
Error: Unexpected MATLAB operator.
I can't use
-a.ang
either because the dot operator has higher precedence than the minus. Any explanation of why matlab can't parse parentheses around an object?
EDIT: Here's the vector class that I created.
classdef vector
properties
mag
ang % in degrees
x
y
end
methods
function v = vector(mag,ang)
if nargin == 2
v.mag = mag;
v.ang = ang;
v.x = mag*cosd(ang);
v.y = mag*sind(ang);
end
end
function res = plus(u,v)
x = u.x + v.x;
y = u.y + v.y;
res = vector(norm([x,y]), atan2d(y,x));
end
function res = minus(u,v)
x = u.x - v.x;
y = u.y - v.y;
res = vector(norm([x,y]), atan2d(y,x));
end
function res = uminus(v)
res = vector;
res.x = -v.x;
res.y = -v.y;
res.mag = v.mag;
res.ang = mod(v.ang+180,360);
end
end
end

I think I've found the answer. In general, Matlab does not support two sets of parentheses chained together because it could either be an indexing or a function call.
MATLAB's parser is limited, partly for historical reasons. It has never
been possible to do something like f(4)(1) because of the ambiguity. Does it mean that f(4) is a function handle and then we want to pass 1 into that function or does it mean that f is a function, we pass 4 into that function, it returns a vector and then we index into the first element of that? Well, the parser doesn't know either. It could be defined, but it hasn't up till now.
Source: https://www.mathworks.com/matlabcentral/newsreader/view_thread/280225
Also, once I had realized that the two side-by-side parentheses were the problem, it seems that the main workarounds are either:
Use the SUBSREF function to explicitly evaluate the parentheses
Define your own anonymous function to perform the indexing and array handling for you.
Those workarounds are explained in the first two answers in the below link.
How can I index a MATLAB array returned by a function without first assigning it to a local variable?
Thanks for looking over my question guys!

I cannot replicate vector function but for a simple structure like this
a.ang=[2,4,6,8]
what you need is
-a.ang
instead of
(-a).ang
which will reproduce the error you mentioned

Related

Implementing my own FFT in MATLAB giving wrong results

I'm trying to implement my own fft in MATLAB the following way:
function z=FastFourierTransform(x)
N=length(x);
if N <= 1
z = x;
else
range = (0:N/2-1);
e = exp(-2i*pi/N).^range;
odd = FastFourierTransform(x(1:2:N-1));
even = e.*FastFourierTransform(x(2:2:N));
z = [even + odd, even - odd];
end
return
Turns out, there seems to be somthing wrong with it since it does not give the same result as the built in function provided by MATLAB.
I'm calling the function the following way:
N = 128;
x = 32*pi*(1:N)'/N;
u = cos(x/16).*(1+sin(x/16));
actualSolution = fft(u);
actualSolution
mySolution = FastFourierTransform(u)';
mySolution
actualSolution
mySolution
The numbers are always the same but they sometimes differ in their sign.
You have swapped odd and even.
Using this line to compute z will produce the correct FFT:
z = [odd + even, odd - even];
My guess is that the source of confusion is that Matlab uses 1-based indices, and the pseudocode you used to implement the function uses 0-based indices.

Two functions in Matlab to approximate integral - not enough input arguments?

I want to write a function that approximates integrals with the trapezoidal rule.
I first defined a function in one file:
function[y] = integrand(x)
y = x*exp(-x^2); %This will be integrand I want to approximate
end
Then I wrote my function that approximates definite integrals with lower bound a and upper bound b (also in another file):
function [result] = trapez(integrand,a,b,k)
sum = 0;
h = (b-a)/k; %split up the interval in equidistant spaces
for j = 1:k
x_j = a + j*h; %this are the points in the interval
sum = sum + ((x_j - x_(j-1))/2) * (integrand(x_(j-1)) + integrand(x_j));
end
result = sum
end
But when I want to call this function from the command window, using result = trapez(integrand,0,1,10) for example, I always get an error 'not enough input arguments'. I don't know what I'm doing wrong?
There are numerous issues with your code:
x_(j-1) is not defined, and is not really a valid Matlab syntax (assuming you want that to be a variable).
By calling trapez(integrand,0,1,10) you're actually calling integrand function with no input arguments. If you want to pass a handle, use #integrand instead. But in this case there's no need to pass it at all.
You should avoid variable names that coincide with Matlab functions, such as sum. This can easily lead to issues which are difficult to debug, if you also try to use sum as a function.
Here's a working version (note also a better code style):
function res = trapez(a, b, k)
res = 0;
h = (b-a)/k; % split up the interval in equidistant spaces
for j = 1:k
x_j1 = a + (j-1)*h;
x_j = a + j*h; % this are the points in the interval
res = res+ ((x_j - x_j1)/2) * (integrand(x_j1) + integrand(x_j));
end
end
function y = integrand(x)
y = x*exp(-x^2); % This will be integrand I want to approximate
end
And the way to call it is: result = trapez(0, 1, 10);
Your integrandfunction requires an input argument x, which you are not supplying in your command line function call

Double integral with variable limits over implicit function in MATLAB

I'm experiencing the problem because of variable limit and implicit funtion being together.
So let's simplify it to this:
s(y)=y - our "implicit" function
Int [Int(x*s(y)*dy, 1,x)*dx, 1, 2] - our double integral (which equals 9/8).
(So you can even separate in into 2 integral I_small= s(y)dy and I=I_small * x*dx)
All that I figured out:
1) I tried using quad2d (so there is no ploblem with variable limit) - but I can't put the root of implicit function in it . So it wotks for non-implicit function:
function main
quad2d(#myfun,1,2,1,#(x)x)
end
function value=myfun(x,y)
value=x.*y;
end
But for implicit I've tried that - and it doesn't work. I know there is something wrong with this code - matlab doesn't understand that argument "y" in function name and "y" in the function itself are the same. But don't know how to fix it.
function main
quad2d(#myfun,1,2,1,#(x)x)
end
function value=myfun(x,y)
f=#(s,y)s-y;
value=x.*fzero(#(s)f(y,s), 0.5);
end
2) This code solves the opposite I = s(x).*y and I can't understand how to switch x to y because fzero doesnt work if I place y in it instead of x(j)
function main
quad(#myfun, 0,1)
end
function z=myfun(x)
z=zeros(size(x));
f=#(x,s) s-x;
for j=1:length(x);
s(j)=fzero(#(s)f(x(j),s), 0.5);
h=#(y) (s(j).*y);
z(j)=quad(h,1,x(j));
end
end
3) I also tried the nested quads, but it only works with constant limits. Can't fiqure it out how instead of Upperlimit should I place #(x)x.
function main
quad(#(y)y.*first_int(2),1,2)
end
function value=first_int(UpperLimit)
value=quad(#(x)yfunction(x,1),1,UpperLimit);
end
function value=yfunction(x,l)
syms y;
f=#(x,y) l.*x-y;
for k=1:length(x)
value(k)=fzero(#(y)f(x(k),y), 0.5);
end
Could you guys help with that?
The command quad2d (as its modern and better counterpart integral2) requires that the function to be integrated accept matrices as inputs.
The function Z=FUN(X,Y) must accept 2D matrices X and Y of the same size and return a matrix Z of corresponding values.
On the other hand, fzero only solves one equation, not a whole bunch of them at once. So, in order for your implicit function to accept matrix inputs, it needs to be written with a loop:
function value = myfun(x,y)
f=#(s,y)s-y;
value = zeros(size(x));
for i=1:size(x,1)
for j=1:size(x,2)
value(i,j) = x(i,j)*fzero(#(s) f(y(i,j),s), 0.5);
end
end
end
Then quad2d(#myfun,1,2,1,#(x)x) or integral2(#myfun,1,2,1,#(x)x) will work.

Evaluate Matlab symbolic function

I have a problem with symbolic functions. I am creating function of my own whose first argument is a string. Then I am converting that string to symbolic function:
f = syms(func)
Lets say my string is sin(x). So now I want to calculate it using subs.
a = subs(f, 1)
The result is sin(1) instead of number.
For 0 it works and calculates correctly. What should I do to get the actual result, not only sin(1) or sin(2), etc.?
You can use also use eval() to evaluate the function that you get by subs() function
f=sin(x);
a=eval(subs(f,1));
disp(a);
a =
0.8415
syms x
f = sin(x) ;
then if you want to assign a value to x , e.g. pi/2 you can do the following:
subs(f,x,pi/2)
ans =
1
You can evaluate functions efficiently by using matlabFunction.
syms s t
x =[ 2 - 5*t - 2*s, 9*s + 12*t - 5, 7*s + 2*t - 1];
x=matlabFunction(x);
then you can type x in the command window and make sure that the following appears:
x
x =
#(s,t)[s.*-2.0-t.*5.0+2.0,s.*9.0+t.*1.2e1-5.0,s.*7.0+t.*2.0-1.0]
you can see that your function is now defined by s and t. You can call this function by writing x(1,2) where s=1 and t=1. It should generate a value for you.
Here are some things to consider: I don't know which is more accurate between this method and subs. The precision of different methods can vary. I don't know which would run faster if you were trying to generate enormous matrices. If you are not doing serious research or coding for speed then these things probably do not matter.

MATLAB Function (Solving an Error)

I have one file with the following code:
function fx=ff(x)
fx=x;
I have another file with the following code:
function g = LaplaceTransform(s,N)
g = ff(x)*exp(-s*x);
a=0;
b=1;
If=0;
h=(b-a)/N;
If=If+g(a)*h/2+g(b)*h/2;
for i=1:(N-1)
If=If+g(a+h*i)*h;
end;
If
Whenever I run the second file, I get the following error:
Undefined function or variable 'x'.
What I am trying to do is integrate the function g between 0 and 1 using trapezoidal approximations. However, I am unsure how to deal with x and that is clearly causing problems as can be seen with the error.
Any help would be great. Thanks.
Looks like what you're trying to do is create a function in the variable g. That is, you want the first line to mean,
"Let g(x) be a function that is calculated like this: ff(x)*exp(-s*x)",
rather than
"calculate the value of ff(x)*exp(-s*x) and put the result in g".
Solution
You can create a subfunction for this
function result = g(x)
result = ff(x) * exp(-s * x);
end
Or you can create an anonymous function
g = #(x) ff(x) * exp(-s * x);
Then you can use g(a), g(b), etc to calculate what you want.
You can also use the TRAPZ function to perform trapezoidal numerical integration. Here is an example:
%# parameters
a = 0; b = 1;
N = 100; s = 1;
f = #(x) x;
%# integration
X = linspace(a,b,N);
Y = f(X).*exp(-s*X);
If = trapz(X,Y) %# value returned: 0.26423
%# plot
area(X,Y, 'FaceColor',[.5 .8 .9], 'EdgeColor','b', 'LineWidth',2)
grid on, set(gca, 'Layer','top', 'XLim',[a-0.5 b+0.5])
title('$\int_0^1 f(x) e^{-sx} \,dx$', 'Interpreter','latex', 'FontSize',14)
The error message here is about as self-explanatory as it gets. You aren't defining a variable called x, so when you reference it on the first line of your function, MATLAB doesn't know what to use. You need to either define it in the function before referencing it, pass it into the function, or define it somewhere further up the stack so that it will be accessible when you call LaplaceTransform.
Since you're trying to numerically integrate with respect to x, I'm guessing you want x to take on values evenly spaced on your domain [0,1]. You could accomplish this using e.g.
x = linspace(a,b,N);
EDIT: There are a couple of other problems here: first, when you define g, you need to use .* instead of * to multiply the elements in the arrays (by default MATLAB interprets multiplication as matrix multiplication). Second, your calls g(a) and g(b) are treating g as a function instead of as an array of function values. This is something that takes some getting used to in MATLAB; instead of g(a), you really want the first element of the vector g, which is given by g(1). Similarly, instead of g(b), you want the last element of g, which is given by g(length(g)) or g(end). If this doesn't make sense, I'd suggest looking at a basic MATLAB tutorial to get a handle on how vectors and functions are used.