Is there a way in Octave to vectorize sprintf()?
See the example, below. The iterative branch works as expected. When I set vectorize_sprintf=1, I don't get the desired effect. Instead of filling the LABELS cell array with one string per cell, all of the strings are concatenated into the first cell of LABELS and the remaining cells are left empty.
Is there a good way to vectorize number to string processing?
%%
%% Graph e^x and ln()
%%
top=8; %% highest power to graph
pow_vec = [0:top]';
ex_vec = e .^ pow_vec;
ln_vec = log(ex_vec);
LABELS=cell(size(ex_vec)); %% Pre-allocate cell matrix
vectorize_sprintf=1;
if ( vectorize_sprintf )
%% Vectorize attempt at sprintf is BROKEN
LABELS=sprintf("%d = log2(%d)\n",ln_vec,ex_vec)
else
%% Iterate for sprintf WORKS
counter=1;
for i = pow_vec'
LABELS(counter++) = sprintf("e^%d=%d\nln(%d)=%d",pow_vec(counter),ex_vec(counter) ,ex_vec(counter) ,ln_vec(counter));
endfor
endif
figure(1); %% Graph e^x
hold on;
plot(ln_vec, ex_vec, "r-"); %% solid red line segments
plot(ln_vec, ex_vec, "rx"); %% markers on the datapoints
text(ln_vec, ex_vec, LABELS);
figure(2); %% Graph ln()
hold on;
plot(ex_vec, ln_vec, "r-"); %% solid red line segments
plot(ex_vec, ln_vec, "rx"); %% markers on the datapoints
text(ex_vec, ln_vec, LABELS);
Your vectorization attempt is not filling the first cell of LABELS, it is actually converting it to a char array (take a look at whos LABELS). I think sprintf always returns a single string only. Since you're using \n, maybe you could use strsplit to get a cell array.
ex_vec = e .^ [0:8];
ln_vec = log(ex_vec);
LABELS = strsplit (sprintf ("%.0f = log2(%.4f)\n", [ln_vec; ex_vec]), "\n")(1:end-1)
I have made the following changes to what you had before:
don't transpose the [0:8] so you get a row, and you don't have to transpose it again when generating a matrix for sprintf
replaced the %d by %.0f and %.4f. It's specially important the %.0f because log (e^8) = 8.0000 but what is used in the string is fix (log (e^8)) which is 7. Alternatively, you can round ln_vec
Related
I am trying to solve the following ODE using Octave, and in particular the function ode45.
dx/dt = x(1-x/2), 0<= t <= 10
with the initial condition x(0) = 0.5
But the graphs I get are not what I expect.
I think that the graph with red crosses represents x' vs x and not x vs t.
The code is the following:
clear all
close all
% Differential Equation: x' = x(1-x/2)
function dx = f(x,t)
dx = x*(1-x./2);
endfunction
% Exacte Solution: 2*e^t/(3+e^t)
function xexac =solexac(t)
xexac = (2*exp(t))./(3+exp(t));
endfunction
x0=0.5; %%Initial condition
T=10; %% maximum time T
t=[0:0.1:T]; %% we choose the times t(k) where is calculated 'y'
sol=ode45(#f,[0,T],x0); %% numerical solution of (E)
tt=sol.x;y=sol.y; %% extraction of the results
clf;hold on ; %% plot the exact and numerical solutionss
plot(tt,y,'xr')
plot(t,solexac(t),'-b')
xlabel('t')
ylabel('x(t)')
title('Chemostat Model')
legend("Numerical Solution","Exacte Solution ")
It would we great that any of you could help me with this code.
ode45 expects the ODE function to have arguments in the order (time, state), so exactly the other way around. What you effectively did was integrate t-t^2/2, and the resulting function 0.5+t^2/2-t^3/6 is what you got in the plot.
I have code similar to the one below, where a function with a parameter depending on the loop iteration is plotted after every iteration. I would like to save the plot with the name trigplot_i.ps where i is the iteration number, but don't know how.
I have tried trigplot_"i".ps but didn't work, and have not been able to find how to cast i to a string either.
I'm a beginner so any help is very welcome.
f(x) := sin(x);
g(x) := cos(x);
for i:1 thru 10 do
(plot2d([i*f(x), i*g(x)], [x,-5,5],[legend,"sin(x)","cos(x)"],
[xlabel,"x"],[ylabel,"y"],
[ps_file,"./trigplot_i.ps"],
[gnuplot_preamble,"set key box spacing 1.3 top right"])
);
code after edits gives an error:
f(x) := sin(x);
g(x) := cos(x);
for i:1 thru 10
do block([myfile],
myfile: sconcat("./trigplot_", i, ".ps"),
printf (true, "iteration ~d, myfile = ~a~%", myfile),
plot2d([i*f(x), i*g(x)], [x,-5,5],[legend,"sin(x)","cos(x)"],
[xlabel,"x"],[ylabel,"y"],
[ps_file, myfile],
[gnuplot_preamble,"set key box spacing 1.3 top right"])
);
error:
"declare: argument must be a symbol; found "./trigplot_1.ps
-- an error.
To debug this try: debugmode(true);"
Looks good. To construct a file name, try this: sconcat("./trigplot_", i, ".ps") or also you can try: printf(false, "./trigplot_~d.ps", i). My advice is to make that a separate step in the loop, and then you can use it in the call to plot2d, e.g.:
for i:1 thru 10
do block ([myfile],
myfile: sconcat("./trigplot_", i, ".ps"),
printf (true, "iteration ~d, myfile = ~a~%", i, myfile),
plot2d (<stuff goes here>, [ps_file, myfile], <more stuff>));
EDIT: Fixed a bug in printf (omitted argument i).
# the unit of period is picosecond
set period 625000.0
set period_sec [format %3.6g [expr $period * 1e-12]]
puts $period_sec
result: 6.25e-07
Is there a way to force tcl to get results like 625e-09
Assuming that you want to format it to the nearest exponent, you could use a proc which formats it like this:
proc fix_sci {n} {
# Not a sci-fmt number with negative exponent
if {![string match "*e-*" $n]} {return $n}
# The set of exponents
set a 9
set b 12
# Grab the number (I called it 'front') and the exponent (called 'exp')
regexp -- {(-?[0-9.]+)e-0*([0-9]+)} $n - front exp
# Check which set of exponent is closer to the exponent of the number
if {[expr {abs($exp-$a)}] < [expr {abs($exp-$b)}]} {
# If it's the first, get the difference and adjust 'front'
set dif [expr {$exp-$a}]
set front [expr {$front/(10.0**$dif)}]
set exp $a
} else {
# If it's the first, get the difference and adjust 'front'
set dif [expr {$exp-$b}]
set front [expr {$front/(10.0**$dif)}]
set exp $b
}
# Return the formatted numbers, front in max 3 digits and exponent in 2 digits
return [format %3ge-%.2d $front $exp]
}
Note that your original code returns 6.25e-007 (3 digits in the exponent).
If you need to change the rule or rounding the exponent, you will have to change the if part (i.e. [expr {abs($exp-$a)}] < [expr {abs($exp-$b)}]). For example $exp >= $a could be used to format if the exponent is 9 or below.
ideone demo of above code for 'closest' exponent.
For Tcl versions before 8.5, use pow(10.0,$dif) instead of 10.0**$dif
I do not think there is anything in the format command that will help you directly. However, if you consider a slight variation on the format code, then it may be a lot easier to get what you want (with a bit of string manipulation):
format %#3.6g $number
gives a number like: 6.25000e-007
This can be parsed more easily:
Extract the exponent
Determine the number of positions to shift the decimal point
Shift it and replace the exponent
It is not entirely straightforward, I am afraid, but it should be doable. Wiki page http://wiki.tcl.tk/5000 may give you some inspiration.
I'm using matlab to plot this code which should plot Theta ( dimensionless temperature at different times(t) ), when I try to run it I get this error "Undefined function 'times' for input arguments of type 'cell'"
t=1:1:5;
alfa=(1.172.*(10.^(-2))); ......
% alfa for steel with 1% carbon = 1.172*10^-2 m^2/s%
L=1;
T={(alfa.*t)./(L.^2)}; % dimensionless time equation %
lambda1=0.3111; % # biot =0.1 %
A1=1.0161; % # biot =0.1 %
theta={A1.*exp(-(lambda1.^2).*T)}; % dimensionless Temperature equation %
plot(t,theta,'.');
I'm still a beginner in matlab & programming in general.
For some reason you're using cell arrays at line 5 and 8 (the curly braces {}). Just remove them and your code will plot...
Regards
Can someone dumb it down and explain, how this code fragment from a previous answer here works ?
bbsl(Bin,Shift) -> <<_:Shift,Rest/bits>> = Bin, <<Rest/bits,0:Shift>>.
bbsl(Bin, Shift) -> % function accepts binary and number
<< _:Shift, % match Shift number of bits into dummy variable _ and
Rest/bits>> = Bin, % puts rest of the bits into Rest variable from Bin variable
<< Rest/bits, % start creating new binary with bits from Rest at beginning
0:Shift >>. % and Shift number of 0's in the end
hope that made sense