我想可视化双摆的动画,但我不知道如何做,因为我对这个animate
包还不熟悉,这里是双摆(tikz)的代码:
\documentclass[tikz,border=8mm]{standalone}
\usetikzlibrary{backgrounds,angles,quotes}
\begin{document}
\begin{tikzpicture}[%
angle eccentricity=1.2,
ball/.style={circle, inner sep=0pt, minimum size=2mm, fill=blue, draw=blue, label=right:$m$},
background rectangle/.style={fill=black},
show background rectangle]
\draw[thick, white] (-2,0) --(2,0);
\draw[white] (0,0) coordinate (b0) foreach \i [count=\ni] in {-70,-55} {--++(\i:2cm) node[midway,auto]{$l$} node[ball] (b\ni) {}};
\foreach \i [count=\auxi] in {b0,b1}{
\draw[dashed, white] (\i)--++(-90:1.8cm) coordinate[pos=.75] (aux\auxi);
}
\draw pic["$\theta_1$", draw, white, angle radius=1.2cm] {angle=aux1--b0--b1};
\draw pic["$\theta_2$", draw, white, angle radius=1.2cm] {angle=aux2--b1--b2};
\end{tikzpicture}
\end{document}
答案1
(使用 TikZ 绘制动画帧)
要使双摆动起来,我们必须求解运动方程,它是一组常微分方程 (ODE)。对于两个不同点质量的无摩擦双摆,摆角的微分方程θ1和θ2在法语维基百科文章第 1 节末尾给出:
https://fr.wikipedia.org/wiki/Pendule_double#Mise_en_%C3%A9quation_utilisant_l'approche_lagrangienne
方程 (1) 和 (2) 都是隐式的,与角加速度耦合。为了使第一个方程显式化,将方程 (2) 代入 (1),然后 (1) 解析为\ddot{
θ1}
.
为了在 LaTeX 中求解 ODE 系统,我们可以使用包pst-ode
(方法:RKF45)。这是一个 PSTricks 包,但多亏了卢普斯特里克,由 Marcel Krüger 开发的 PostScript 解释器,下面的示例可以直接用lualatex
;ps2pdf
排版,不再需要(Ghostscript)。
timeTheta1Theta2.dat
逐行读取第一次运行期间写入的文件以获取每一步的时间和角度。最后用绘制动画帧TikZ
。
这些是您可能想要使用的参数:
/tEnd 70 def % time span to be simulated [s]
/m1 1 def % mass1 [kg]
/m2 1 def % mass2 [kg]
/l1 2 def % pendulum1 length [m]
/l2 2 def % pendulum2 length [m]
/G 9.81 def % acceleration [m/s^2]
/theta1zero 179 Pi mul 180 div def % theta1_0=179°
/theta2zero 180 Pi mul 180 div def % theta2_0=180°
70 秒以上的实时动画。单击即可运行动画(如果 Firefox 太慢,请尝试使用基于 Chromium 的浏览器。)
排版三次lualatex
:
%\PassOptionsToPackage{dvisvgm}{animate} % dvilualatex <file> ; dvisvgm --zoom=-1 --font-format=woff2 --bbox=papersize <file>.dvi
\documentclass[margin=1mm,varwidth]{standalone}
\usepackage{pst-ode}
\usepackage[controls,autoplay]{animate}
\usepackage{tikz}
\usepackage{listofitems} % read space separated items
\usepackage{siunitx}
\usepackage{xfp}
\usepackage[T1]{fontenc}
% adjustable parameters & definitions
\pstVerb{
tx@Dict begin
/tEnd 70 def % time span to be simulated [s]
/m1 1 def % mass1 [kg]
/m2 1 def % mass2 [kg]
/l1 2 def % pendulum1 length [m]
/l2 2 def % pendulum2 length [m]
/G 9.81 def % acceleration [m/s^2]
/theta1zero 179 Pi mul 180 div def % theta1_0=179°
/theta2zero 180 Pi mul 180 div def % theta2_0=180°
/N (cvi(tEnd*25+1)) AlgParser cvx exec def % (integer) number of time steps (for 25 frames per s) + 1
%
/M2 (m2/(m1+m2)) AlgParser cvx exec def % some constants
/rM2 (1/M2) AlgParser cvx exec def
/l12 (l1/l2) AlgParser cvx exec def
/l21 (l2/l1) AlgParser cvx exec def
/G1 (G/l1) AlgParser cvx exec def
/G2 (G/l2) AlgParser cvx exec def
/G1M2 (G1/M2) AlgParser cvx exec def
%
/theta1Dot (x[2]) AlgParser cvx def % 1st order ODE system
/theta2Dot (x[3]) AlgParser cvx def
/omega1Dot (((G1*sin(x[1])-x[2]^2*sin(x[0]-x[1]))*cos(x[0]-x[1])-l21*x[3]^2*sin(x[0]-x[1])-G1M2*sin(x[0]))
/(rM2-cos(x[0]-x[1])^2)) AlgParser cvx def
/omega2Dot (-l12*(omega1Dot*cos(x[0]-x[1])-x[2]^2*sin(x[0]-x[1]))-G2*sin(x[1])) AlgParser cvx def
end
}
% solve equations of motion
\pstODEsolve[algebraicAll,saveData]{timeTheta1Theta2}{% PS variable that takes result list
t | x[0]*180/Pi-90 | x[1]*180/Pi-90 % table format of data to be saved in timeTheta1Theta2
}{0}{tEnd}{N}{ % t_0, t_end, number of time steps + 1
theta1zero | theta2zero | 0 | 0 % initial conditions
}{
theta1Dot | theta2Dot | omega1Dot | omega2Dot % ODE system's RHS
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% \fileopenr{<file stream>}{<file name>}, opens file for reading
\newcommand\fileopenr[2]{%
\newread#1%
\immediate\openin#1=#2%
}
% \readtolist[<sep char>]{<file stream>}{\list}
% reads a line from file stream and splits at <sep char> into \list[1], \list[2], ...
\newcommand\readtolist[3][,]{{%
\setsepchar{#1}%
\immediate\read#2 to \inputline%
\ifeof#2
\immediate\closein#2%
\ifdefined\multiframebreak\multiframebreak\fi%
\else%
\greadlist*#3\inputline%
\fi%
}}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{document}
$l_1=l_2=\qty{2}{\metre}$; $m_1=m_2=\qty{1}{\kilogram}$\\
\IfFileExists{timeTheta1Theta2.dat}{}{\end{document}}%
\begin{animateinline}{25}
\fileopenr{\data}{timeTheta1Theta2.dat}%
\readtolist[ ]{\data}{\table}%
\multiframe{100000}{}{
\begin{tikzpicture}%
\useasboundingbox (-4.2,-4.2) rectangle (4.2,4.2);
\filldraw (0,0) -- ++(\table[2]:2) circle[radius=1mm] -- ++(\table[3]:2) circle[radius=1mm];
\filldraw [fill=white] (0,0) circle [radius=1pt];
\node[anchor=north west, inner sep=0pt] at (-4.2,4.2) {\strut$t=\qty{\fpeval{trunc(\table[1])}}{\second}$};
\end{tikzpicture}%
\readtolist[ ]{\data}{\table}%
}
\end{animateinline}
\end{document}