Handle function implicitly accounting for independent variables - matlab

I have that
clc, clear all, close all
tic
k1 = 1E-02:0.1:1E+02;
k2 = 1E-02:0.1:1E+02;
k3 = 1E-02:0.1:1E+02;
k = sqrt(k1.^2+k2.^2+k3.^2);
c = 1.476;
gamma = 3.9;
colors = {'b'};
Ek = (1.453*k.^4)./((1 + k.^2).^(17/6));
E = #(k) (1.453*k.^4)./((1 + k.^2).^(17/6));
E_int = zeros(1,numel(k));
E_int(1) = 1.5;
for i = 2:numel(k)
if k(i) < 400
E_int(i) = E_int(i-1) - integral(E,k(i-1),k(i));
elseif k(i) > 400
E_int(i) = 2.180/(k(i)^(2/3));
end %end if
end %end i
beta = (c*gamma)./(k.*sqrt(E_int));
figure
plot(k,beta,colors{1})
count = 0;
%F_11 = zeros(1,numel(k1));
F_33 = zeros(1,numel(k1));
Afterwards, I should calculate F_33 as
for i = 1:numel(k1)
count = count + 1;
phi_33 = #(k2,k3) (1.453./(4.*pi)).*(((k1(i)^2+k2.^2+(k3 + beta(i).*k1(i)).^2).^2)./((k1(i)^2+k2.^2+k3.^2).^2)).*((k1(i)^2+k2.^2)./((1+k1(i)^2+k2.^2+(k3+beta(i).*k1(i)).^2).^(17/6)));
F_33(count) = 4*integral2(phi_33,0,1000,0,1000);
end
Now let's come to my question. I know from a paper that:
k = sqrt(k1.^2+k2.^2+k3.^2);
k30 = k3 + beta.*k1;
k0 = sqrt(k1.^2+k2.^2+k30.^2);
E_k0 = 1.453.*(k0.^4./((1+k0.^2).^(17/6)));
Therefore the expression for phi_33 would result in
phi_33 = (E_k0./(4*pi.*(k.^4))).*(k1.^2+k2.^2);
The question is: how can I make use of this final expression insted of the long one I'm using at the moment (within the for loop)?
The last expression for phi_33 is easier to handle (especially because of reckless mistakes in writing the former) and it would "pass by reference" (k2,k3), which are the independent variables.
Any hint is more than welcome.
Best regards,
fpe

If I understand you correctly you want to use the new expression in exactly the same way as the old one-liner. You just want to divide your function phi33 into parts because of readability.
You could do this by placing the expression in a separate function taking all values needed for the calculation. Using your old expression exactly this would look something like this:
function phi_33 = phi_33_old(k1,k2,k3,beta,i)
phi_33 = (1.453./(4.*pi)).*(((k1(i)^2+k2.^2+(k3 + beta(i).*k1(i)).^2).^2)./((k1(i)^2+k2.^2+k3.^2).^2)).*((k1(i)^2+k2.^2)./((1+k1(i)^2+k2.^2+(k3+beta(i).*k1(i)).^2).^(17/6)));
end
This function could then be called inside your for-loop like this.
phi_33_test = #(k2,k3) phi_33_old(k1,k2,k3,beta,i);
Using the same style, a new function could be defined as follows.
function phi_33 = phi_33_new(k1,k2,k3,beta,i)
k = sqrt(k1.^2+k2.^2+k3.^2);
k30 = k3 + beta.*k1;
k0 = sqrt(k1.^2+k2.^2+k30.^2);
E_k0 = 1.453.*(k0.^4./((1+k0.^2).^(17/6)));
phi_33_allValues = (E_k0./(4*pi.*(k.^4))).*(k1.^2+k2.^2);
phi_33 = phi_33_allValues(i);
end
Note that here all values of phi_33 are calculated and then the ith value is selected. It is written in this way only to show the similarity to the old case. This new function can now be called inside the for-loop in the same way as the old one.
phi_33 = #(k2,k3) phi_33_new(k1,k2,k3,beta,i);

Related

Calculating numerical integral using integral or quadgk

I am using MATLAB to calculate the numerical integral of a complex function including natural exponent.
I get a warning:
Infinite or Not-a-Number value encountered
if I use the function integral, while another error is thrown:
Output of the function must be the same size as the input
if I use the function quadgk.
I think the reason could be that the integrand is infinite when the variable ep is near zero.
Code shown below. Hope you guys can help me figure it out.
close all
clear
clc
%%
N = 10^5;
edot = 10^8;
yita = N/edot;
kB = 8.6173324*10^(-5);
T = 300;
gamainf = 0.115;
dTol = 3;
K0 = 180;
K = K0/160.21766208;
nu = 3*10^12;
i = 1;
data = [];
%% lambda = ec/ef < 1
for ef = 0.01:0.01:0.1
for lambda = 0.01:0.01:0.08
ec = lambda*ef;
f = #(ep) exp(-((32/3)*pi*gamainf^3*(0.5+0.5*sqrt(1+2*dTol*K*(ep-ec)/gamainf)-dTol*K*(ep-ec)/gamainf).^3/(K*(ep-ec)).^2-16*pi*gamainf^3*(0.5+0.5*sqrt(1+2*dTol*K*(ep-ec)/gamainf)-dTol*K*(ep-ec)/gamainf).^2/((1+dTol*K*(ep-ec)/(gamainf*(0.5+0.5*sqrt(1+2*dTol*K*(ep-ec)/gamainf)-dTol*K*(ep-ec)/gamainf)))*(K*(ep-ec)).^2))/(kB*T));
q = integral(f,0,ef,'ArrayValued',true);
% q = quadgk(f,0,ef);
prob = 1-exp(-yita*nu*q);
data(i,1) = ef;
data(i,2) = lambda;
data(i,3) = q;
i = i+1;
end
end
I've rewritten your equations so that a human can actually understand it:
function integration
N = 1e5;
edot = 1e8;
yita = N/edot;
kB = 8.6173324e-5;
T = 300;
gamainf = 0.115;
dTol = 3;
K0 = 180;
K = K0/160.21766208;
nu = 3e12;
i = 1;
data = [];
%% lambda = ec/ef < 1
for ef = 0.01:0.01:0.1
for lambda = 0.01:0.01:0.08
ec = lambda*ef;
q = integral(#f,0,ef,'ArrayValued',true);
% q = quadgk(f,0,ef);
prob = 1 - exp(-yita*nu*q);
data(i,:) = [ef lambda q];
i = i+1;
end
end
function y = f(ep)
G = K*(ep - ec);
r = dTol*G/gamainf;
S = sqrt(1 + 2*r);
x = (1 + S)/2 - r;
Z = 16*pi*gamainf^3;
y = exp( -Z*x.^2.*( 2*x/(3*G.^2) - 1/(G.^2*(1 + r/x))) ) /...
(kB*T));
end
end
Now, for the first iteration, ep = 0.01, the value of the argument of the exp() function inside f is huge. In fact, if I rework the function to return the argument to the exponent (not the value):
function y = f(ep)
% ... all of the above
% NOTE: removed the exp() to return the argument
y = -Z*x.^2.*( 2*x/(3*G.^2) - 1/(G.^2*(1 + r/x))) ) /...
(kB*T);
end
and print its value at some example nodes like so:
for ef = 0.01 : 0.01 : 0.1
for lambda = 0.01 : 0.01 : 0.08
ec = lambda*ef;
zzz(i,:) = [f(0) f(ef/4) f(ef)];
i = i+1;
end
end
zzz
I get this:
% f(0) f(ef/4) f(ef)
zzz =
7.878426438111721e+07 1.093627454284284e+05 3.091140080273912e+03
1.986962280947140e+07 1.201698288371587e+05 3.187767404903769e+03
8.908646053687230e+06 1.325435523124976e+05 3.288027743119838e+03
5.055141696747510e+06 1.467952125661714e+05 3.392088351112798e+03
...
3.601790797707676e+04 2.897200140791236e+02 2.577170427480841e+01
2.869829209254144e+04 3.673888685004256e+02 2.404148067956737e+01
2.381082059148755e+04 4.671147785149462e+02 2.238181495716831e+01
So, integral() has to deal with things like exp(10^7). This may not be a problem per se if the argument would fall off quickly enough, but as shown above, it doesn't.
So basically you're asking for the integral of a function that ranges in value between exp(~10^7) and exp(~10^3). Needless to say, The d(ef) in the order of 0.01 isn't going to compensate for that, and it'll be non-finite in floating point arithmetic.
I suspect you have a scaling problem. Judging from the names of your variables as well as the equations, I would think that this has something to do with thermodynamics; a reworked form of Planck's law? In that case, I'd check if you're working in nanometers; a few factors of 10^(-9) will creep in, rescaling your integrand to the compfortably computable range.
In any case, it'll be wise to check all your units, because it's something like that that's messing up the numbers.
NB: the maximum exp() you can compute is around exp(709.7827128933840)

Calculating values in a for loop

I have a for loop that is storing values. For some reason, it is calculating values for all the number up to and including those in the for loop, instead of just the ones in the array.
t = 3600:50:172800;x = 0.1;y = 0; ro = 0.1;
T = zeros(1,length(t));
for Cm = 1E6:1E6:4E6
for i = 1:length(t)
T = T_ILS(x,y,ro,Cm,t);
Tall(Cm,:) = [T];
end
end
The error I get is "Requested 2000000x3385 array exceeds maximum array size preferences". I would like the for loop to calculate just the Cm values and not every number in between.
You are not computing every value in between, but your indices are messed up. Cm takes values in the millions, but you use it to index Tall(Cm,:). You probably want
t = 3600:50:172800;x = 0.1;y = 0; ro = 0.1;
T = zeros(1,length(t));
Cm = 1E6:1E6:4E6;
for j = 1:length(Cm)
for i = 1:length(t)
T(i) = T_ILS(x,y,ro,Cm(j),t(i));
end
Tall(j,:) = [T];
end
Notice that the main function call assigns to T(i) and uses t(i) in the function arguments to justify the existence of the for loop.
In the inner loop, T is the output of the function T_ILS, using the same arguments each time.
for i = 1:length(t)
T = T_ILS(x,y,ro,Cm,t);
Tall(Cm,:) = [T];
end
I don't know what this function computes, but you probably wanted to do this instead
for i = 1:length(t)
T = T_ILS(x,y,ro,Cm,t(i));
Tall(Cm,:) = [T];
end
to account for each value of the vector t, or even better:
for t = 3600:50:172800
T = T_ILS(x,y,ro,Cm,t);
Tall(Cm,:) = [T];
end
EDIT: Also, to make this answer complete, I'd like to merge #MadPhysicist's answer with mine. The result would be
Cm = 1E6:1E6:4E6; x = 0.1;y = 0; ro = 0.1;
T = zeros(1,length(t));
for i = 1:length(Cm)
for t = 3600:50:172800;
T = T_ILS(x,y,ro,Cm(i),t);
Tall(i,:) = [T];
end
end

MATLAB - Finding Zero of Sum of Functions by Iteration

I am trying to sum a function and then attempting to find the root of said function. That is, for example, take:
Consider that I have a matrix,X, and vector,t, of values: X(2*n+1,n+1), t(n+1)
for j = 1:n+1
sum = 0;
for i = 1:2*j+1
f = #(g)exp[-exp[X(i,j)+g]*(t(j+1)-t(j))];
sum = sum + f;
end
fzero(sum,0)
end
That is,
I want to evaluate at
j = 1
f = #(g)exp[-exp[X(1,1)+g]*(t(j+1)-t(j))]
fzero(f,0)
j = 2
f = #(g)exp[-exp[X(1,2)+g]*(t(j+1)-t(j))] + exp[-exp[X(2,2)+g]*(t(j+1)-t(j))] + exp[-exp[X(3,2)+g]*(t(j+1)-t(j))]
fzero(f,0)
j = 3
etc...
However, I have no idea how to actually implement this in practice.
Any help is appreciated!
PS - I do not have the symbolic toolbox in Matlab.
I suggest making use of matlab's array operations:
zerovec = zeros(1,n+1); %preallocate
for k = 1:n+1
f = #(y) sum(exp(-exp(X(1:2*k+1,k)+y)*(t(k+1)-t(k))));
zerovec(k) = fzero(f,0);
end
However, note that the sum of exponentials will never be zero, unless the exponent is complex. Which fzero will never find, so the question is a bit of a moot point.
Another solution is to write a function:
function [ sum ] = func(j,g,t,X)
sum = 0;
for i = 0:2*j
f = exp(-exp(X(i+1,j+1)+g)*(t(j+3)-t(j+2)));
sum = sum + f;
end
end
Then loop your solver
for j=0:n
fun = #(g)func(j,g,t,X);
fzero(fun,0)
end

Summing elements within an eval statement, in a for loop

I have written a complete code that runs in MATLAB, but outputs a slightly incorrect result. I need to get the following:
utotal
where
utotal = S1plot + S2plot + ...
until the digit equals (N/2) + 1, where N is even. If N = 10, say, the digit would be 6.
Then I need to evaluate utotal within the script. How can I achieve this?
This is what I have so far:
N = 10;
for alpha = 1:(N/2+1)
eval(['utotal = sum(S' num2str(alpha) 'plot);'])
end
but it doesn't work because it evaluates the following:
utotal = sum(S1plot);
utotal = sum(S2plot);
utotal = sum(S3plot);
utotal = sum(S4plot);
utotal = sum(S5plot);
utotal = sum(S6plot);
Thanks in advance for help.
Here's a workaround you can use for now. Note that this is extremely bad coding practice and the difficulty you're having now is only one of the reasons you shouldn't do it.
%// Generate random data
S1plot = randi(100,51,5);
S2plot = randi(100,51,5);
S3plot = randi(100,51,5);
S4plot = randi(100,51,5);
S5plot = randi(100,51,5);
S6plot = randi(100,51,5);
N = 10;
%// Put individual matrices into 3D matrix S
%// To access matrix Snplot, use S(:,:,n)
%// This is the format these variables should have been in in the first place
for alpha = 1:(N/2+1)
eval(['S(:,:,' num2str(alpha) ') = (S' num2str(alpha) 'plot);'])
end
%// Now sum along the third dimension
utotal = sum(S,3);
See the comments by #beaker. This solution does not do what the OP wants.
I haven't tested this but it should work.
N=10;
for alpha = 1:(N/2+1)
allSum = [allSum 'sum(S' num2str(alpha) 'plot)+'];
end
allSum(end)=';';
eval(['utotal = ' allSum]);
N = 10;
Result =0;
for alpha = 1:(N/2+1)
Result = Result + num2str(alpha)
end
eval(['utotal = sum(S' Result 'plot);'])

use nested functions in matlab M-file

i have question,about which i am too much interested,suppose that i have two M-file in matlab, in the first one i have described following function for calculating peaks and peaks indeces
function [peaks,peak_indices] = find_peaks(row_vector)
A = [0 row_vector 0];
j = 1;
for i=1:length(A)-2
temp=A(i:i+2);
if(max(temp)==temp(2))
peaks(j) = row_vector(i);
peak_indices(j) = i;
j = j+1;
end
end
end
and in second M-file i have code for describing sinusoidal model for given data sample
function [ x ]=generate(N,m,A3)
f1 = 100;
f2 = 200;
T = 1./f1;
t = (0:(N*T/m):(N*T))';
wn = rand(length(t),1).*2 - 1;
x = 20.*sin(2.*pi.*f1.*t) + 30.*cos(2.*pi.*f2.*t) + A3.*wn;
end
my question is how to combine it together?one solution would be just create two M-file into folder,then call function from one M-file and made operation on given vector and get result,and then call second function from another M file on given result and finally get what we want,but i would like to build it in one big M-file,in c++,in java,we can create classes,but i am not sure if we can do same in matlab too,please help me to clarify everything and use find_peaks function into generate function
UPDATED:
ok now i would like to show simple change what i have made in my code
function [ x ] = generate(N,m,A3)
f1 = 100;
f2 = 200;
T = 1./f1;
t = (0:(N*T/m):(N*T))'; %'
wn = rand(length(t),1).*2 - 1;
x = 20.*sin(2.*pi.*f1.*t) + 30.*cos(2.*pi.*f2.*t) + A3.*wn;
[pks,locs] = findpeaks(x);
end
i used findpeaks built-in function in matlab,but i am getting following error
generate(1000,50,50)
Undefined function 'generate' for input arguments of type 'double'.
also i am interested what would be effective sampling rate to avoid alliasing?
You can simply put both in one file. The file must have the same name as the first function therein, and you will not be able to access subsequently defined functions from outside that file. See the MATLAB documentation on functions http://www.mathworks.co.uk/help/matlab/ref/function.html (particularly the examples section).
Also note that MATLAB has a built-in function findpeaks().
(By the way, you're still sampling at too low a frequency and will most certainly get aliasing - see http://en.wikipedia.org/wiki/Aliasing#Sampling_sinusoidal_functions )
Edit: As you requested it, here is some more information on the sampling theorem. A good and simple introduction to these basics is http://www.dspguide.com/ch3/2.htm and for further reading you should search for the Shannon/Nyquist sampling theorem.
Try with this, within a single MATLAB script
function test()
clc, clear all, close all
x = generate(1000,50,50);
[p,i] = find_peaks(x)
end
function x = generate(N,m,A3)
f1 = 100;
f2 = 200;
T = 1./f1;
t = (0:(N*T/m):(N*T))'; %'
wn = rand(length(t),1).*2 - 1;
x = 20.*sin(2.*pi.*f1.*t) + 30.*cos(2.*pi.*f2.*t) + A3.*wn;
end
function [peaks,peak_indices] = find_peaks(row_vector)
A = [0;row_vector;0];
j = 1;
for i=1:length(A)-2
temp=A(i:i+2);
if(max(temp)==temp(2))
peaks(j) = row_vector(i);
peak_indices(j) = i;
j = j+1;
end
end
end