给定代码使用直接使用Dynamics的快速算法绘制ODE解决方案的结果,我发现它在屏幕上非常快速地绘制解决方案。
我将此算法集成到Manipulate []中,并注意到绘图部分现在比以前慢得多。
我花了4个小时,但不明白为什么会这样。我希望有人能发现问题以及问题所在。
这个算法是Leonid在今天发表的另一个问题here的答案中再次发布的(再次感谢Leonid!)
算法非常快,并且还可以快速绘制图。但它直接使用Dynamics。我想在Manipulate中使用它。
我把它整合到Manipulate中,尽管我知道如何,因为代码是为我提前的,我不确定我是否做得对,但结果是正确的。
绘图确实起作用并生成正确的绘图,就像原始算法一样,但现在绘图的速度现在要慢得多。两种情况下的所有参数都相同(即问题参数)。这是我长期以来一直在努力解决的问题。如何在使用Manipulate时加快fps。
所以,问题可能在于我将它集成到Manipulate内部运行,我做了一些不高效的东西,或者可能是因为Manipulate已经使用了DynamicModule []而这会产生副作用,使得绘图渲染变慢或整个过程较慢。
我会发布我的Manipulate代码,我将Leonid代码集成在中(我尝试了很多不同的方法,而且它们都很慢,这是下面的一个版本)。
Manipulate[
Module[{ll = emptyList[], sol, plot, t, y, angle,
llaux = emptyList[]},
plot[] :=
Graphics[{Hue[0.67`, 0.6`, 0.6`], Line[fromLinkedList[ll]]},
AspectRatio -> 1/GoldenRatio, Axes -> True,
AxesLabel -> {"time", "angle"},
PlotRange -> {{0, max}, {-Pi/4, Pi/4}}, PlotRangeClipping -> True];
llaux = ll;
sol := First@
NDSolve[{y''[t] + 0.01 y'[t] + Sin[y[t]] == 0, y[0] == Pi/4,
y'[0] == 0}, y, {t, time, time + 1}];
angle := y /. sol;
ll := With[{res =
If[llaux === emptyList[] || pop[llaux][[1]] != time,
addToList[llaux, {time, angle[time]}],(*else*)llaux]},
llaux = res];
Dynamic[plot[]]
]
,
{{time, 0, "run"}, 0, max, Dynamic@delT, AnimationRate -> 1,
ControlType -> Trigger}, {{delT, 0.01, "delT"}, 0.01, 1, 0.01,
Appearance -> "Labeled"},
{{y0, Pi/4, "y(0)"}, -Pi, Pi, Pi/100, Appearance -> "Labeled"},
{{yder0, 0, "y'(0)"}, -1, 1, .1, Appearance -> "Labeled"},
{{linkedList, {}}, None},
TrackedSymbols :> {time},
Initialization :> (
max = 200;
toLinkedList[data_List] := Fold[linkedList, linkedList[], data];
fromLinkedList[ll_linkedList] :=
List @@ Flatten[ll, Infinity, linkedList];
addToList[ll_, value_] := linkedList[ll, value];
pop[ll_] := Last@ll;
emptyList[] := linkedList[];
)
]
这是原始代码,与Leonid here发布的代码完全相同,但我在顶部添加了2个参数,因此两个版本都将运行完全相同的参数来更轻松地比较速度。你会注意到,当你运行它时,绘图在屏幕上生成的速度与上面相比有多快。
我想帮助找到速度差异的原因。我现在假设绘图中的速度差异是由于Manipulate内部的Dyanmics交互,因为我知道算法在外面非常快。
max = 200; delT = 0.01;
ClearAll[linkedList, toLinkedList, fromLinkedList, addToList, pop,
emptyList];
(*SetAttributes[linkedList,HoldAllComplete];*)
toLinkedList[data_List] := Fold[linkedList, linkedList[], data];
fromLinkedList[ll_linkedList] :=
List @@ Flatten[ll, Infinity, linkedList];
addToList[ll_, value_] := linkedList[ll, value];
pop[ll_] := Last@ll;
emptyList[] := linkedList[];
Clear[getData];
Module[{ll = emptyList[], time = 0, restart, plot, y},
getData[] := fromLinkedList[ll];
plot[] :=
Graphics[{Hue[0.67`, 0.6`, 0.6`], Line[fromLinkedList[ll]]},
AspectRatio -> 1/GoldenRatio, Axes -> True,
AxesLabel -> {"time", "angle"},
PlotRange -> {{0, max}, {-Pi/4, Pi/4}}, PlotRangeClipping -> True];
DynamicModule[{sol, angle, llaux},
restart[] := (time = 0; llaux = emptyList[]);
llaux = ll;
sol := First@
NDSolve[{y''[t] + 0.01 y'[t] + Sin[y[t]] == 0, y[0] == Pi/4,
y'[0] == 0}, y, {t, time, time + 1}];
angle := y /. sol;
ll := With[{res =
If[llaux === emptyList[] || pop[llaux][[1]] != time,
addToList[llaux, {time, angle[time]}],(*else*)llaux]},
llaux = res
];
Column[{
Row[{Dynamic@delT, Slider[Dynamic[delT], {0.01, 1., 0.01}]}],
Dynamic[time, {None, Automatic, None}],
Row[{Trigger[Dynamic[time], {0, max, Dynamic@delT},
AppearanceElements -> {"PlayPauseButton"}],
Button[Style["Restart", Small], restart[]]}
],
Dynamic[plot[]]}, Frame -> True
]
]
]
再次感谢您提供的任何提示或事项。
更新
好的,这很有意思。我从来不知道只能使用Dynamics制作CDF,我认为必须使用Manipulate。但是我错了。我刚试过一个,它确实有效! Here it is在我的网站上,模拟阻尼驱动摆(由于关节上存在驱动力而表现出混乱运动),仅使用动力学,没有操纵。
以上代码如下:
DynamicModule[{sol, angle, bob, r, time = 0, animationRate = 1},
(*simulation of damped and driven pendulum, exhibit chaotic motion*)
Dynamic@Grid[{
{Trigger[Dynamic[time], {0, Infinity, 0.01}, animationRate,
AppearanceElements -> {"PlayPauseButton", "ResetButton"}],
Style["time (sec)", 10], Dynamic[time]},
{
Dynamic@Show[Graphics[{
{Dashed, Gray, Thin, Circle[{0, 0}, 1]},
{Red, Thick, Line[{{0, 0}, bob}]},
{Blue, PointSize[0.1], Point[bob]}
}, ImagePadding -> 10], ImageSize -> 300], SpanFromLeft
}}, Frame -> True, Alignment -> Left],
Initialization :>
(
sol :=
First@NDSolve[{y''[t] + 0.1 y'[t] + Sin[y[t]] == 1.5 Cos[t],
y[0] == Pi/4, y'[0] == 0}, y, {t, time, time + 1},
Sequence@ndsolveOptions];
bob := {Sin[(y /. sol)[time]], - Cos[(y /. sol)[time]]};
ndsolveOptions = {MaxSteps -> Infinity,
Method -> {"StiffnessSwitching",
Method -> {"ExplicitRungeKutta", Automatic}},
AccuracyGoal -> 10, PrecisionGoal -> 10};
)
]
这是我第一个使用直接动态的CDF。如果您希望在更新屏幕时看到性能上的差异,请使用Manipulate进行上述版本。我没有注意到这种情况有多大区别,但请注意这是绘制钟摆位置,不需要缓冲,也没有数据处理。简单地绘制鲍勃位置的逐点图。
Manipulate[
(
sol = First@
NDSolve[{y''[t] + 0.1 y'[t] + Sin[y[t]] == 1.5 Cos[t],
y[0] == Pi/4, y'[0] == 0}, y, {t, time, time + 1},
Sequence@ndsolveOptions];
bob = {Sin[(y /. sol)[time]], - Cos[(y /. sol)[time]]};
Show[Graphics[{
{Dashed, Gray, Thin, Circle[{0, 0}, 1]},
{Red, Thick, Line[{{0, 0}, bob}]},
{Blue, PointSize[0.1], Point[bob]}
}, ImagePadding -> 10], ImageSize -> 300]
),
{{time, 0, "run"}, 0, Infinity, 0.01, AnimationRate -> animationRate,
AppearanceElements -> {"PlayPauseButton", "ResetButton"}},
Initialization :>
(
animationRate = 1;
ndsolveOptions = {MaxSteps -> Infinity,
Method -> {"StiffnessSwitching",
Method -> {"ExplicitRungeKutta", Automatic}},
AccuracyGoal -> 10, PrecisionGoal -> 10};
)
]
我认为现在可以从动态制作CDF非常有趣。
答案 0 :(得分:4)
这是AnimationRate的问题。 在两者中设置相同会给出相同的时间(难以触发的时间btw): 评价:
Clear[getData];
Module[{ll = emptyList[], time = 0, restart, plot, y, timeinit},
getData[] := fromLinkedList[ll];
timeinit[n_ /; 0.01 < n < .5] := (init = AbsoluteTime[]);
plot[] :=
Graphics[{Hue[0.67`, 0.6`, 0.6`], Line[fromLinkedList[ll]]},
AspectRatio -> 1/GoldenRatio, Axes -> True,
AxesLabel -> {"time", "angle"},
PlotRange -> {{0, max}, {-Pi/4, Pi/4}}, PlotRangeClipping -> True,
PlotLabel :>
Row[{"seconds used: ", (timeinit[time];
If[time < 1, "", Round[AbsoluteTime[] - init]])}]];
DynamicModule[{sol, angle, llaux},
restart[] := (time = 0; llaux = emptyList[]);
llaux = ll;
sol := First@
NDSolve[{y''[t] + 0.01 y'[t] + Sin[y[t]] == 0, y[0] == Pi/4,
y'[0] == 0}, y, {t, time, time + 1}];
angle := y /. sol;
ll := With[{res =
If[llaux === emptyList[] || pop[llaux][[1]] != time,
addToList[llaux, {time, angle[time]}],(*else*)llaux]},
llaux = res];
Column[{Row[{Dynamic@delT,
Slider[Dynamic[delT], {0.01, 1., 0.01}]}],
Dynamic[time, {None, Automatic, None}],
Row[{Trigger[Dynamic[time], {0, max, Dynamic@delT},
AppearanceElements -> {"PlayPauseButton"},
AnimationRate -> 15],
Button[Style["Restart", Small], restart[]]}], Dynamic[plot[]]},
Frame -> True]]]
(* 和: *)
Manipulate[
Module[{ll = emptyList[], sol, plot, t, y, angle,
llaux = emptyList[], timeinit, init},
timeinit[n_ /; 0.01 < n < .5] := (init = AbsoluteTime[]);
plot[] :=
Graphics[{Hue[0.67`, 0.6`, 0.6`], Line[fromLinkedList[ll]]},
AspectRatio -> 1/GoldenRatio, Axes -> True,
PlotLabel :>
Row[{"seconds used: ", (timeinit[time];
If[time < 1, "", Round[AbsoluteTime[] - init]])}],
AxesLabel -> {"time", "angle"},
PlotRange -> {{0, max}, {-Pi/4, Pi/4}}, PlotRangeClipping -> True];
llaux = ll;
sol := First@
NDSolve[{y''[t] + 0.01 y'[t] + Sin[y[t]] == 0, y[0] == Pi/4,
y'[0] == 0}, y, {t, time, time + 1}];
angle := y /. sol;
ll := With[{res =
If[llaux === emptyList[] || pop[llaux][[1]] != time,
addToList[llaux, {time, angle[time]}],(*else*)llaux]},
llaux = res];
Dynamic[plot[]]], {{time, 0, "run"}, 0, max, Dynamic@delT,
AnimationRate -> 15, ControlType -> Trigger}, {{delT, 0.01, "delT"},
0.01, 1, 0.01, Appearance -> "Labeled"}, {{y0, Pi/4, "y(0)"}, -Pi,
Pi, Pi/100, Appearance -> "Labeled"}, {{yder0, 0, "y'(0)"}, -1,
1, .1, Appearance -> "Labeled"}, {{linkedList, {}}, None},
TrackedSymbols :> {time}, Initialization :> (max = 200;
toLinkedList[data_List] := Fold[linkedList, linkedList[], data];
fromLinkedList[ll_linkedList] :=
List @@ Flatten[ll, Infinity, linkedList];
addToList[ll_, value_] := linkedList[ll, value];
pop[ll_] := Last@ll;
emptyList[] := linkedList[];)]