I have the following 2n*π-periodic function F(x) = sin(x/n) and I need to graph the dx/dt = γ - F(x) on the segment from 0 to 2pi. So it should look like this. I tried to do it matlab this way:
gamma = 1.01;
n=3;
[t,phi] = ode45(#(t,x)gamma-sin(x/n), [0,400], pi);
[t1,phi1] = ode45(#(t,x)gamma-sin(x/n), [112,400], 0);
[t2,phi2] = ode45(#(t,x)gamma-sin(x/n), [231,250], 0);
figure();
plot(t, phi, 'k', t1, phi1, 'k', t2, phi2, 'k');
ylim([0 2*pi]);
yticks([0 pi 2*pi]);
yticklabels(["0" "\pi" "2\pi"]);
grid on; grid minor;
title('\itsin(x/n)')
but I only got something like this. So there the lines are not transferred, but "begin anew". does anyone here know how to do that?
I get a plot similar to your first sketch, and based on your code in the comments (in future, put such additions into the question itself, use formatting to mark it as addition, and cite it then in the comment) with the changes
use pi as initial point as seen in the drawing,
use the options of the ODE solver to restrict the step size, directly and by imposing error tolerances
your original time span covers about 3 periods, reduce this to [0, 200] to get the same features as the drawing.
gamma = 1.01; n=3;
opts = odeset('AbsTol',1e-6,'RelTol',1e-9,'MaxStep',0.1);
[t, phi] = ode45(#(t,x)gamma-sin(x/n), [0,200], pi, opts);
phi = mod(phi, 2*pi);
plot(t, phi, 'k');
ylim([0 2*pi]); yticks([0 pi 2*pi]); yticklabels(["0" "\pi" "2\pi"]);
grid on; grid minor;
title('\itsin(x/n)')
To get more elaborate, use events to get points on the numerical solution where it exactly crosses the 2*pi periods, then use that to segment the solution plot (styling left out)
function [ res, term, dir ] = event(t,y)
y = mod(y+pi,2*pi)-pi;
res = [ y ];
dir = [1]; % only crossing upwards
term = [0]; % do not terminate
end%function
opts = odeset(opts,'Events',#(t,y)event(t,y));
sol = ode45(#(t,x)gamma-sin(x/n), [0,200], pi, opts);
tfs = [ sol.xe; sol.x(end) ]
N = length(tfs)
clf;
t0 = 0;
for i=1:N
tf = tfs(i);
t = linspace(t0+1e-2,tf-1e-2,150);
y = deval(sol,t); % octave: deval=#(res,t) interp1(res.x, res.y,t)
y = mod(y,2*pi);
plot(t, y);
hold on;
t0=tf;
end;
hold off;
Is there a way in mathematica to have variable coefficients for NDSolve? I need to vary the coefficient values and create multiple graphs, but I cannot figure out a way to do it short of reentering the entire expression for every graph. Here is an example (non-functional) of what I would like to do; hopefully it is close to working:
X[\[CapitalDelta]_, \[CapitalOmega]_, \[CapitalGamma]_] =
NDSolve[{\[Rho]eg'[t] ==
(I*\[CapitalDelta] - .5*\[CapitalGamma])*\[Rho]eg[t] -
I*.5*\[CapitalOmega]*\[Rho]ee[t] +
I*.5*\[CapitalOmega]*\[Rho]gg[t],
\[Rho]ge'[t] == (-I*\[CapitalDelta] - .5*\[CapitalGamma])*\[Rho]ge[t] +
I*.5*\[CapitalOmega]\[Conjugate]*\[Rho]ee[t] -
I*.5*\[CapitalOmega]\[Conjugate]*\[Rho]gg[t],
\[Rho]ee'[t] == -I*.5*\[CapitalOmega]\[Conjugate]*\[Rho]eg[t] +
I*.5*\[CapitalOmega]*\[Rho]ge[t] - \[CapitalGamma]*\[Rho]ee[t],
\[Rho]gg'[t] == I*.5*\[CapitalOmega]\[Conjugate]*\[Rho]eg[t] -
I*.5*\[CapitalOmega]*\[Rho]ge[t] + \[CapitalGamma]*\[Rho]ee[t],
\[Rho]ee[0] == 0, \[Rho]gg[0] == 1, \[Rho]ge[0] == 0, \[Rho]eg[0] == 0},
{\[Rho]ee, \[Rho]eg, \[Rho]ge, \[Rho]gg}, {t, 0, 12}];
Plot[Evaluate[\[Rho]ee[t] /. X[5, 2, 6]], {t, 0, 10},PlotRange -> {0, 1}]
In this way I would only have to re-call the plot command with inputs for the coefficients, rather than re-enter the entire sequence over and over. That would make things much cleaner.
PS: Apologies for the awful looking code. I never realized until now that mathematica didn't keep the character conversions.
EDIT a nicer formatted version:
You should just use SetDelayed (":=") instead of Set in the function definition:
X[\[CapitalDelta]_, \[CapitalOmega]_, \[CapitalGamma]_] :=
NDSolve[{\[Rho]eg'[
t] == (I*\[CapitalDelta] - .5*\[CapitalGamma])*\[Rho]eg[t] -
I*.5*\[CapitalOmega]*\[Rho]ee[t] +
I*.5*\[CapitalOmega]*\[Rho]gg[t], \[Rho]ge'[
t] == (-I*\[CapitalDelta] - .5*\[CapitalGamma])*\[Rho]ge[t] +
I*.5*\[CapitalOmega]\[Conjugate]*\[Rho]ee[t] -
I*.5*\[CapitalOmega]\[Conjugate]*\[Rho]gg[t], \[Rho]ee'[
t] == -I*.5*\[CapitalOmega]\[Conjugate]*\[Rho]eg[t] +
I*.5*\[CapitalOmega]*\[Rho]ge[t] - \[CapitalGamma]*\[Rho]ee[
t], \[Rho]gg'[t] ==
I*.5*\[CapitalOmega]\[Conjugate]*\[Rho]eg[t] -
I*.5*\[CapitalOmega]*\[Rho]ge[t] + \[CapitalGamma]*\[Rho]ee[
t], \[Rho]ee[0] == 0, \[Rho]gg[0] == 1, \[Rho]ge[0] ==
0, \[Rho]eg[0] ==
0}, {\[Rho]ee, \[Rho]eg, \[Rho]ge, \[Rho]gg}, {t, 0, 12}];
Plot[Evaluate[{\[Rho]ee[t] /. X[5, 2, 6], \[Rho]ee[t] /.
X[2, 6, 17]}], {t, 0, 10}, PlotRange -> {0, 1}]
Can I format an Erlang binary so that each byte is written in hex? I.e.,
> io:format(???, [<<255, 16>>]).
<<FF, 10>>
I don't see an obvious way to do it in io:format documentation, but perhaps I am simply missing one? Converting a binary to list and formatting its elements separately is too inefficient.
No, there is not such formating option but you can do something like:
io:format("<<~s>>~n", [[io_lib:format("~2.16.0B",[X]) || <<X:8>> <= <<255,16>> ]]).
There is a lot faster solution if you need.
-module(bin_to_hex).
-compile([native, {hipe, [o3]}]).
-export([bin_to_hex/1]).
bin_to_hex(B) when is_binary(B) ->
bin_to_hex(B, <<>>).
-define(H(X), (hex(X)):16).
bin_to_hex(<<>>, Acc) -> Acc;
bin_to_hex(Bin, Acc) when byte_size(Bin) band 7 =:= 0 ->
bin_to_hex_(Bin, Acc);
bin_to_hex(<<X:8, Rest/binary>>, Acc) ->
bin_to_hex(Rest, <<Acc/binary, ?H(X)>>).
bin_to_hex_(<<>>, Acc) -> Acc;
bin_to_hex_(<<A:8, B:8, C:8, D:8, E:8, F:8, G:8, H:8, Rest/binary>>, Acc) ->
bin_to_hex_(
Rest,
<<Acc/binary,
?H(A), ?H(B), ?H(C), ?H(D), ?H(E), ?H(F), ?H(G), ?H(H)>>).
-compile({inline, [hex/1]}).
hex(X) ->
element(
X+1, {16#3030, 16#3031, 16#3032, 16#3033, 16#3034, 16#3035, 16#3036,
16#3037, 16#3038, 16#3039, 16#3041, 16#3042, 16#3043, 16#3044,
16#3045, 16#3046, 16#3130, 16#3131, 16#3132, 16#3133, 16#3134,
16#3135, 16#3136, 16#3137, 16#3138, 16#3139, 16#3141, 16#3142,
16#3143, 16#3144, 16#3145, 16#3146, 16#3230, 16#3231, 16#3232,
16#3233, 16#3234, 16#3235, 16#3236, 16#3237, 16#3238, 16#3239,
16#3241, 16#3242, 16#3243, 16#3244, 16#3245, 16#3246, 16#3330,
16#3331, 16#3332, 16#3333, 16#3334, 16#3335, 16#3336, 16#3337,
16#3338, 16#3339, 16#3341, 16#3342, 16#3343, 16#3344, 16#3345,
16#3346, 16#3430, 16#3431, 16#3432, 16#3433, 16#3434, 16#3435,
16#3436, 16#3437, 16#3438, 16#3439, 16#3441, 16#3442, 16#3443,
16#3444, 16#3445, 16#3446, 16#3530, 16#3531, 16#3532, 16#3533,
16#3534, 16#3535, 16#3536, 16#3537, 16#3538, 16#3539, 16#3541,
16#3542, 16#3543, 16#3544, 16#3545, 16#3546, 16#3630, 16#3631,
16#3632, 16#3633, 16#3634, 16#3635, 16#3636, 16#3637, 16#3638,
16#3639, 16#3641, 16#3642, 16#3643, 16#3644, 16#3645, 16#3646,
16#3730, 16#3731, 16#3732, 16#3733, 16#3734, 16#3735, 16#3736,
16#3737, 16#3738, 16#3739, 16#3741, 16#3742, 16#3743, 16#3744,
16#3745, 16#3746, 16#3830, 16#3831, 16#3832, 16#3833, 16#3834,
16#3835, 16#3836, 16#3837, 16#3838, 16#3839, 16#3841, 16#3842,
16#3843, 16#3844, 16#3845, 16#3846, 16#3930, 16#3931, 16#3932,
16#3933, 16#3934, 16#3935, 16#3936, 16#3937, 16#3938, 16#3939,
16#3941, 16#3942, 16#3943, 16#3944, 16#3945, 16#3946, 16#4130,
16#4131, 16#4132, 16#4133, 16#4134, 16#4135, 16#4136, 16#4137,
16#4138, 16#4139, 16#4141, 16#4142, 16#4143, 16#4144, 16#4145,
16#4146, 16#4230, 16#4231, 16#4232, 16#4233, 16#4234, 16#4235,
16#4236, 16#4237, 16#4238, 16#4239, 16#4241, 16#4242, 16#4243,
16#4244, 16#4245, 16#4246, 16#4330, 16#4331, 16#4332, 16#4333,
16#4334, 16#4335, 16#4336, 16#4337, 16#4338, 16#4339, 16#4341,
16#4342, 16#4343, 16#4344, 16#4345, 16#4346, 16#4430, 16#4431,
16#4432, 16#4433, 16#4434, 16#4435, 16#4436, 16#4437, 16#4438,
16#4439, 16#4441, 16#4442, 16#4443, 16#4444, 16#4445, 16#4446,
16#4530, 16#4531, 16#4532, 16#4533, 16#4534, 16#4535, 16#4536,
16#4537, 16#4538, 16#4539, 16#4541, 16#4542, 16#4543, 16#4544,
16#4545, 16#4546, 16#4630, 16#4631, 16#4632, 16#4633, 16#4634,
16#4635, 16#4636, 16#4637, 16#4638, 16#4639, 16#4641, 16#4642,
16#4643, 16#4644, 16#4645, 16#4646}).
Which performs 90MB/s on mine notebook i5 CPU M 520 # 2.40GHz when tested on 10MB chunks. But optimization was brought to the extreme there. It can also do 97MB if using 16bit lookup but it is crazy and too long to post here.
Improving upon #hairyhum
This takes care of zero paddings
<< <<Y>> ||<<X:4>> <= Id, Y <- integer_to_list(X,16)>>
reverse transformation
<<<<Z>> || <<X:8,Y:8>> <= Id,Z <- [binary_to_integer(<<X,Y>>,16)]>>, %%hex to binary
This hasn’t seen any action for a while, but all of the prior solutions seem overly convoluted.
Here’s what, for me, seems much simpler:
[begin if N < 10 -> 48 + N; true -> 87 + N end end || <<N:4>> <= Bin]
If you prefer it expanded a bit:
[begin
if
N < 10 ->
48 + N; % 48 = $0
true ->
87 + N % 87 = ($a - 10)
end
end || <<N:4>> <= Bin]
You could do:
[ hd(erlang:integer_to_list(Nibble, 16)) || << Nibble:4 >> <= Binary ]
Which would return you a list(string) containing the hex digits of the binary. While I doubt the efficiency of this operation is going to have any effect on the runtime of your system, you could also have this bin_to_hex function return an iolist which is simpler to construct and will be flattened when output anyway. The following function returns an iolist with the formatting example you gave:
bin_to_hex(Bin) when is_binary(Bin) ->
JoinableLength = byte_size(Bin) - 1,
<< Bytes:JoinableLength/binary, LastNibble1:4, LastNibble2:4 >> = Bin,
[ "<< ",
[ [ erlang:integer_to_list(Nibble1, 16), erlang:integer_to_list(Nibble2, 16), ", " ]
|| << Nibble1:4, Nibble2:4 >> <= Bytes ],
erlang:integer_to_list(LastNibble1, 16),
erlang:integer_to_list(LastNibble2, 16),
" >>" ].
It's a bit ugly, but runs through the binary once and doesn't traverse the output list (otherwise I'd have used string:join to get the interspersed ", " sequences). If this function is not the inner loop of some process (I have a hard time believing this function will be your bottleneck), then you should probably go with some trivially less efficient, but far more obvious code like:
bin_to_hex(Bin) when is_binary(Bin) ->
"<< " ++ string:join([byte_to_hex(B) || << B >> <= Bin ],", ") ++ " >>".
byte_to_hex(<< N1:4, N2:4 >>) ->
[erlang:integer_to_list(N1, 16), erlang:integer_to_list(N2, 16)].
Here is another short and fast version which I use:
hexlify(Bin) when is_binary(Bin) ->
<< <<(hex(H)),(hex(L))>> || <<H:4,L:4>> <= Bin >>.
hex(C) when C < 10 -> $0 + C;
hex(C) -> $a + C - 10.
if you prefer to make a binary string instead of erlang default list strings, you may use binary comprehension syntax, like what I did on my sha1 generating code:
1> << << if N >= 10 -> N -10 + $a;
1> true -> N + $0 end >>
1> || <<N:4>> <= crypto:hash(sha, "hello world") >>.
<<"2aae6c35c94fcfb415dbe95f408b9ce91ee846ed">>
same as in python binascii.b2a_hex:
>>> binascii.b2a_hex(sha.new('hello world').digest())
'2aae6c35c94fcfb415dbe95f408b9ce91ee846ed'
As of OTP24, there is
1> binary:encode_hex(<<1,2,3,4,5,6,255>>).
<<"010203040506FF">>
bin_to_hex_list(Bin) when is_binary(Bin) ->
lists:flatten([integer_to_list(X,16) || <<X>> <= Bin]).