0

Pygameで簡単な振り子シミュレーションを書こうとしています。重要なのは、動きを表す微分方程式を解くのではなく、振り子にかかる力(重力と張力)を直接シミュレートしようとしているということです。最初に、ベクトルを取得し、軸システムをある角度で回転させ、このベクトルのコンポーネントを新しい回転した軸システムに返す関数を作成しました。この関数のコードは問題なく、期待どおりに機能します。

シミュレーションの各ティックで、重力ベクトルを振り子とロープの間の角度で回転させ、新しいコンポーネントを取得します。1つはロープの方向に、もう1つはロープに直交します。ロープの方向の張力と成分が互いに打ち消し合うため、直交成分のみが重要です。計算した後、加速度ベクトルを回転させて通常の座標系に戻し、積分します。ただし、結果として生じる動作は意図したとおりではありません。理由は何ですか?

これはコードです:

from __future__ import division
import copy
import pygame
import random
import math
import numpy as np
import time

clock = pygame.time.Clock()
pygame.init()
size = (width, height) = (600,500)
screen = pygame.display.set_mode(size)

def rotate(vector,theta):
    #rotate the vector by theta radians around the x-axis
    Vx,Vy = vector[0],vector[1]
    cos,sin = math.cos(theta),math.sin(theta)
    newX,newY = Vx*cos-Vy*sin, Vy*cos+Vx*sin #the newX axis is the result of rotating x axis by theta
    return [newX,newY]

class pendulum:
    def __init__(self,x,y,x0,y0):
        self.x = x
        self.y = y
        self.x0 = x0
        self.y0 = y0
        self.velocity = [0,0]
        self.a= [0,0]
        self.angle = 0
    def CalcForce(self):
        self.angle = math.atan2(-(self.y-self.y0),self.x-self.x0)
        gravity = rotate(g,self.angle)
        self.a[1]=gravity[1]
        self.a[0] = 0 #This component is cancelled by the tension
        self.a = rotate(self.a,-self.angle)
    def move(self):
       #print pylab.dot(self.velocity,[self.x-self.x0,self.y-self.y0])
        self.velocity[0]+=self.a[0]
        self.velocity[1]+=self.a[1]
        self.x+=self.velocity[0]
        self.y+=self.velocity[1]
    def draw(self):
        pygame.draw.circle(screen, (0,0,0), (self.x0,self.y0), 5)
        pygame.draw.line(screen, (0,0,0), (self.x0,self.y0), (int(self.x), int(self.y)),3)
        pygame.draw.circle(screen, (0,0,255), (int(self.x),int(self.y)), 14,0)
g = [0,0.4]
p = pendulum(350,100,300,20)

while 1:
    screen.fill((255,255,255))
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
    p.CalcForce()
    p.move()
    p.draw()
    clock.tick(60)
    pygame.display.flip()

ありがとうございました。

4

2 に答える 2

2

ここにはたくさんの問題があります。いくつか修正して、いくつか残しておきます。

私が修正したのは次のとおりです。1)numpyをインポートしたので、それを使用し、ベクトルの観点から物事を書く必要があります。2)すべてを書き、すぐに機能させることは、自分自身に対する不合理な要求です。したがって、ここで私もプロットするように、中間結果などをプロットする必要がありますa。そうすれば、それが理にかなっているかどうかを確認できます。3)「ローテーション」アプローチ全体が混乱します。代わりに、構成部品について考えてください。ここで直接計算します(短く、読みやすく、理解しやすいなど)。4)タイムステップを使用するすべてのシミュレーションでは、他のパラメーターを変更せずにタイムステップを変更できるように、明示的にdtを使用する必要があります。

今、あなたがそれを見るならば、あなたはそれがほとんど合理的に見えるのを見ることができます。ただし、加速度が上向きになることはないため、ボールが振動している間はボールが落下することに注意してください。これは、ロープの張力をボールの力に含めなかったためです。その部分はあなたにお任せします。

import pygame
import math
import numpy as np

clock = pygame.time.Clock()
pygame.init()
size = (width, height) = (600,500)
screen = pygame.display.set_mode(size)


class pendulum:
    def __init__(self,x,y,x0,y0):
        self.x0 = np.array((x0, y0))
        self.x = np.array((x, y), dtype=float)
        self.v = np.zeros((2,), dtype=float)
        self.a = np.zeros((2,), dtype=float)
    def CalcForce(self):
        dx = self.x0 - self.x
        angle = math.atan2(-dx[0], dx[1])
        a = g[1]*math.sin(angle)  # tangential accelation due to gravity
        self.a[0] = at*math.cos(angle)
        self.a[1] = at*math.sin(angle)
    def move(self):
        #print np.dot(self.a, self.x-self.x0) #is a perp to string?
        self.x += dt*self.v
        self.v += dt*self.a
    def draw(self):
        pygame.draw.circle(screen, (0,0,0), self.x0, 5)
        pygame.draw.line(screen, (0,0,0), self.x0, self.x.astype(int),3)
        pygame.draw.circle(screen, (0,0,255), self.x.astype(int), 14,0)
        pygame.draw.line(screen, (255, 0, 0), (self.x+200*self.a).astype(int), self.x.astype(int), 4)
dt = .001
g = [0,0.4]
p = pendulum(350,100,300,20)

while 1:
    screen.fill((255,255,255))
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
    for i in range(100): # don't plot every timestep
        p.CalcForce()
        p.move()
        p.draw()
    clock.tick(60)
    pygame.display.flip()
于 2013-03-20T04:14:42.793 に答える
1

シミュレーションをしたいのなら、難しいやり方だと思います。運動方程式から始めます。ここで方程式20を参照してください。ドットは、時間に関して微分することを意味します---したがって、方程式は次のようになりd^2/dt^2 \theta = ...ます。次に、時間方向に有限差分スキームを実装し、時間をステップスルーする必要があります。各ステップ(のラベルi)で、振り子の長さとに基づいて、ボブのx座標とy座標を計算できます\theta_i。有限差分に関するwikiの記事をチェックしてください。

于 2013-03-19T21:29:31.303 に答える