Using a function handle with equation and Simpson's rule - matlab

I'm working on a problem that applies a luminosity equation:
E = 64.77* T^−4 ∫ x^−5( e^(1.432/Tx) -1 )^−1 dx
Where T = 3500;
to simp son's rule which is a few sums and such.
problem 17.8 here: http://my.safaribooksonline.com/book/computer-aided-engineering/9780123748836/-introduction-to-numerical-methods/ch17lev1sec10
What I've done is made a function simpson(fn, a, b, h) that runs simp son's rule correctly.
however, the problem is making that integral equation into a function handle that works. I've gotten it to work for simple function handles like
f = #x x.^2
but when I try and make the integral into a function:
fn = #(x)(64.77/T^4).*integral((x.^(-5)).*((exp(((1.432)./(3500.*x)))).^(-1)), 4e-5, 7e-5);
simp(fn, 5, 15, 1)
function s = simp(fn, a, b, h)
x1 = a + 2*h:2*h:b-2*h;
sum1 = sum(feval(fn, x1));
x2 = a + h:22*h:b-h;
sum2 = sum(feval(fn, x2));
s = h/3*(feval(fn, a) + feval(fn, b) + 4*sum2 + 2*sum1);
it doesn't work. error message is Integral: first input must be function handle.
Any help appreciated.

You're supposed to be evaluating the integral using Simpsons rule, whereas you are using integral to calculate the integral, then fn is not a function of x. You want to do this:
fn = #(x)(x.^(-5)).*((exp(((1.432)./(3500.*x)))).^(-1));
I=simp(fn,a,b,h);
E=(64.77/T^4)*I;

Related

Using a function that has another function as parameter:

I want to integrate x^2 from 2 to 4 with the trapezoidal integration method. For this, I defined a function trap that takes 4 arguments:
function y = trap( fn, a, b, h )
n = (b-a)/h;
x = a + [1:n-1]*h;
y = h/2*(feval(fn, a) + feval(fn, b) + 2*sum(feval(fn,x)));
and a function f
function y= f(x)
y=x^2
end
Now, by executing trap(f,2,4,0.1), I get the following error:
Not enough input arguments.
Error in f (line 2)
y=x^2
What is the origin of that error?
You have to call trap using the function handle #f, not f.
trap(#f,2,4,0.1)
function y = trap( fn, a, b, h )
n = (b-a)/h;
x = a + [1:n-1]*h;
y = h/2*(fn(a) + fn(b) + 2*sum(fn(x)));
end
function y= f(x)
y = x.^2;
end
which gives, as expected,
ans =
18.67
Also you needed element-wise multiplication in f(x) to compute y = x.^2.
And feval is not necessary. You can directly call fn(a) to evaluate the function.

Problems attaching a function handle on Matlab to integral expression

I have an integral expression which I defined on Matlab using
x = 0:1/1000:1;
g = #(x) (exp(-1./x.^2).*heaviside(x)).*(exp(-1./(1-x).^2).*heaviside(1-x));
t = 0:1/1000:1;
f = zeros(size(t));
for i = 1:length(t)
f(i) = integral(g,0,t(i));
end
I can plot it, for example, using plot(t,f), but for other purposes I would like to attach a function handle to f, i.e. something like f = #(t) zeros(size(t)). I have not been able to figure it out thus far. f = #(t) integral(#(x)g(x),0,t) is also not sufficient.
Sorry, I can't comment yet. But does this work?
funcHand= #(t) integral(g,0,t);
You don't have to define x in your code above, since the input to integral is a function handle.
Then to check it's the same:
f2 = zeros(size(t));
for i = 1:length(t)
f2(i) = funcHand(t(i));
end
Whoops, the other answer said all the above (just replaced the for loop with arrayfun. I didn't see it while writing the answer.
Edit
If you want to build-in the for loop, try:
funcHand= #(t) arrayfun(#(u) integral(g, 0, u),t);
And test:
plot(funcHand(t))
Try
f = #(u) integral(g, 0, u)
The additional level of indirection in g seems superfluous. Note that I have called the input u. Keep in mind that f will not accept vectors as its inputs. So doing something like f(t) in your current workspace will not create the same array as your for loop is doing. You will have to iterate through the array. The convenience function arrayfun will do this for you:
o = arrayfun(f, t)
It is roughly equivalent to the loop you have now:
o = zeros(size(t));
for i = 1:length(o)
o(i) = f(t(i));
end
arrayfun can actually be incorporated into your function handle to allow it to process vector arguments:
h = #(t) arrayfun(f, t)
To avoid the proliferation of unnecessary function handles, you can do
f = #(t) arrayfun(#(u) integral(g, 0, u), t)

How to write/code several functions as one

I am trying to write a line composed of two segments as a single equation in :
y = m1*x + c1 , for x<=x1
y = m2*x + c2 , for x>=x1
My questions are:
How can I write the function of this combined line as a single equation?
How can I write multiple functions (valid in separate regions of a linear parameter space) as a single equation?
Please explain both how to express this mathematically and how to program this in general and in Matlab specifically.
You can write this equation as a single line by using the Heaviside step function, https://en.wikipedia.org/wiki/Heaviside_step_function.
Combining two functions into one:
In fact, what you are trying to do is
f(x) = a(x) (for x < x1)
f(x) = q (for x = x1), where q = a(x1) = b(x1)
f(x) = b(x) (for x > x1)
The (half-maximum) Heaviside function is defined as
H(x) = 0 (for x < 0)
H(x) = 0.5 (for x = 0)
H(x) = 1 (for x > 0)
Hence, your function will be
f(x) = H(x1-x) * a(c) + H(x-x1) * b(x)
and, therefore,
f(x) = H(x1-x) * (m1*x+c1) + H(x-x1) * (m2x+c2)
If you want to implement this, note that many programming languages will allow you to write something like
f(x) = (x<x1)?a(x):b(x)
which means if x<x1, then return value a(x), else return b(x), or in your case:
f(x) = (x<x1)?(m1*x+c1):(m2x+c2)
Matlab implementation:
In Matlab, you can write simple functions such as
a = #(x) m1.*x+c1,
b = #(x) m2.*x+c2,
assuming that you have previously defined m1, m2, and c1, c2.
There are several ways to using/implementing the Heaviside function
If you have the Symbolic Math Toolbox for Matlab, you can directly use heaviside() as a function.
#AndrasDeak (see comments below) pointed out that you can write your own half-maximum Heaviside function H in Matlab by entering
iif = #(varargin) varargin{2 * find([varargin{1:2:end}], 1, 'first')}();
H = #(x) iif(x<0,0,x>0,1,true,0.5);
If you want a continuous function that approximates the Heaviside function, you can use a logistic function H defined as
H = #(x) 1./(1+exp(-100.*x));
Independently of your implementation of the Heaviside function H, you can, create a one-liner in the following way (I am using x1=0 for simplicity) :
a = #(x) 2.*x + 3;
b = #(x) -1.5.*x + 3;
Which allows you to write your original function as a one-liner:
f = #(x) H(-x).*a(x) + H(x).*b(x);
You can then plot this function, for example from -10 to 10 by writing plot(-10:10, f(-10:10)) you will get the plot below.
Generalization:
Imagine you have
f(x) = a(x) (for x < x1)
f(x) = q (for x = x1), where q = a(x1) = b(x1)
f(x) = b(x) (for x1 < x < x2)
f(x) = r (for x = x2), where r = b(x2) = c(x2)
f(x) = c(x) (for x2 < x < x3)
f(x) = s (for x = x2), where s = c(x3) = d(x3)
f(x) = d(x) (for x3 < x)
By multiplying Heaviside functions, you can now determine zones where specific functions will be computed.
f(x) = H(x1-x)*a(c) + H(x-x1)*H(x2-x)*b(x) + H(x-x2)*H(x3-x)*c(x) + H(x-x3)*d(x)
PS: just realized that one of the comments above talks about the Heaviside function, too. Kudos to #AndrasDeak .

Matlab - "Could not extract differential variables to solve for" in dsolve

I am trying to solve a RLC circuit as a symbolic differential equation in MATLAB using dsolve, the equation being
U(t) = L*Q''(t) + R*Q'(t) + (1/C)*Q(t)
with the initial conditions
Q(0) = 0
Q'(0) = 0
and
U(t) = 10*sin(2*t)
L = 1
R = 0
C = 1/4
While this works ...
When I implement it explicitly (and using strings) as
Q = dsolve('D2Q(t) + 4*Q(t) = 10*sin(2*t)', 'DQ(0)=0, Q(0)=0');
Q = simplify(Q);
I'll get
Q =
5 sin(2 t) 5 t cos(2 t)
---------- - ------------
4 2
which is correct.
... this does not.
For purely esoteric reasons I tried computing it directly using symbolic equations, as the documentation on dsolve stated it could be done.
So starting with
syms L R C t Q(t)
U = sym('10')*sin(sym('2')*t)
DEQ = L*diff(Q(t),t,2) + R*diff(Q(t),t) + (1/C)*Q(t)
DEQ = subs(DEQ, [L R C], [sym('1'), sym('0'), sym('1/4')])
eqn = (U == DEQ)
I receive
eqn =
10*sin(2*t) == 4*Q(t) + diff(Q(t), t, t)
Which is correct. If I now feed it into dsolve though, using
Q = dsolve(eqn, ...
Q(t) == 0, ...
diff(Q(t),t) == 0);
Matlab throws the error
Error using symengine (line 58)
Could not extract differential variables to solve for. Use 'solve' or 'vpasolve'
to compute the solutions of non-differential equations.
Why is that?
It looks like you're using sym/diff and symfuns incorrectly. Q(t) is what is referred to as an arbitrary (help sym/diff uses the term "abstract" instead) symbolic function, i.e., a function with no definition. Your function's name is Q (think of it as a function handle) and it is represented by the abstract formula Q(t), which just means that it's a function of t. When you want to take the derivative of an abstract function, pass in the name of the function - in your case, Q (the online documentation makes this slightly clearer, but not really). When you want evaluate the function use the formula, e.g., Q(0), the output of which is a sym rather than a symfun.
Here is how I might write the code for your second case:
syms L R C t Q(t)
U = 10*sin(2*t); % No need to wrap integer or exactly-represenable values in sym
dQ = diff(Q,t);
d2Q = diff(dQ,t);
DEQ = L*d2Q + R*dQ + Q/C;
DEQ = subs(DEQ, {L, R, C}, {1, 0, 1/4});
eqn = (U == DEQ);
Q = dsolve(eqn, Q(0) == 0, dQ(0) == 0);
Q = simplify(Q)
which returns
Q =
(5*sin(2*t))/4 - (5*t*cos(2*t))/2
You also forgot to evaluate your initial conditions at zero in the second case so I fixed that too. By the way, in current versions of Matlab you should be using the pure symbolic form for symbolic math (as opposed to strings).

Using inline function with constant arguments in MATLAB

This is a part of my code.
clear all;
clc;
p = 50;
t = [-6 : 0.01 : 6];
f = inline('(t+2).*sin(t)', 't')
v = inline('3*f(p*t+2)','t','f','p')
plot(t,f(t));
v(t,f,p);
figure;
plot(t,v(t,f,p));
Here I have two questions.
Why I have to pass p into the function v even though p is a constant which has already declared ?
How I can get an expression for v completely in terms of t as 3*[(50*t+2)*sin(50*t+2)] or in its simplified form ?
Update
This is an update for the second question
Let
f(x) = 1 + x - x^2
g(x) = sin(x)
If I give f(g(x)), I wanna get the output in words, like this
f(g(x)) = (cos(X))^2 + sin(x)
not in numerical value. Is there any function capable to do that?
1) Why do I have to pass p to v even though p is a constant which has already been declared?
Well, a MATLAB's inline function object has an eval wrapper, so the only variables in its scope are those which were automatically captured from the expression or explicitly specified.
In other words, if you want v to recognize p, you have no other option but declaring it when creating the inline object and passing it to v explicitly. The same goes for f as well!
2) How I can get an expression for v completely in terms of t as 3*[(50*t+2)*sin(50*t+2)] or in its simplified form?
Use anonymous functions, like Shai suggested. They are more powerful, more elegant and much faster. For instance:
v = #(t)(3*(50*t+2)*sin(50*t+2))
Note that if you use a name, which is already in use by a variable, as an argument, the anonymous function will treat it as an argument first. It does see other variables in the scope, so doing something like g = #(x)(x + p) is also possible.
EDIT #1:
Here's another example, this time a function of a function:
x = 1:5;
f = #(x)(x .^ 3); %// Here x is a local variable, not as defined above
g = #(x)(x + 2); %// Here x is also a local variable
result = f(g(x));
or alternatively define yet another function that implements that:
h = #(x)f(g(x)); %// Same result as h = #(x)((x + 2) .^ 3)
result = h(x);
The output should be the same.
EDIT #2:
If you want to make an anonymous function out of the expression string, concatenate the '#(x)' (or the correct anonymous header, as you see fit) to the beginning and apply eval, for example:
expr = '(x + 2) .^ 3';
f = eval(['#(x)', expr]) %// Same result as f = #(x)((x + 2) .^ 3)
Note that you can also do char(f) to convert it back into a string, but you'll have to manually get rid of the '#(...)' part.
EDIT #3:
If you're looking for a different solution, you can explore the Symbolic Toolbox. For example, try:
syms x
f(x) = x + 2
g(x) = x ^ 3
or can also use sym, like so:
f(x) = sym('x + 2');
g(x) = sym('x ^ 3');
Use subs to substitute values and evaluate the symbolic expression.
How about using anonymous functions:
p = 50;
t = -6:0.01:6;
f = #(x) (x+2).*sin(x);
v = #(x) 3*f(p*x+2);
figure;
subplot(1,2,1); plot( t, f(t) ); title('f(t)');
subplot(1,2,2); plot( t, v(t) ); title('v(t)');
Is this what you wanted?
Adding a constant into an inline can be done during its definition.
Instead of
p = 50;
v = inline('3*f(p*t+2)','t','f','p')
You can write
p = 50;
v = inline( sprintf('3*f(%f*t+2)', p), 't','f')