Q068891のメモ帳

気が向いたときにLinuxだったり、プログラムだったり、適当なメモをざっくばらんに書いてます。

HTML5 canvas + javascript でLévy walkを描画

下記一様なランダムウォークに引き続き、HTML5 canvas + javascript で lévy walkのアニメーションを作成してみました。 q068891.hatenablog.com

lévy walkは移動距離の頻度がべき分布に従うランダムウォークの一種です。

普段はごにょごにょ近くを移動して、たまーに遠くに移動するという動きをします。

人間も一緒です。

普段近所のコンビニとか近くを移動しますが、旅行等でたまーに遠くに移動します。 そういう意味では、移動距離の頻度が一様なランダムウォークよりも(ごにょごにょ近くしか移動しない)、人間の動き方により近いモデルと言えます。

実際に下記論文では100,000個の携帯電話の移動データを利用して、人間がlévy walk的に動いていることを示しています。

https://arxiv.org/pdf/0806.1256.pdf

人間の他にも様々な動物がlévy walk的な動きをしていることがわかっています。

動物の場合はそこら辺の近くで餌を探して、たまに遠くへ餌場を移していると考えると直感的にも理解できる気がします。 まぁなんにせよ一様なランダムウォークよりも、猿や人間等の動きを表すことができているモデルと言えます。

ソース

<script type="text/javascript">

    //べき指数
    var power = 2.0;

    //キャンパスの大きさ    
    var height = 600;
    var width = 600;

    //walkerの数
    var walker_num = 20;

    //walkerが1回で進む距離
    var d = 1;

    //walkerが最大でどれくらい進むか最大距離。べき分布なのでどこかで最大値を打ち切らないとシミュレーションできない。
    var h = 1000000000;
    var ctx;
    var radian;

    //walkerの現在位置配列x,y
    var x = new Array(walker_num);
    var y = new Array(walker_num);

    var walker_radian = new Array(walker_num);
    var number_of_walk = new Array(walker_num);


    //walker毎に色をランダムに決定する
    var color_r = new Array(walker_num);
    var color_g = new Array(walker_num);
    var color_b = new Array(walker_num);

    for (var i=0;i<walker_num;i++){
      //初期位置をランダムに決定
      x[i] = height * Math.random();
      y[i] = width * Math.random();
      number_of_walk[i] = 0;
      walker_radian[i] = 0;

      color_r[i] = Math.floor(Math.random() * 256);
      color_g[i] = Math.floor(Math.random() * 256);
      color_b[i] = Math.floor(Math.random() * 256);
    }

    function init(){
      var canvas = document.getElementById('levywalk');
      ctx = canvas.getContext('2d');
      setInterval(draw, 10);
    }

    function draw(){

      //枠の四角描画
      ctx.strokeStyle = 'rgb(0,0,0)';
      ctx.strokeRect(0, 0, width, height);

      //walker描画
      for (var i=0;i<walker_num;i++){
        ctx.beginPath();
        //walkerの色をランダムに決定。rgbが数値だけ受け取り、変数を受け取ってくれないので多少メンドクサイ書き方になってる
        ctx.strokeStyle = 'rgb(' + (color_r[i]) + ',' + (color_g[i]) + ',' + (color_b[i]) + ')';
        ctx.arc(x[i],y[i],0.05,0,Math.PI*2,false);
        ctx.stroke();
        
      }

      //walkerが次に移動する座標を計算
      for (var i=0;i<walker_num;i++){

        //もし、べき分布からランダムに決定した距離を歩き済みだったら、進む角度をランダムに決定 & 次に進む距離をべき分布からランダムに決定
        //べき分布で決められた距離をまだ歩ききっていなかったらそのまま歩く
        if(number_of_walk[i] <= 0){
          radian = 2.0 * Math.PI * Math.random();
          walker_radian[i] = radian;
          
          var tmp1 =  Math.pow(d,-power);
          var tmp2 =  Math.pow(width*h,-power) - tmp1;
          var tmp3 =  tmp2 * Math.random() + tmp1;
          number_of_walk[i] =  Math.pow(tmp3 ,(1.0/-power));
        }

        //計算した角度に距離d分移動し次の座標へ移動
        x[i] = x[i] + d * Math.cos(walker_radian[i]);
        y[i] = y[i] + d * Math.sin(walker_radian[i]);
        number_of_walk[i] = number_of_walk[i] - 1;  

        //周期的境界条件
        if(width <= x[i]){
          x[i] = x[i] - width;
        }
        if(height <= y[i]){
          y[i] = y[i] - height;
        }
        if(x[i] <= 0){
          x[i] = x[i] + width;
        }
        if(y[i] <= 0){
          y[i] = y[i] + height;
        }
        
      }
    }

</script>

<body onload="init();">
  <canvas id="levywalk" width="600" height="600"></canvas>
</body>