我们可以使用Kane方法对具有任意质量和长度(see this)的n
摆系统的运动方程进行积分。该程序的实现受到jakevdp的启发。但是,当我使用这种近似方法来找到伪时间段T
(定义为n
摆系统(即{{1})中每个摆的所有时间段的平均值时, },average(period(theta_1),...,period(theta_n)))
作为T
的函数的图在幅度方面似乎难以置信。
目的:可视化摆的数量n
与整个系统的伪时间周期n
之间的关系,其中T=2π/omega bar
是所有角速度{{1}的平均值}。
以下实现定义和求解具有任意质量和长度的omega bar
摆系统的运动方程(在这种情况下,我们将omega
用于所有n
)。这是m[i]=1
和i
的初始值问题。
theta_1(0)=135,...,theta_n(0)=135
以上内容返回广义的物理坐标,即相对于垂直方向的每个摆线段的角位置theta_1'(0)=0,...,theta_n'(0)=0
和速度# %matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from sympy import symbols
from sympy.physics import mechanics
from sympy import Dummy, lambdify
from scipy.integrate import odeint
def integrate_pendulum(n, times,
initial_positions=135,
initial_velocities=0,
lengths=None, masses=1):
"""Integrate a multi-pendulum with `n` sections"""
#-------------------------------------------------
# Step 1: construct the pendulum model
# Generalized coordinates and velocities
# (in this case, angular positions & velocities of each mass)
q = mechanics.dynamicsymbols('q:{0}'.format(n))
u = mechanics.dynamicsymbols('u:{0}'.format(n))
# mass and length
m = symbols('m:{0}'.format(n))
l = symbols('l:{0}'.format(n))
# gravity and time symbols
g, t = symbols('g,t')
#--------------------------------------------------
# Step 2: build the model using Kane's Method
# Create pivot point reference frame
A = mechanics.ReferenceFrame('A')
P = mechanics.Point('P')
P.set_vel(A, 0)
# lists to hold particles, forces, and kinetic ODEs
# for each pendulum in the chain
particles = []
forces = []
kinetic_odes = []
for i in range(n):
# Create a reference frame following the i^th mass
Ai = A.orientnew('A' + str(i), 'Axis', [q[i], A.z])
Ai.set_ang_vel(A, u[i] * A.z)
# Create a point in this reference frame
Pi = P.locatenew('P' + str(i), l[i] * Ai.x)
Pi.v2pt_theory(P, A, Ai)
# Create a new particle of mass m[i] at this point
Pai = mechanics.Particle('Pa' + str(i), Pi, m[i])
particles.append(Pai)
# Set forces & compute kinematic ODE
forces.append((Pi, m[i] * g * A.x))
kinetic_odes.append(q[i].diff(t) - u[i])
P = Pi
# Generate equations of motion
KM = mechanics.KanesMethod(A, q_ind=q, u_ind=u,
kd_eqs=kinetic_odes)
fr, fr_star = KM.kanes_equations(particles, forces)
#-----------------------------------------------------
# Step 3: numerically evaluate equations and integrate
# initial positions and velocities – assumed to be given in degrees
y0 = np.deg2rad(np.concatenate([np.broadcast_to(initial_positions, n),
np.broadcast_to(initial_velocities, n)]))
# lengths and masses
if lengths is None:
lengths = np.ones(n) / n
lengths = np.broadcast_to(lengths, n)
masses = np.broadcast_to(masses, n)
# Fixed parameters: gravitational constant, lengths, and masses
parameters = [g] + list(l) + list(m)
parameter_vals = [9.81] + list(lengths) + list(masses)
# define symbols for unknown parameters
unknowns = [Dummy() for i in q + u]
unknown_dict = dict(zip(q + u, unknowns))
kds = KM.kindiffdict()
# substitute unknown symbols for qdot terms
mm_sym = KM.mass_matrix_full.subs(kds).subs(unknown_dict)
fo_sym = KM.forcing_full.subs(kds).subs(unknown_dict)
# create functions for numerical calculation
mm_func = lambdify(unknowns + parameters, mm_sym)
fo_func = lambdify(unknowns + parameters, fo_sym)
# function which computes the derivatives of parameters
def gradient(y, t, args):
vals = np.concatenate((y, args))
sol = np.linalg.solve(mm_func(*vals), fo_func(*vals))
return np.array(sol).T[0]
# ODE integration
return odeint(gradient, y0, times, args=(parameter_vals,))
。下面从广义坐标中提取theta
坐标。
omega
然后,将摆数固定为(x,y)
,并使用以下方法确定伪时间段:
def get_xy_coords(p, lengths=None):
"""Get (x, y) coordinates from generalized coordinates p"""
p = np.atleast_2d(p)
n = p.shape[1] // 2
if lengths is None:
lengths = np.ones(n) / n
zeros = np.zeros(p.shape[0])[:, None]
x = np.hstack([zeros, lengths * np.sin(p[:, :n])])
y = np.hstack([zeros, -lengths * np.cos(p[:, :n])])
return np.cumsum(x, 1), np.cumsum(y, 1)
当我们绘制它时,我们得到n=10
的以下图形:
但是,它应根据n = 10
nperiod = []
#Array containing pseudo-period for a system of `n` pendulums
for i in range(1,n + 1):
t = np.linspace(0, 10, 1000)
p = integrate_pendulum(i, times=t)
#x, y has first column of zeros
x, y = get_xy_coords(p)
r,s = np.shape(y)
#Call method to find pseudo-period
nperiod.append(computeperiod())
#Takes `j`, denoting `j`-th pendulum, as input and returns `theta_j` for all times where `1≤j≤n`. This information corresponds to the `j`-th column of the `y` matrix, transformed into polar coordinates.
def theta(j):
theta_j = []
for i in range(0, r):
theta_j.append(math.acos(abs(y[i][j-1]-y[i][j])))
#We should technically divide by the length of the pendulum in `abs(.)`
timenew = [i for i in range(1,r + 1)]
graph_j = pd.Series(data=theta_j, index=timenew)
#Returns array omega_j which is the numerical time derivative of all values contained in the `r x 1` array `theta_j`, i.e. the value of the `j`-th angle theta_j for all times
return pd.Series(data=np.gradient(graph_j.values), index=graph_j.index)
#Returns pseudo-time period using formula `T=2π/omega`
def computeperiod():
series = []
for j in range(1,s):
series.append(2 * math.pi/(theta(j).mean()))
numberline = [i for i in range(1,s)] #Here s=n+1
timeperiod = pd.Series(data=series, index=numberline)
return abs(timeperiod.mean())
print(nperiod)
numbers = [i for i in range(len(nperiod))]
finalperiods = pd.Series(data=nperiod, index=numbers)
finalperiods.plot()
渐近地表现为n=10
,其中O(n^(3/2))
和T(n) = 2 * π * n^(3/2)(l/g)^(1/2)
如下。
此外,其幅度应减小大约g = 9.8
的一个因子。因此,似乎这种方法显然有问题。