情報学部 菅沼ホーム JavaScript 目次 基礎技術目次 索引

速度と加速度(その2)

  1. 摩擦

      一般的に,物体が運動するときは摩擦が存在し,外部から何らかの力が加わらない限り,等速直線運動を永久に続けるようなことはありません.ここでは,摩擦について考えてみます.摩擦には様々な物が存在しますが,その一つに速度に比例する摩擦があります.例えば,先の章で述べた自由落下運動に速度に比例した摩擦(摩擦係数:k )を加えると,物体の質量を m,重力の加速度を g / t2 としたとき,その微分方程式は以下のようになります.

      物体を投げ上げた時点の水平方向( x 軸方向)の位置を x0,高さ( y 軸方向の位置)を y0,x 軸方向の初期速度を vx0 / t,y 軸方向の初期速度を vy0 / t として,上の微分方程式を解くと,x 軸方向の位置と速度は,

    となり,また,y 軸方向の位置と速度は以下のようになります.

      以上の結果に基づき,window オブジェクトにおける setInterval メソッドを利用して,自由落下運動を描画したものが以下に示すプログラムです.このプログラムにおいて,緑の丸は摩擦がない場合,また,赤い丸は摩擦がある場合を表しています.
    <!DOCTYPE HTML>
    <HTML>
    <HEAD>
    	<TITLE>自由落下運動(摩擦)</TITLE>
    	<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
    	<META NAME=viewport CONTENT="width=device-width, initial-scale=1">
    	<LINK REL="stylesheet" TYPE="text/css" HREF="../../../master.css">
    	<SCRIPT TYPE="text/javascript">
    		canvas  = null;
    		ctx     = null;
    		timerID = -1;
    		x0      = 0.0;   // 円の水平方向の初期位置
    		y0      = 0.0;   // 円の垂直方向の初期位置
    		x1      = 0.0;   // 円の位置( x ,摩擦無し)
    		y1      = 0.0;   // 円の位置( y ,摩擦無し)
    		x2      = 0.0;   // 円の位置( x ,摩擦あり)
    		y2      = 0.0;   // 円の位置( y ,摩擦あり)
    		t       = 0.0;   // 時間
    		dt      = 0.04;   // 時間の刻み幅
    		vx0     = 100.0;   // 水平方向の初期速度
    		vy0     = -200.0;   // 垂直方向の初期速度
    		g       = 98.0;   // 加速度
    		k       = 0.2;   // 摩擦係数
    		m       = 1.0;   // 質量
    
    		function start() {
    			canvas = document.getElementById('canvas_e');
    			canvas.width  = 600;   // キャンバス要素の幅
    			canvas.height = 600;   // キャンバス要素の高さ
    			ctx = canvas.getContext('2d');
    			y0 = canvas.height / 2;
    			y1 = y0;
    			y2 = y0;
    			timerID = setInterval('draw()', 40);
    		}
    					// 描画
    		function draw()
    		{
    			if (x1 < canvas.height) {
    				t  += dt;
    				x1  = vx0 * t;
    				y1  = y0 + vy0 * t + 0.5 * g * t * t;
    				x2  = vx0 * (1 - Math.exp(-k * t)) / k;
    				y2  = y0 + m * (vy0 - m * g / k) / k - m * (vy0 - m * g / k) * Math.exp(-k * t / m) / k + m * g * t / k;
    			}
    			else {
    				x1 = x0;
    				y1 = y0;
    				x2 = x0;
    				y2 = y0;
    				t  = 0;
    			}
    			ctx.clearRect(0, 0, canvas.width, canvas.height);
    			ctx.beginPath();
    			ctx.fillStyle = "rgb(0, 255, 0)";
    			ctx.arc(x1, y1, 20, 0, 2*Math.PI, false);
    			ctx.fill();
    			ctx.beginPath();
    			ctx.fillStyle = "rgb(255, 0, 0)";
    			ctx.arc(x2, y2, 20, 0, 2*Math.PI, false);
    			ctx.fill();
    		}
    	</SCRIPT>
    </HEAD>
    <BODY CLASS="white" STYLE="text-align: center" onLoad="start()">
    	<H1>自由落下運動(摩擦)</H1>
    	<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="600" HEIGHT="600"></CANVAS>
    </BODY>
    </HTML>
    			
      この例の場合は,簡単に微分方程式を解くことができますが,一般的には可能であるとは限りません(勿論,コンピュータを使用して数値的に解くことは可能ですが).しかし,アニメーションやゲームにおいては,それほど正確さが求められるわけではありません.そこで,計算する時間間隔 dt が小さい場合は,前章の「加速度」における (5) 式,(6) 式を使用して,速度や位置を近似的に計算することが可能です.自由落下運動(近似)は,上で述べた方法との大きな違いを見つけることが困難だと思います.基本的に,以下のような方法で近似計算をします.現在の y 軸方向の速度を v1 とすると,y 軸方向の加速度 a は,
    a = -k * v1 / m - g			
    となります.そこで,dt 時間後の y 軸方向の速度 v2 は,
    v2 = v1 + a * dt			
    となります.そこで,現在の y 軸方向の位置を y1 としたとき,dt 時間後の y 軸方向の位置 y2 を,v1 と v2 の平均を利用して,以下のようにして計算します.
    y2 = y1 + 0.5 * (v1 + v2) * dt			
      なお,x 軸方向に関しても,加速度計算に g が入らないだけで,同様の方法で計算できます.以下に示すのが,この方法を使用したプログラムです.
    <!DOCTYPE HTML>
    <HTML>
    <HEAD>
    	<TITLE>自由落下運動(摩擦,近似)</TITLE>
    	<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
    	<META NAME=viewport CONTENT="width=device-width, initial-scale=1">
    	<LINK REL="stylesheet" TYPE="text/css" HREF="../../../master.css">
    	<SCRIPT TYPE="text/javascript">
    		canvas  = null;
    		ctx     = null;
    		timerID = -1;
    		x0      = 0.0;   // 円の水平方向の初期位置
    		y0      = 0.0;   // 円の垂直方向の初期位置
    		x1      = 0.0;   // 円の位置( x ,摩擦無し)
    		y1      = 0.0;   // 円の位置( y ,摩擦無し)
    		x2      = 0.0;   // 円の位置( x ,摩擦あり)
    		y2      = 0.0;   // 円の位置( y ,摩擦あり)
    		t       = 0.0;   // 時間
    		dt      = 0.04;   // 時間の刻み幅
    		vx0     = 100.0;   // 水平方向の初期速度
    		vy0     = -200.0;   // 垂直方向の初期速度
    		vy      = vy0;   // 垂直方向の速度(摩擦無し)
    		vx_f    = vx0;   // 水平方向の速度(摩擦あり)
    		vy_f    = vy0;   // 垂直方向の速度(摩擦あり)
    		g       = 98.0;   // 加速度
    		k       = 0.2;   // 摩擦係数
    		m       = 1.0;   // 質量
    
    		function start() {
    			canvas = document.getElementById('canvas_e');
    			canvas.width  = 600;   // キャンバス要素の幅
    			canvas.height = 600;   // キャンバス要素の高さ
    			ctx = canvas.getContext('2d');
    			y0 = canvas.height / 2;
    			y1 = y0;
    			y2 = y0;
    			timerID = setInterval('draw()', 40);
    		}
    					// 描画
    		function draw()
    		{
    			if (x1 < canvas.height) {
    					// 摩擦無し
    				x1 += vx0 * dt;
    				let v1 = vy;
    				let v2 = vy + g * dt;
    				y1 += 0.5 * (v1 + v2) * dt;
    				vy = v2;
    					// 摩擦あり
    				v1 = vx_f;
    				v2 = vx_f + (-k * vx_f / m) * dt;
    				x2 += 0.5 * (v1 + v2) * dt;
    				vx_f = v2;
    
    				v1 = vy_f;
    				v2 = vy_f + (-k * vy_f / m + g) * dt;
    				y2 += 0.5 * (v1 + v2) * dt;
    				vy_f = v2;
    			}
    			else {
    				x1   = x0;
    				y1   = y0;
    				x2   = x0;
    				y2   = y0;
    				vy   = vy0;
    				vx_f = vx0;
    				vy_f = vy0;
    			}
    			ctx.clearRect(0, 0, canvas.width, canvas.height);
    			ctx.beginPath();
    			ctx.fillStyle = "rgb(0, 255, 0)";
    			ctx.arc(x1, y1, 20, 0, 2*Math.PI, false);
    			ctx.fill();
    			ctx.beginPath();
    			ctx.fillStyle = "rgb(255, 0, 0)";
    			ctx.arc(x2, y2, 20, 0, 2*Math.PI, false);
    			ctx.fill();
    		}
    	</SCRIPT>
    </HEAD>
    <BODY CLASS="white" STYLE="text-align: center" onLoad="start()">
    	<H1>自由落下運動(摩擦,近似)</H1>
    	<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="600" HEIGHT="600"></CANVAS>
    </BODY>
    </HTML>
    			
      上に示した例は多少わかりにくかったかもしれませんので,前章で示した速度加速度において示した例に対して,それらに摩擦を加えた結果を以下に示します(近似計算結果の表示).この例において,緑が摩擦がない場合,赤が摩擦がある場合を示しています.

      まず,等速直線運動において,摩擦がない場合は前章の結果と同じですが,摩擦がある場合は,速度に比例した摩擦によって加速度 - f1 * v12 ( f1 は摩擦係数)が生じるため,速度が徐々に遅くなり,最後には止まってしまいます.また,等加速度運動における摩擦がある場合は,本来の加速度 a と摩擦による逆向きの加速度 - f2 * v22 によって加速度は 0 に近づき,最終的には等速直線運動になります.
    <!DOCTYPE HTML>
    <HTML>
    <HEAD>
    	<TITLE>摩擦,近似</TITLE>
    	<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
    	<META NAME=viewport CONTENT="width=device-width, initial-scale=1">
    	<LINK REL="stylesheet" TYPE="text/css" HREF="../../../master.css">
    	<SCRIPT TYPE="text/javascript">
    		canvas  = null;
    		ctx     = null;
    		timerID = -1;
    		dt      = 0.04;   // 時間の刻み幅
    		x11     = 0.0;   // 円の位置( x ,摩擦無し,等速直線運動)
    		x12     = 0.0;   // 円の位置( x ,摩擦あり,等速直線運動)
    		y1      = 0.0;   // 円の位置( y ,等速直線運動)
    		v11     = 100.0;   // 円の速度(摩擦無し,等速直線運動)
    		v12     = 100.0;   // 円の速度(摩擦あり,等速直線運動)
    		x21     = 0.0;   // 円の位置( x ,摩擦無し,等加速度運動)
    		x22     = 0.0;   // 円の位置( x ,摩擦あり,等加速度運動)
    		y2      = 0.0;   // 円の位置( y ,等加速度運動)
    		v21     = 0.0;   // 円の速度(摩擦無し,等加速度運動)
    		v22     = 0.0;   // 円の速度(摩擦あり,等加速度運動)
    		a       = 200.0;   // 加速度
    		f1      = 0.2;   // 摩擦係数1
    		f2      = 0.7;   // 摩擦係数2
    
    		function start() {
    			canvas = document.getElementById('canvas_e');
    			canvas.width  = 600;   // キャンバス要素の幅
    			canvas.height = 400;   // キャンバス要素の高さ
    			ctx = canvas.getContext('2d');
    			y1  = canvas.height / 2 - 100;
    			y2  = canvas.height / 2 + 100;
    			timerID = setInterval('draw()', 33);
    		}
    					// 描画
    		function draw()
    		{
    			if (x11 < canvas.width) {
    							// 摩擦無し
    									// 等速直線運動
    				x11   += v11 * dt;
    									// 等加速度運動
    				let v  = v21 + a * dt;   // 加速度 a による速度の変化(加速)
    				x21   += 0.5 * (v21 + v) * dt;   // 加速前と加速後の速度の平均で位置を計算
    				v21    = v;
    							// 摩擦あり
    									// 等速直線運動+摩擦
    				v    = v12 - f1 * v12 * dt;   // 速度に比例した摩擦による速度の変化(減速)
    				x12 += 0.5 * (v12 + v) * dt;   // 減速前と減速後の速度の平均で位置を計算
    				v12  = v;
    									// 等加速度運動+摩擦
    				v    = v22 + (a - f2 * v22) * dt;   // 本来の加速度と速度に比例した摩擦による速度の変化
    				x22 += 0.5 * (v22 + v) * dt;   // 変化前と変化後の速度の平均で位置を計算
    				v22  = v;
    			}
    			else {
    				x11 = 0.0;
    				x12 = 0.0;
    				v12 = 100.0;
    				x21 = 0.0;
    				x22 = 0.0;
    				v21 = 0.0;
    				v22 = 0.0;
    			}
    
    			ctx.clearRect(0, 0, canvas.width, canvas.height);
    							// 摩擦無し
    			ctx.fillStyle = "rgb(0, 255, 0)";
    			ctx.beginPath();
    			ctx.arc(x11, y1, 20, 0, 2*Math.PI, false);
    			ctx.fill();
    			ctx.beginPath();
    			ctx.arc(x21, y2, 20, 0, 2*Math.PI, false);
    			ctx.fill();
    							// 摩擦あり
    			ctx.fillStyle = "rgb(255, 0, 0)";
    			ctx.beginPath();
    			ctx.arc(x12, y1, 20, 0, 2*Math.PI, false);
    			ctx.fill();
    			ctx.beginPath();
    			ctx.arc(x22, y2, 20, 0, 2*Math.PI, false);
    			ctx.fill();
    		}
    	</SCRIPT>
    </HEAD>
    <BODY CLASS="white" STYLE="text-align: center" onLoad="start()">
    	<H1>摩擦,近似</H1>
    	<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="600" HEIGHT="400"></CANVAS>
    </BODY>
    </HTML>
    			

  2. 周期運動

      ここでは,振り子やバネのような周期運動について説明します.右図に示すような剛体振り子に対する微分方程式(θ = 0 周りで線形化したもの)は,m を質量,g を重力加速度,r を棒の長さの半分,k を摩擦係数,I を慣性モーメントとすると,以下のようになります.

    また,p,q を利用して以下のように変形することができます.

    さらに,この微分方程式の解は,条件により,以下のような結果になります.

      以上の結果に基づき,window オブジェクトにおける setInterval メソッドを利用して,剛体振り子の運動を記述したものが以下に示すプログラムです.このプログラムでは,m = 2 * r = 1 を仮定しています.緑色の棒は摩擦がない場合( k = 0 ),赤い棒は k = 0.5 の場合,青い棒は k = 2.6 の場合を表しています.このように,摩擦がないと永久に振動し続け,k が小さい場合は振動しながら停止し,また,k が大きくなると振動せずに停止位置に向かいます.
    <!DOCTYPE HTML>
    <HTML>
    <HEAD>
    	<TITLE>剛体振り子</TITLE>
    	<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
    	<META NAME=viewport CONTENT="width=device-width, initial-scale=1">
    	<LINK REL="stylesheet" TYPE="text/css" HREF="../../../master.css">
    	<SCRIPT TYPE="text/javascript">
    		canvas  = null;
    		ctx     = null;
    		timerID = -1;
    		g       = 9.8;
    		m       = 1.0;
    		r       = 0.5;
    		I       = 4.0 * r * r / 12.0;
    		a20     = 20.0 * Math.PI / 180.0;
    		k1      = 0;
    		k2      = 0.5;
    		k3      = 2.6;
    		p1      = k1 / (I + m * r * r);
    		p2      = k2 / (I + m * r * r);
    		p3      = k3 / (I + m * r * r);
    		q       = m * r * g / (I + m * r * r);
    		alpha1  = -0.5 * p1;
    		beta1   = 0.5 * Math.sqrt(4 * q - p1 * p1);
    		c12     = 0.5 * Math.PI;
    		c11     = a20;
    		alpha2  = -0.5 * p2;
    		beta2   = 0.5 * Math.sqrt(4 * q - p2 * p2);
    		c22     = Math.atan(-beta2 / alpha2);
    		c21     = a20 / Math.sin(c22);
    		m1      = 0.5 * (-p3 + Math.sqrt(p3 * p3 - 4 * q));
    		m2      = 0.5 * (-p3 - Math.sqrt(p3 * p3 - 4 * q));
    		c31     = -a20 * m2 / (m1 - m2);
    		c32     = a20 - c31;
    		len     = 0.0;
    		t       = 0;
    		dt      = 0.01;
    		x1      = 0.0;
    		x2      = 0.0;
    		x3      = 0.0;
    		y1      = 0.0;
    		y2      = 0.0;
    		y3      = 0.0;
    
    		function start() {
    			canvas = document.getElementById('canvas_e');
    			canvas.width  = 400;   // キャンバス要素の幅
    			canvas.height = 600;   // キャンバス要素の高さ
    			ctx     = canvas.getContext('2d');
    			len     = canvas.height - 100;
    			let z   = Math.sin(a20);
    			x1      = 200 + len * Math.sin(z);
    			y1      = 50 + len * Math.cos(z);
    			x2      = x1;
    			y2      = y1;
    			x3      = x1;
    			y3      = y1;
    			timerID = setInterval('draw()', 40);
    		}
    					// 描画
    		function draw()
    		{
    			t += dt;
    
    			let z = c11 * Math.exp(alpha1 * t) * Math.sin(beta1 * t + c12);
    			x1    = 200 + len * Math.sin(z);
    			y1    = 50 + len * Math.cos(z);
    
    			z  = c21 * Math.exp(alpha2 * t) * Math.sin(beta2 * t + c22);
    			x2 = 200 + len * Math.sin(z);
    			y2 = 50 + len * Math.cos(z);
    
    			z  = c31 * Math.exp(m1 * t) + c32 * Math.exp(m2 * t);
    			x3 = 200 + len * Math.sin(z);
    			y3 = 50 + len * Math.cos(z);
    
    			ctx.clearRect(0, 0, canvas.width, canvas.height);
    							// 摩擦無し
    			ctx.lineWidth   = 3;
    			ctx.strokeStyle = "rgb(0, 255, 0)";
    			ctx.beginPath();
    			ctx.moveTo(200, 50);
    			ctx.lineTo(Math.floor(x1), Math.floor(y1));
    			ctx.stroke();
    							// 摩擦小,k = 0.5
    			ctx.strokeStyle = "rgb(255, 0, 0)";
    			ctx.beginPath();
    			ctx.moveTo(200, 50);
    			ctx.lineTo(Math.floor(x2), Math.floor(y2));
    			ctx.stroke();
    							// 摩擦大,k = 2.6
    			ctx.strokeStyle = "rgb(0, 0, 255)";
    			ctx.beginPath();
    			ctx.moveTo(200, 50);
    			ctx.lineTo(Math.floor(x3), Math.floor(y3));
    			ctx.stroke();
    		}
    	</SCRIPT>
    </HEAD>
    <BODY CLASS="white" STYLE="text-align: center" onLoad="start()">
    	<H1>剛体振り子</H1>
    	<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="400" HEIGHT="600"></CANVAS>
    </BODY>
    </HTML>
    			
      次のプログラムは,同じ問題に対し,時間と角度の変化を図示したものです.
    <!DOCTYPE HTML>
    <HTML>
    <HEAD>
    	<TITLE>剛体振り子(角度の変化)</TITLE>
    	<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
    	<META NAME=viewport CONTENT="width=device-width, initial-scale=1">
    	<LINK REL="stylesheet" TYPE="text/css" HREF="../../../master.css">
    	<SCRIPT TYPE="text/javascript">
    		canvas  = null;
    		ctx     = null;
    		timerID = -1;
    		g       = 9.8;
    		m       = 1.0;
    		r       = 0.5;
    		I       = 4.0 * r * r / 12.0;
    		a20     = 20.0;
    		k1      = 0;
    		k2      = 0.5;
    		k3      = 2.6;
    		p1      = k1 / (I + m * r * r);
    		p2      = k2 / (I + m * r * r);
    		p3      = k3 / (I + m * r * r);
    		q       = m * r * g / (I + m * r * r);
    		alpha1  = -0.5 * p1;
    		beta1   = 0.5 * Math.sqrt(4 * q - p1 * p1);
    		c12     = 0.5 * Math.PI;
    		c11     = a20;
    		alpha2  = -0.5 * p2;
    		beta2   = 0.5 * Math.sqrt(4 * q - p2 * p2);
    		c22     = Math.atan(-beta2 / alpha2);
    		c21     = a20 / Math.sin(c22);
    		m1      = 0.5 * (-p3 + Math.sqrt(p3 * p3 - 4 * q));
    		m2      = 0.5 * (-p3 - Math.sqrt(p3 * p3 - 4 * q));
    		c31     = -a20 * m2 / (m1 - m2);
    		c32     = a20 - c31;
    		amp     = 0.0;
    		t       = 0;
    		dt      = 0.01;
    		x       = 0.0;
    		y1      = 0.0;
    		y2      = 0.0;
    		y3      = 0.0;
    
    		function start() {
    			canvas = document.getElementById('canvas_e');
    			canvas.width  = 800;   // キャンバス要素の幅
    			canvas.height = 600;   // キャンバス要素の高さ
    			ctx     = canvas.getContext('2d');
    			amp     = (canvas.height / 2 - 20) / a20;
    			x       = 0;
    			y1      = canvas.height / 2 - a20 * amp;
    			y2      = y1;
    			y3      = y1;
    			timerID = setInterval('draw()', 40);
    		}
    					// 描画
    		function draw()
    		{
    			t += dt;
    
    			x  = 200 * t;
    			y1 = canvas.height / 2 - amp * c11 * Math.exp(alpha1 * t) * Math.sin(beta1 * t + c12);
    			y2 = canvas.height / 2 - amp * c21 * Math.exp(alpha2 * t) * Math.sin(beta2 * t + c22);
    			y3 = canvas.height / 2 - amp * (c31 * Math.exp(m1 * t) + c32 * Math.exp(m2 * t));
    
    			ctx.clearRect(0, 0, canvas.width, canvas.height);
    							// 軸
    			ctx.strokeStyle = "rgb(0, 0, 0)";
    			ctx.beginPath();
    			ctx.moveTo(0, canvas.height/2);
    			ctx.lineTo(canvas.width, canvas.height/2);
    			ctx.stroke();
    			ctx.font = "12px 'MS ゴシック'";
    			ctx.fillStyle = "rgb(0, 0, 0)";
    			ctx.fillText("時間", canvas.width-30, canvas.height/2+15);
    
    			ctx.strokeStyle = "rgb(192, 192, 192)";
    			ctx.beginPath();
    			ctx.moveTo(0, 20);
    			ctx.lineTo(canvas.width, 20);
    			ctx.stroke();
    			ctx.fillStyle = "rgb(0, 0, 0)";
    			ctx.fillText("θ=20度", 5, 15);
    
    			ctx.strokeStyle = "rgb(192, 192, 192)";
    			ctx.beginPath();
    			ctx.moveTo(0, canvas.height-20);
    			ctx.lineTo(canvas.width, canvas.height-20);
    			ctx.stroke();
    			ctx.fillStyle = "rgb(0, 0, 0)";
    			ctx.fillText("θ=-20度", 5, canvas.height-5);
    
    			if (x < canvas.width) {
    							// 摩擦無し
    				ctx.beginPath();
    				ctx.fillStyle = "rgb(0, 255, 0)";
    				ctx.arc(Math.floor(x), Math.floor(y1), 10, 0, 2*Math.PI, false);
    				ctx.fill();
    							// 摩擦小,k = 0.5
    				ctx.beginPath();
    				ctx.fillStyle = "rgb(255, 0, 0)";
    				ctx.arc(Math.floor(x), Math.floor(y2), 10, 0, 2*Math.PI, false);
    				ctx.fill();
    							// 摩擦大,k = 2.6
    				ctx.beginPath();
    				ctx.fillStyle = "rgb(0, 0, 255)";
    				ctx.arc(Math.floor(x), Math.floor(y3), 10, 0, 2*Math.PI, false);
    				ctx.fill();
    			}
    			else {
    				t  = 0.0;
    				x  = 0.0;
    				y1 = canvas.height / 2 - a20 * amp;
    				y2 = y1;
    				y3 = y1;
    			}
    		}
    	</SCRIPT>
    </HEAD>
    <BODY CLASS="white" STYLE="text-align: center" onLoad="start()">
    	<H1>剛体振り子(角度の変化)</H1>
    	<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="800" HEIGHT="600"></CANVAS>
    </BODY>
    </HTML>
    			
      次のプログラムは,同じ問題を先に述べた近似的方法で解き,時間と角度の変化を図示(近似)したものです.前の結果と大きくは変わりませんが,摩擦がない場合は,発散していく傾向が見られます(近似的方法の誤差による).
    <!DOCTYPE HTML>
    <HTML>
    <HEAD>
    	<TITLE>剛体振り子(角度の変化,近似)</TITLE>
    	<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
    	<META NAME=viewport CONTENT="width=device-width, initial-scale=1">
    	<LINK REL="stylesheet" TYPE="text/css" HREF="../../../master.css">
    	<SCRIPT TYPE="text/javascript">
    		canvas  = null;
    		ctx     = null;
    		timerID = -1;
    		g       = 9.8;
    		m       = 1.0;
    		r       = 0.5;
    		I       = 4.0 * r * r / 12.0;
    		a20     = 20.0;
    		k1      = 0;
    		k2      = 0.5;
    		k3      = 2.6;
    		p1      = k1 / (I + m * r * r);
    		p2      = k2 / (I + m * r * r);
    		p3      = k3 / (I + m * r * r);
    		q       = m * r * g / (I + m * r * r);
    		alpha1  = -0.5 * p1;
    		beta1   = 0.5 * Math.sqrt(4 * q - p1 * p1);
    		c12     = 0.5 * Math.PI;
    		c11     = a20;
    		alpha2  = -0.5 * p2;
    		beta2   = 0.5 * Math.sqrt(4 * q - p2 * p2);
    		c22     = Math.atan(-beta2 / alpha2);
    		c21     = a20 / Math.sin(c22);
    		m1      = 0.5 * (-p3 + Math.sqrt(p3 * p3 - 4 * q));
    		m2      = 0.5 * (-p3 - Math.sqrt(p3 * p3 - 4 * q));
    		c31     = -a20 * m2 / (m1 - m2);
    		c32     = a20 - c31;
    		amp     = 0.0;
    		t       = 0;
    		dt      = 0.01;
    		x       = 0.0;
    		y1      = 0.0;
    		y2      = 0.0;
    		y3      = 0.0;
    		a1      = 0.0;
    		a2      = 0.0;
    		a3      = 0.0;
    		v1      = 0.0;
    		v2      = 0.0;
    		v3      = 0.0;
    		w1      = 0.0;
    		w2      = 0.0;
    		w3      = 0.0;
    
    		function start() {
    			canvas = document.getElementById('canvas_e');
    			canvas.width  = 800;   // キャンバス要素の幅
    			canvas.height = 600;   // キャンバス要素の高さ
    			ctx = canvas.getContext('2d');
    
    			amp = (canvas.height / 2 - 20) / a20;
    
    			w1 = a20;
    			v1 = 0;
    			a1 = -p1 * v1 - q * w1;
    			x  = 0;
    			y1 = canvas.height / 2 - w1 * amp;
    
    			w2 = a20;
    			v2 = 0;
    			a2 = -p2 * v2 - q * w2;
    			y2 = canvas.height / 2 - w2 * amp;
    
    			w3 = a20;
    			v3 = 0;
    			a3 = -p3 * v3 - q * w3;
    			y3 = canvas.height / 2 - w3 * amp;
    
    			timerID = setInterval('draw()', 40);
    		}
    					// 描画
    		function draw()
    		{
    			t += dt;
    			x  = 200 * t;
    
    			let v = v1 + a1 * dt;   // 加速度から速度
    			w1   += 0.5 * (v + v1) * dt;
    			v1    = v;
    			a1    = -p1 * v1 - q * w1;   // 加速度
    			y1    = canvas.height / 2 - amp * w1;
    
    			v   = v2 + a2 * dt;
    			w2 += 0.5 * (v + v2) * dt;
    			v2  = v;
    			a2  = -p2 * v2 - q * w2;
    			y2  = canvas.height / 2 - amp * w2;
    
    			v   = v3 + a3 * dt;
    			w3 += 0.5 * (v + v3) * dt;
    			v3  = v;
    			a3  = -p3 * v3 - q * w3;
    			y3  = canvas.height / 2 - amp * w3;
    
    			ctx.clearRect(0, 0, canvas.width, canvas.height);
    							// 軸
    			ctx.strokeStyle = "rgb(0, 0, 0)";
    			ctx.beginPath();
    			ctx.moveTo(0, canvas.height/2);
    			ctx.lineTo(canvas.width, canvas.height/2);
    			ctx.stroke();
    			ctx.font = "12px 'MS ゴシック'";
    			ctx.fillStyle = "rgb(0, 0, 0)";
    			ctx.fillText("時間", canvas.width-30, canvas.height/2+15);
    
    			ctx.strokeStyle = "rgb(192, 192, 192)";
    			ctx.beginPath();
    			ctx.moveTo(0, 20);
    			ctx.lineTo(canvas.width, 20);
    			ctx.stroke();
    			ctx.fillStyle = "rgb(0, 0, 0)";
    			ctx.fillText("θ=20度", 5, 15);
    
    			ctx.strokeStyle = "rgb(192, 192, 192)";
    			ctx.beginPath();
    			ctx.moveTo(0, canvas.height-20);
    			ctx.lineTo(canvas.width, canvas.height-20);
    			ctx.stroke();
    			ctx.fillStyle = "rgb(0, 0, 0)";
    			ctx.fillText("θ=-20度", 5, canvas.height-5);
    
    			if (x < canvas.width) {
    							// 摩擦無し
    				ctx.beginPath();
    				ctx.fillStyle = "rgb(0, 255, 0)";
    				ctx.arc(Math.floor(x), Math.floor(y1), 10, 0, 2*Math.PI, false);
    				ctx.fill();
    							// 摩擦小,k = 0.5
    				ctx.beginPath();
    				ctx.fillStyle = "rgb(255, 0, 0)";
    				ctx.arc(Math.floor(x), Math.floor(y2), 10, 0, 2*Math.PI, false);
    				ctx.fill();
    							// 摩擦大,k = 2.6
    				ctx.beginPath();
    				ctx.fillStyle = "rgb(0, 0, 255)";
    				ctx.arc(Math.floor(x), Math.floor(y3), 10, 0, 2*Math.PI, false);
    				ctx.fill();
    			}
    			else {
    				t  = 0.0;
    				x  = 0;
    
    				w1 = a20;
    				v1 = 0;
    				a1 = -p1 * v1 - q * w1;
    				y1 = canvas.height / 2 - w1 * amp;
    
    				w2 = a20;
    				v2 = 0;
    				a2 = -p2 * v2 - q * w2;
    				y2 = canvas.height / 2 - w2 * amp;
    
    				w3 = a20;
    				v3 = 0;
    				a3 = -p3 * v3 - q * w3;
    				y3 = canvas.height / 2 - w3 * amp;
    			}
    		}
    	</SCRIPT>
    </HEAD>
    <BODY CLASS="white" STYLE="text-align: center" onLoad="start()">
    	<H1>剛体振り子(角度の変化,近似)</H1>
    	<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="800" HEIGHT="600"></CANVAS>
    </BODY>
    </HTML>
    			

  3. もう一つの例

      この例では,前の章で作成したもう一つの例に対し,速度に比例する摩擦を加えています.
    <!DOCTYPE HTML>
    <HTML>
    <HEAD>
    	<TITLE>等速度運動と等加速度運動(摩擦)</TITLE>
    	<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
    	<META NAME=viewport CONTENT="width=device-width, initial-scale=1">
    	<LINK REL="stylesheet" TYPE="text/css" HREF="../../master.css">
    	<SCRIPT TYPE="text/javascript">
    		canvas  = null;
    		ctx     = null;
    		timerID = -1;
    		x1      = 0.0;   // 円1の位置( x )
    		y1      = 0.0;   // 円1の位置( y )
    		x2      = 0.0;   // 円2の位置( x )
    		y2      = 0.0;   // 円2の位置( y )
    		x0      = 0.0;   // 円の水平方向の初期位置
    		t       = 0.0;   // 時間
    		dt      = 0.04;   // 時間の刻み幅
    		v10     = 50.0;   // 円1の初期速度
    		v20     = 0.0;   // 円2の初期速度
    		v1      = 60.0;   // 円1の速度
    		v2      = 0.0;   // 円2の速度
    		a       = 100.0;   // 円2の加速度
    		k       = 0.2;   // 摩擦係数
    		ang1    = -20 * Math.PI / 180;   // 円1の進行方向
    		ang2    = 20 * Math.PI / 180;   // 円2の進行方向
    
    		function start() {
    			canvas = document.getElementById('canvas_e');
    			canvas.width  = 600;   // キャンバス要素の幅
    			canvas.height = 400;   // キャンバス要素の高さ
    			ctx = canvas.getContext('2d');
    			y1  = canvas.height / 2;
    			y2  = canvas.height / 2;
    			timerID = setInterval('draw()', 40);
    		}
    					// 描画
    		function draw()
    		{
    			if (x2 < canvas.width) {
    				let t1 = v1;
    				let t2 = v1 - k * v1 * dt;
    				x1    += 0.5 * (t1 + t2) * Math.cos(ang1) * dt;
    				y1    += 0.5 * (t1 + t2) * Math.sin(ang1) * dt;
    				v1     = t2;
    				t1     = v2;
    				t2     = v2 + (a - k * v2) * dt;
    				x2    += 0.5 * (t1 + t2) * Math.cos(ang2) * dt;
    				y2    += 0.5 * (t1 + t2) * Math.sin(ang2) * dt;
    				v2     = t2;
    			}
    			else {
    				x1 = x0;
    				y1 = canvas.height / 2;
    				x2 = x0;
    				y2 = canvas.height / 2;
    				v1 = v10;
    				v2 = v20;
    				t  = 0;
    			}
    			ctx.clearRect(0, 0, canvas.width, canvas.height);
    
    			ctx.beginPath();
    			ctx.fillStyle = "rgb(0, 255, 0)";
    			ctx.arc(x1, y1, 20, 0, 2*Math.PI, false);
    			ctx.fill();
    
    			ctx.beginPath();
    			ctx.fillStyle = "rgb(255, 0, 0)";
    			ctx.arc(x2, y2, 20, 0, 2*Math.PI, false);
    			ctx.fill();
    		}
    	</SCRIPT>
    </HEAD>
    <BODY CLASS="white" STYLE="text-align: center" onLoad="start()">
    	<H1>等速度運動と等加速度運動(摩擦)</H1>
    	<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="600" HEIGHT="400"></CANVAS>
    </BODY>
    </HTML>
    			

情報学部 菅沼ホーム JavaScript 目次 基礎技術目次 索引