Summation of piecewise functions in matlab - matlab

I have function y, whish is the sum of piecewise functions f0_basis and f1_basis (defined on [r_i-1; r_i+1]), multipled by number coefficients alpha and beta:
y=#(r) 0;
for j=1:1:N
y1= #(r) f0_basis(r ,j).*alpha(j)+f1_basis(r ,j).*beta(j);
y=#(r) y1(r)+y(r);
end
fplot(y,[a,b])
The fplot gives me what I want (a=1 and b=1.1):
However when I try, to find the value of y(r_i) - it always gives me the same wrong result for (a<r_i<b)
y(r_i)=-0.0016
which doesnt reperesents the plot above. Though if I try y(a) and y(b) - it gives me the right result.
What is wrong? I want to simply create an array y_array(i) = y(r_i).
N=11
a=1; b=1.1
delta_r=(b-a)/(N-1)
r_grid(i)=a+delta_r.*(i-1);
function y=f0_basis(r ,i)%i - номер середины узла
ri=r_grid(i);
r1=ri-delta_r;
r2=ri+delta_r;
y1=(2*((r-ri)/delta_r).^3-3*((r-ri)/delta_r).^2+1).*(r>=ri & r<=r2 & r2<=b);%правый конец
y2=(-2*((r-r1)/delta_r).^3+3*((r-r1)/delta_r).^2).*(r>=r1 & r<=ri & r1>=a);%левый конец
y3=0;%в сотальных случаях
y=y1+y2+y3;
end
function y=f1_basis(r ,i)%ri - середина узла
ri=r_grid(i);
r1=ri-delta_r;
r2=ri+delta_r;
r_div_1=(r-ri)/delta_r;
r_div_2=(r-r1)/delta_r;
y1=delta_r*(r_div_1.^3-2*(r_div_1.^2)+r_div_1).*(r>=ri & r<=r2 & r2<=b);%правый конец
y2=delta_r*(r_div_2.^3-r_div_2.^2).*(r>=r1 & r<=ri & r1>=a);%левый конец
y3=0;%в сотальных случаях
y=y1+y2+y3;
end
Alpha:
-0,000828144527478242
-0,000823822186226137
-0,000819532164240625
-0,000815314580859248
-0,000811187867518122
-0,000807162471718638
-0,000803245019928998
-0,000799439804012876
-0,000795750103056819
-0,000792175886650016
-0,000788726122705251
Beta:
-1,14781261976785e-05
-0,00257727396861173
-0,000627562853139588
0,000211869596648955
0,000683549308474220
0,000987694942326156
0,00119967671089174
0,00136043282028271
0,00145954455875083
0,00163805699746171
-0,000147024199470849
UPDATE:
it seems that y(r_i)=-0.0016 for only r_grid(i) array. If I try some r not from r_grid(i) array - it works fine.

I think your problem is in the functions f0_basis and f1_basis. You compute 2 terms inside each function (the 3rd one is null), each term is subject to some constraints. But the constraints are overlapping for one point, if r==ri. In this case, you are adding two equal terms, but nowhere else. That's why you have strange results at r_grid(i).
So change the tests, for example r>=r1 & r<ri & r1>=a for y2.

Related

vectorize a function with multiple variables

Consider the arbitrary function:
function myFunc_ = myFunc(firstInput, secondInput)
myFunc_ = firstInput * secondInput;
end
Now imagine I want to map the above function to an array for the first input firstInput, while the second input secondInput is constant. For example, something like:
firstVariable = linspace(0., 1.);
plot(firstVariable, map(myFunc, [firstVariable , 0.1]))
where 0.1 is an arbitrary scalar value for the secondInput and firstVariable array is an arbitrary array for the firstInput.
I have looked into the arrayfun() function. However, I don't know how to include the constant variable. Plus it seems like the syntax between MATLAB and Octave are different, or maybe I'm mistaken. It is important for me to have a cross-compatible code that I can share with colleagues.
Assuming in the original function you were multiplying two scalars and you want to vectorise, then
function myFunc_ = myFunc(firstInput, secondInput)
myFunc_ = firstInput .* secondInput;
end
should work just fine.
Then plot it directly:
plot( firstVariable, myFunc(firstVariable , 0.1) )
I'm afraid the arbitrary examples given in the original question were too simplified and as a result, they do not represent the actual issue I'm facing with my code. But I did manage to find the right syntax that works inside Octave:
plot(firstVariable, arrayfun(#(tempVariable) myFunc(tempVariable, 0.1), firstVariable))
basically the
#(tempVariable) myFunc(tempVariable, 0.1)
creates what is so-called an anonymous function and the
arrayfun(<function>, <array>)
maps the function over the given array.

Operations with function handle in matlab

Could you please help me with the following issue: I have the following function handle:
r1 = #(lambda) b + lambda*(r - b); % r and b are vectors of return data
I want to find the optimal lambdas that set me a mean function to zero, for a given set of powers within that function. What I tried to do and didn't work, as it returns me an error for undefined operators for input arguments of type 'function_handle' is:
lambda0 = 0.3;
for a = 2:10 %power coefficient
S1(a) = fzero(mean((r - b)*r1.^(1/(a - 1))),lambda0);
end
Any suggestion as to how to go about this problem is highly appreciated! Thank you in advance.
fzero accepts a function handle as the first input. As you currently have it, you're trying to pass a statement as the first input. This statement can't even be properly evaluated because you are trying to perform numerical operations on a function handle (more on this in a bit).
You need to instead do something like this where we create a new function handle that evaluates the original function handle and performs the other operations you need.
S1(a) = fzero(#(lambda)mean((r - b)*r1(lambda).^(1/(a - 1))),lambda0);
Further Explanation
Performing operations on a function handle is not the same as performing them on the result.
So for example, if we had a function handle:
func = #(x)2*x;
If we evaluation this, by calling it with an input value for x
func(2)
4
This works as we would expect. If now we really want the value (2*x)^2, we could try to write it the way that you wrote your statement in your question
func2 = func^2;
We will get an error!
Undefined operator '^' for input arguments of type 'function_handle'.
This does not work because MATLAB attempts to apply the ^ operation to the function handle itself and not the value of the evaluated function handle.
Instead, we would need to create a new function handle that essentially wraps the other one and performs any additional options:
func2 = #(x)func(x)^2;
func2(2)
16
Bringing it Full-Circle
So if we go back to your question, you defined your anonymous function r1 like this.
r1 = #(lambda) b + lambda*(r - b); % r and b are vectors of return data
This all looks great. You have one input argument and you reference r and b from the parent workspace.
Now when you call fzero you try to perform operations on this function handle in hopes of creating a new function handle.
mean((r - b)*r1.^(1/(a - 1)))
Like we just showed this will result in a very similar error
Undefined operator .^ for input arguments of type 'function_handle'
So we need to wrap this into a new function.
newfunc = #(lambda)mean((r - b)*r1(lambda).^(1 / (a - 1)));
Now we can safely pass this to fzero.
result = fzero(newfunc, lambda0);

Matlab ShortEng number format via sprintf() and fprintf()?

I like using MATLAB's shortEng notation in the interactive Command Window:
>> a = 123e-12;
>> disp(a);
1.2300e-10 % Scientific notation. Urgh!
>> format shortEng;
>> disp(a);
123.0000e-012 % Engineering notation! :-D
But I want to use fprintf:
>> format shortEng;
>> fprintf('%0.3e', a);
1.2300e-10 % Scientific. Urgh!
How do I print values with fprintf or sprintf with Engineering formatting using the MATLAB Format Operators?
I know I could write my own function to format the values into strings, but I'm looking for something already built into MATLAB.
NOTE: "Engineering" notation differs from "Scientific" in that the exponent is always a multiple of 3.
>> fprintf('%0.3e', a); % This is Scientific notation.
1.230000e-10
There is no way to use directly fprintf format specifier for the format you require. A way around is to use the output of disp as a string to be printed. But disp doesn't return a string, it writes directly to the standard output. So, how to do this?
Here's where evalc (eval with capture of output) comes to the rescue:
%// Create helper function
sdisp = #(x) strtrim(evalc(sprintf('disp(%g)', x)));
%// Test helper function
format ShortEng;
a = 123e-12;
fprintf(1, 'Test: %s', sdisp(a));
This is a workaround, of course, and can backfire in multiple ways because of the untested inputs of the helper functions. But it illustrates a point, and is one of the rare occasions where the reviled eval function family is actually irreplaceable.
You can use the following utility:
http://www.people.fas.harvard.edu/~arcrock/lib118/numutil/unpacknum.m
This will unpack the number also according to a given number N and makes sure that the exponent will be a multiple of N. By putting N=3 you have the Engineering Notation.
More into detail, unpacknum takes 3 arguments: the number x, the base (10 if you want Engineering Notation) and the value N (3 if you want Engineering Notation) and it returns the couple (f,e) which you can use in fprintf().
Check the unpacknum help for a quick example.
This function converts a value into a string in engineering notation:
function sNum = engn(value)
exp= floor(log10(abs(value)));
if ( (exp < 3) && (exp >=0) )
exp = 0; % Display without exponent
else
while (mod(exp, 3))
exp= exp - 1;
end
end
frac=value/(10^exp); % Adjust fraction to exponent
if (exp == 0)
sNum = sprintf('%+8.5G', frac);
else
sNum = sprintf('%+8.5GE%+.2d', frac, exp);
end
end
You can finetune the format to your liking. Usage in combination with fprintf is easy enough:
fprintf('%s\t%s\n', engn(543210.123), engn(-0.0000567)) % +543.21E+03 -56.7E-06
fprintf('%s\t%s\n', engn(-321.123), engn(876543210)) % -321.12 +876.54E+06
You can use the following utility posted to the MATLAB file exchange:
num2eng
It offers extensive control over the formatting of the output string and full input checking, so is more flexible and less prone to error than the simpler evalc approach suggested by user2271770.
It can also output strings using SI prefixes instead of engineering notation, if you prefer.

How can I plot these variables in Matlab?

I want to plot my variables for teta=0:360 degree. But I cant solve matrix problems. Plot all variables such as vc, ac, bzegon ,bdot.
teta=0:.1:2*pi;
w=2000*2*pi/60;l1=.05;l2=0.15;
beta=asin(l1/l2*sin(teta));
bdot=l1/l2*w*(cos(teta)./sin(beta));
xc=l1*cos.(teta)+l2*cos.(beta);
vc=-l1*w*sin.(teta)-l2*bdot.*sin.(beta);
bzegon=-l*w*(w*sin.(teta)*(xc-l1*cos.(teta))+cos.(teta)*(vc+l1*sin.(teta)))/((xc-l*cos. (teta))^2);
ac=-l1*w*cos.(teta)-l2*bzegon.*sin.(beta)-l2*bdot.*cos.(beta);
plot(teta,bdot);
set(gca,'XTick',0:pi/2:2*pi)
set(gca,'XTickLabel',{'0','pi/2','pi','3pi/2','2p'})
%title('bdot');
ylabel('bdot');
xlabel('radian');
replace:
xc=l1*cos.(teta)+l2*cos.(beta);
vc=-l1*w*sin.(teta)-l2*bdot.*sin.(beta);
bzegon=-l*w*(w*sin.(teta)*(xc-l1*cos.(teta))+cos.(teta)*(vc+l1*sin.(teta)))/((xc-l*cos. (teta))^2);
ac=-l1*w*cos.(teta)-l2*bzegon.*sin.(beta)-l2*bdot.*cos.(beta);
with:
xc=l1*cos(teta)+l2*cos(beta);
vc=-l1*w.*sin(teta)-l2*bdot.*sin(beta);
bzegon=-l1*w.*(w.*sin(teta).*(xc-l1*cos(teta))+cos(teta).*(vc+l1*sin(teta)))/((xc-l1*cos(teta)).^2);
ac=-l1*w.*cos(teta)-l2*bzegon.*sin(beta)-l2*bdot.*cos(beta);
You have to check all the parameters once again, maybe I messed up somewhere.
There are a lot of mistakes in your code with the . operator. You can't do cos.(beta), the . operator for element-by-element operation needs to be before things like multiply, add, subtract, raise to the power n, etc... Here's a corrected version of your code (I have assumed a scalar value for l which is not specified in your question):
teta=0:.1:2*pi;
w=2000*2*pi/60;l1=.05;l2=0.15;
l=l1+l2; % or whatever value, I assumed l was a scalar
beta=asin(l1/l2*sin(teta));
bdot=l1/l2*w*(cos(teta)./sin(beta));
xc=l1*cos(teta)+l2*cos(beta);
vc=-l1*w*sin(teta)-l2*bdot.*sin(beta);
bzegon=-l*w.*(w.*sin(teta).*(xc-l1*cos(teta))+cos(teta).*(vc+l1*sin(teta)))/((xc-l*cos(teta)).^2);
ac=-l1*w.*cos(teta)-l2*bzegon.*sin(beta)-l2*bdot.*cos(beta);
plot(teta,bdot);
set(gca,'XTick',0:pi/2:2*pi)
set(gca,'XTickLabel',{'0','pi/2','pi','3pi/2','2p'})
%title('bdot');
ylabel('bdot');
xlabel('radian');

Error running matlab code after compiling

It looks like this has been asked many times, but none of the past posts seem to solve my question. All those had to do with matrix/vector while my code does not have any of these, just simple variables. It takes three variables as arguments. It works perfectly fine within the Matlab environment. I only got the error when I compiled it with mcc -m Normal.m and tried to run with the executable like this "./Normal 1 5 0.5". The complete error message is:
Error using /
Matrix dimensions must agree.
Error in Normal (line 4)
MATLAB:dimagree
It is complaining about line 4: N=2/dt, what is wrong with this?
Here is the code:
function val=Normal(l1,l2,dt)
const=(l2/l1-1);
N=2/dt;
S=1.0/sqrt(l2/l1);
Z(1)=S;
for i=2:N
t= -1+(i-1)*dt;
Z(i)=1.0/sqrt(const*t*t+1);
S=S+2*Z(i);
end
Z(21)=1.0/(l2/l1);
S=S+1.0/sqrt(l2/l1);
val=dt*S/2;
end
But dt is not a scalar when passed into the standalone through the command ./Normal 1 5 0.5. It is a character array with 3 elements ('0', '.','5')!
When passing numerical arguments to a standalone, they are passed as strings. Thus, inside the function, you need to convert '0.5' into a double, and similarly for l1 and l2:
dt = str2num(dt);
l1 = str2num(l1);
l2 = str2num(l2);
Note that you can use isdeployed to determine at runtime if the function is a standalone:
if isdeployed, dt = str2num(dt); end
And you might need to display the result:
if isdeployed, disp(val); end
Result:
>> system('Normal 1 5 0.5');
1.4307
>> Normal(1,5,0.5) % .m function for comparison
ans =
1.4307