「がんばれない」けど「がんばりたい」

ITエンジニアの仕事のこと。AI、機械学習、ディープラーニング。地頭力。車のこと。

Trigonometry and Forces: The Pendulum|Nature of Code

振り子の運動についてまとめ。

ニュートンの第2法則と角速度の両方を考慮する。 Nature of Codeの図を引用すると以下のような重力方向の力Fgと振り子の重りが動こうとする力Fpには、 Fp = Fg x sin(θ)と書いてある。 The Pendulum

この図のみからこの式の関係がすぐに理解できなかったので、次のように補助線を書いてみた。ちょっと図が小さいのでクリックして拡大してください。

875_05

重りが自然界から受けている力は赤色のFg,Fpになります。これと天井にあるオレンジ色のθだけだと、よく分からなかったので、赤のFgを逆向きに延ばした青色の線(ベクトル)を引きました。-Fgのベクトルです。そうすると、天井にあるオレンジθ=青色θになる事に気づきます。

次に-Fg(青)ベクトルと青θのsin成分を出してみると、-Fg x Sin(θ)は青で書いてある-Fgsin(θ)となります。これは、図を見ると分かるようにFpの逆方向ベクトル成分と等価。 つまり -Fp = -Fg x sin(θ)なので、両辺にマイナス1を掛ければ、
Fp = Fg x sin(θ)

たぶんあってる…


まぁ物理現象の計算式については、とりあえずこんなところまでの理解で一旦おしまいにして、次に、この振り子運動内において、どれが角速度運動(angular acceleration)になるか?を考えてみます。

[ちょっとおさらい]
角速度が運動にもたらす方式はこれまでやってきたとおり、以下になりますね。

anglar Velocity(新しい角速度) = angularVelocity + angular acceleration. angle(新しい角度) = angle + angularVelocity;

上図から振り子に影響する力が重力方向の力のsin(θ)倍になるので、 pendulum angular acceleration = acceleration due to gravity * sine (θ) なので式は、 angular acceleration = gravity * sin(θ) まぁ、ここでgravityは自然界では9.8/mssですが、コンピュータの世界はピクセル単位なので、 画面内で表現したい数値に調整すれば良い定数として理解すればいいです。 という事は、振り子の運動って、sin(θ)に定数かけるだけ!って事に… 自分もそうだけど、まじめな人は「微分」とかしないでいいの??等々考えてしまいがちですが、 Nature of Codeに書かれていたけど、自分らの目標はあくまでもスクリーン上にコンピュータをつかって、自然現象みたいな動きを実現する事であって、物理学をきちんと把握しなくてもいいんじゃ!(かなり意訳。)と。

ではではコードにしていきましょう。

#include 'testApp.h'

#define NUM_OF_PENDULUM 100

ofEasyCam cam;

class Pendulum
{
    
public:
    
    
    //gravity
    float g;
    
    //arm
    float r;
    
    //angle
    float ang;
    
    //angular velocity
    float aVelocity;
    
    //angular acceleration
    float aAcceleration;
    
    //origin
    ofVec3f origin;
    
    //location
    ofVec3f location;
    
    //dumping
    float dumping;
    
    ofVec4f color;
    
    void setup()
    {
        g = 0.4;
        
        r = ofRandom(100, 500);

        origin.set(ofGetWidth()*0.5, ofGetHeight()*0.5 - 300, 0.0);

        location.z = ofRandom(-100, 100);
        
        aVelocity = 0.0;
        aAcceleration = 0.0;
        ang = PI/4;
        
        dumping = 0.995;
        
        color.set(ofRandom(10,255), ofRandom(10,255),ofRandom(10,255),ofRandom(100,255));
    }
    
    /**
     *  to update pendulm's angle
     */
    void update()
    {
        
        //rは、加速度に影響するので、rで割る事で正規化する
        //rが大きいほど加速度は小さくなるという自然現象はdrawのlocationを計算しているところで、
        //実現している。
        aAcceleration = (-1 * g * sin(ang)) / r;
        aVelocity += aAcceleration;
        ang += aVelocity;
//        aVelocity*=dumping;
        
        //angが毎フレーム毎に+されているからといって、
        //常にoriginよりも下側で振り子のように位置が変化している理由は
        //aAccelerationを産出する式で-1を掛ける事により、
        //blobの位置が第3or第4象限にあることになるため。

//        cout << "aAcceleration = " << aAcceleration << endl;
//        cout << "aVelocity = " << aVelocity << endl;
//        cout << "ang = " << ang * RAD_TO_DEG << endl;
//        cout << "sin(ang) = " << sin(ang) << endl;
//        cout << endl;
    }
    
    void draw()
    {
        ofSetColor(100,100,100);
        location.set(r * sin(ang), r*cos(ang), location.z);
        location += origin;
        ofLine(origin.x, origin.y, origin.z, location.x, location.y, location.z);
        
        ofSetColor(color.x, color.y, color.z, color.w);
        ofCircle(location.x, location.y, location.z, 10);
    }
};

vector<Pendulum> ps;

//--------------------------------------------------------------
void testApp::setup(){
    
    ofSetFrameRate(60);
    ofEnableSmoothing();
    ofSetVerticalSync(true);
    ofBackground(0);
    
    ofEnableAlphaBlending();
    ofEnableBlendMode(OF_BLENDMODE_ADD);
    ofEnableDepthTest();
    
    ps.resize(NUM_OF_PENDULUM);
    for (int i = 0; i < ps.size(); i++)
    {
        Pendulum*p = &ps[i];
        p->setup();
    }
}

//--------------------------------------------------------------
void testApp::update(){

    for (int i = 0; i < ps.size(); i++)
    {
        Pendulum*p = &ps[i];
        p->update();
    }

}

//--------------------------------------------------------------
void testApp::draw(){

    for (int i = 0; i < ps.size(); i++)
    {
        Pendulum*p = &ps[i];
        p->draw();
    }
}