VisualC++ と OpenGL を利用した仮想物理実験室
ラグランジュ未定乗数法を用いた球面振子のシミュレーション
ここまでは,拘束条件を取り扱うために一般化座標を導入し, ラグランジュ運動方程式を解くことで単振子のシミュレーションと球面振子のシミュレーションを行ないました。 本節では,拘束条件を別の形で導入して,前回と同様に球面振子のシミュレーションを行ないます。
ボールには,重力G と紐に引っ張られる力,張力S の2つの力が働いています。
張力
張力は支点(r_0)に向かって,距離に比例した力が加わっていると仮定します。
ボールに加わっている力
運動方程式
上式の運動方程式にはまだ拘束条件は考えられていません。 αはまだ未知です。
拘束条件
球面振り子の場合には、次の条件が課されます。
上式の両辺を時間で2回微分します。
つまり,上記の拘束条件(2)の場合,位置r, 速度 \dot{r}, 加速度 \ddot{r} には上式関係を満たす必要があるということです.
一方,運動方程式(1)の両辺に (r - r_0) の内積をとると
となります。式(3)と(4)からαを決めることができます。
これによりボールの運動を支配する運動方程式が決まります.ただし,v は速度を表します.
球面振り子の運動方程式
式(5)を用いてシミュレーションするために,シミュレーションを行うため, 数値計算法としてルンゲクッタ法を利用します. ルンゲクッタ法を用いるために,次のように変形します.
極座標を用いた単振子+ルンゲクッタ法のアニメーション
極座標を用いた単振子+ルンゲクッタ法のプログラム
【0-2-3】仮想物理実験室の構築 (ver1.2)を参照ください
構造体の定義
// ボールの定義 double ball_r = 4.0;//ボールの半径 struct BALL { double x0, y0, z0; double x, y, z; double vx, vy, vz; double l; }; const int N = 3; BALL ball[N]; void SetUp(void){ for(int i=0; i<N; i++ ){ ball[i].l = L; ball[i].x0 = 0.0; ball[i].y0 = 0.0; ball[i].z0 = poll_z; ball[i].x = ball[i].l; ball[i].y = 0.0; ball[i].z = poll_z; ball[i].vx = 0; ball[i].vy = 10.0 * double(i+1); ball[i].vz = 0; } }
ルンゲクッタ法を利用した数値計算
double fx(double t, double x, double y, double z, double vx, double vy, double vz){ return vx; } double fvx(double t, double x, double y, double z, double vx, double vy, double vz){ double l2 = pow(x,2) + pow(y,2) + pow(z,2); double v2 = pow(vx,2) + pow(vy,2) + pow(vz,2); return (g*z-v2) * x / l2 ; } double fy(double t, double x, double y, double z, double vx, double vy, double vz){ return vy; } double fvy(double t, double x, double y, double z, double vx, double vy, double vz){ double l2 = pow(x,2) + pow(y,2) + pow(z,2); double v2 = pow(vx,2) + pow(vy,2) + pow(vz,2); return (g*z-v2) * y / l2 ; } double fz(double t, double x, double y, double z, double vx, double vy, double vz){ return vz; } double fvz(double t, double x, double y, double z, double vx, double vy, double vz){ double l2 = pow(x,2) + pow(y,2) + pow(z,2); double v2 = pow(vx,2) + pow(vy,2) + pow(vz,2); return -g + (g*z-v2) * z / l2 ; } void RungeKutta4(BALL *ball){ double k1[6],k2[6],k3[6],k4[6]; double x = ball -> x - ball -> x0; double vx = ball -> vx; double y = ball -> y - ball -> y0; double vy = ball -> vy; double z = ball -> z - ball -> z0; double vz = ball -> vz; k1[0]=dt*fx(t,x,y,z,vx,vy,vz); k1[1]=dt*fvx(t,x,y,z,vx,vy,vz); k1[2]=dt*fy(t,x,y,z,vx,vy,vz); k1[3]=dt*fvy(t,x,y,z,vx,vy,vz); k1[4]=dt*fz(t,x,y,z,vx,vy,vz); k1[5]=dt*fvz(t,x,y,z,vx,vy,vz); k2[0]=dt*fx(t+dt/2.0, x+k1[0]/2.0,y+k1[2]/2.0,z+k1[4]/2.0,vx+k1[1]/2.0,vy+k1[3]/2.0,vz+k1[5]/2.0); k2[1]=dt*fvx(t+dt/2.0,x+k1[0]/2.0,y+k1[2]/2.0,z+k1[4]/2.0,vx+k1[1]/2.0,vy+k1[3]/2.0,vz+k1[5]/2.0); k2[2]=dt*fy(t+dt/2.0, x+k1[0]/2.0,y+k1[2]/2.0,z+k1[4]/2.0,vx+k1[1]/2.0,vy+k1[3]/2.0,vz+k1[5]/2.0); k2[3]=dt*fvy(t+dt/2.0,x+k1[0]/2.0,y+k1[2]/2.0,z+k1[4]/2.0,vx+k1[1]/2.0,vy+k1[3]/2.0,vz+k1[5]/2.0); k2[4]=dt*fz(t+dt/2.0, x+k1[0]/2.0,y+k1[2]/2.0,z+k1[4]/2.0,vx+k1[1]/2.0,vy+k1[3]/2.0,vz+k1[5]/2.0); k2[5]=dt*fvz(t+dt/2.0,x+k1[0]/2.0,y+k1[2]/2.0,z+k1[4]/2.0,vx+k1[1]/2.0,vy+k1[3]/2.0,vz+k1[5]/2.0); k3[0]=dt*fx(t+dt/2.0, x+k2[0]/2.0,y+k2[2]/2.0,z+k2[4]/2.0,vx+k2[1]/2.0,vy+k2[3]/2.0,vz+k2[5]/2.0); k3[1]=dt*fvx(t+dt/2.0,x+k2[0]/2.0,y+k2[2]/2.0,z+k2[4]/2.0,vx+k2[1]/2.0,vy+k2[3]/2.0,vz+k2[5]/2.0); k3[2]=dt*fy(t+dt/2.0, x+k2[0]/2.0,y+k2[2]/2.0,z+k2[4]/2.0,vx+k2[1]/2.0,vy+k2[3]/2.0,vz+k2[5]/2.0); k3[3]=dt*fvy(t+dt/2.0,x+k2[0]/2.0,y+k2[2]/2.0,z+k2[4]/2.0,vx+k2[1]/2.0,vy+k2[3]/2.0,vz+k2[5]/2.0); k3[4]=dt*fz(t+dt/2.0, x+k2[0]/2.0,y+k2[2]/2.0,z+k2[4]/2.0,vx+k2[1]/2.0,vy+k2[3]/2.0,vz+k2[5]/2.0); k3[5]=dt*fvz(t+dt/2.0,x+k2[0]/2.0,y+k2[2]/2.0,z+k2[4]/2.0,vx+k2[1]/2.0,vy+k2[3]/2.0,vz+k2[5]/2.0); k4[0]=dt*fx(t+dt/2.0, x+k3[0],y+k3[2],z+k3[4],vx+k3[1],vy+k3[3],vz+k3[5]); k4[1]=dt*fvx(t+dt/2.0,x+k3[0],y+k3[2],z+k3[4],vx+k3[1],vy+k3[3],vz+k3[5]); k4[2]=dt*fy(t+dt/2.0, x+k3[0],y+k3[2],z+k3[4],vx+k3[1],vy+k3[3],vz+k3[5]); k4[3]=dt*fvy(t+dt/2.0,x+k3[0],y+k3[2],z+k3[4],vx+k3[1],vy+k3[3],vz+k3[5]); k4[4]=dt*fz(t+dt/2.0, x+k3[0],y+k3[2],z+k3[4],vx+k3[1],vy+k3[3],vz+k3[5]); k4[5]=dt*fvz(t+dt/2.0,x+k3[0],y+k3[2],z+k3[4],vx+k3[1],vy+k3[3],vz+k3[5]); ball->x = ball->x + (k1[0]+2.0*k2[0]+2.0*k3[0]+k4[0])/6.0; ball->vx = ball->vx + (k1[1]+2.0*k2[1]+2.0*k3[1]+k4[1])/6.0; ball->y = ball->y + (k1[2]+2.0*k2[2]+2.0*k3[2]+k4[2])/6.0; ball->vy = ball->vy + (k1[3]+2.0*k2[3]+2.0*k3[3]+k4[3])/6.0; ball->z = ball->z + (k1[4]+2.0*k2[4]+2.0*k3[4]+k4[4])/6.0; ball->vz = ball->vz + (k1[5]+2.0*k2[5]+2.0*k3[5]+k4[5])/6.0; }