磁摆的力计算与数值积分

Force calculation for magnetic pendulum and numerical integration

我一直在研究磁摆的模拟(Magnetic Pendulum供参考)。现在,我有一个关于如何计算 forces/acceleration 的问题:
在您在网上找到的磁摆(例如上面提供的那个)和其他物理力和加速度计算的示例中,力是在起始位置计算的,该位置根据时间步长 dt 更新,然后在时间更新新的力t+dt 计算得到一个新位置等等。基本的数值积分,有意义。

然而,我注意到,如果我这样计算力,事情不会像人们预期的那样发展。例如:当钟摆被磁铁吸引时,它只会停在特定的磁铁上,即使你会认为它会 “过度摆动” 一点。因此,我为每个力引入了三个变量,这是所有以前的力加在一起,现在它似乎以某种方式正常工作。 我在想

  1. 我使用的计算力的方法在物理模拟中很有意义并且
  2. 如果不是,那我做错了什么?因为它似乎对其他人有用。

这是我的代码:

p5.disableFriendlyErrors = true;
let magnete = [];
let particles = [];
var maganzahl = 3; //number of magnets
var magradius = 100; //radius of magnets from mid-point
var G = 0.002; //coefficient of force towards middle (gravity)
var R = 0.2; //friction coefficient
var h = 50; //height of bob over magnets
var M = 150000; //strength of magnets
var m = 1; //mass (might not work)
var dt = 0.25; //timestep
var d = 2; //pixel density
var counter2 = 0;
var Reset;
var end = false;
//--------------------------------------------

function setup() {
  createCanvas(600, 600);
  pixelDensity(d);
  background(60);

  Reset = createButton('Reset');
  Reset.position(width + 19, 49);
  Reset.mousePressed(resetcanvas);

  //construction of magnets
  for (var i = 0; i < maganzahl; i++) {
    magnete.push(new Magnet((width / 2) + magradius * cos(TWO_PI * (i / maganzahl)), (height / 2) + magradius * sin(TWO_PI * (i / maganzahl)), i));
  }
}

//construction of a new "starting position" by mouse-click
function mousePressed() {
  if (mouseX < width && mouseY < height) {
    particles.push(new Particle(mouseX, mouseY));
  }
}

function draw() {

  for (var i = 0; i < particles.length; i++) {
    if (particles[i].counter < 1000) {
      //5 updates per frame(to speed it up)
      for (var k = 0; k < 5; k++) {
        for (var j = 0; j < magnete.length; j++) {
          particles[i].attracted(magnete[j]);
        }
        particles[i].update();
        particles[i].show2();
      }
    } else if (particles[i].counter < 1001) {
      particles[i].counter += 1;

      var nearest = [];
      for (var j = 0; j < magnete.length; j++) {
        nearest.push(particles[i].near(magnete[j]));
      }
      if (nearest.indexOf(min(nearest)) == 0) {
        var c = color("green");
      }
      if (nearest.indexOf(min(nearest)) == 1) {
        var c = color("purple");
      }
      if (nearest.indexOf(min(nearest)) == 2) {
        var c = color("orange");
      }
      if (nearest.indexOf(min(nearest)) == 3) {
        var c = color("blue");
      }
      if (nearest.indexOf(min(nearest)) == 4) {
        var c = color("red");
      }
      if (nearest.indexOf(min(nearest)) == 5) {
        var c = color("yellow");
      }
      //show particle trace according to nearest magnet
      particles[i].show(c);
    }
  }
  //displaying magnets
  for (var i = 0; i < magnete.length; i++) {
    magnete[i].show();
  }
  //displaying mid-point
  stroke(255);
  circle(width / 2, height / 2, 3);
}

function resetcanvas() {
  background(60);
}

function Particle(x, y) {
  this.orgpos = createVector(x, y);
  this.pos = createVector(x, y);
  this.prev = createVector(x, y);
  this.vel = createVector();
  this.acc = createVector();
  this.accpre = createVector();
  this.accprepre = createVector();
  this.velprediction = this.vel;
  this.magnetf = createVector();
  this.gravity = createVector();
  this.friction = createVector();
  this.shape = new Array();
  this.counter = 0;


  //calculating new positions
  this.update = function() {
    //predictor for velocity -> Beeman's algorithm
    this.velprediction.add(this.accpre.mult(3 / 2 * dt).add(this.accprepre.mult(-1 / 2 * dt)));

    var momgrav = createVector(width / 2 - this.pos.x, height / 2 - this.pos.y);
    var momfric = createVector(this.velprediction.x, this.velprediction.y);
    momgrav.mult(G * m); //force due to gravity
    momfric.mult(-R); //force due to friction
    this.gravity.add(momgrav);
    this.friction.add(momfric);

    //a = F/m
    this.acc = createVector((this.magnetf.x + this.gravity.x + this.friction.x) / m, (this.magnetf.y + this.gravity.y + this.friction.y) / m);

    //-=Beeman's Algorithm=-
    this.vel.add(this.acc.mult(dt * 1 / 3).add(this.accpre.mult(dt * 5 / 6)).add(this.accprepre.mult(-1 / 6 * dt)));
    this.pos.add(this.vel.mult(dt).add(this.accpre.mult(dt * dt * 2 / 3)).add(this.accprepre.mult(-1 / 6 * dt * dt)));

    this.accprepre = createVector(this.accpre.x, this.accpre.y);
    this.accpre = createVector(this.acc.x, this.acc.y);
    this.velprediction = createVector(this.vel.x, this.vel.y);
    this.counter += 1;
    this.shape.push(new p5.Vector(this.pos.x, this.pos.y));
  }

  //calculating force due to magnets -> attracted called earlier than update in sketch.js
  this.attracted = function(target) {
    var magn = createVector(target.pos.x - this.pos.x, target.pos.y - this.pos.y);
    var dist = sqrt(sq(h) + sq(magn.x) + sq(magn.y)); //distance bob - magnet
    strength = M / (Math.pow(dist, 3));
    magn.mult(strength);
    this.magnetf.add(magn);
  }

  //calculating distance to target
  this.near = function(target) {
    var dist = sqrt(sq(h) + sq(this.pos.x - target.pos.x) + sq(this.pos.y - target.pos.y));
    return (dist);
  }

  //trace
  this.show = function(col) {
    beginShape();
    stroke(col);
    for (var i = 0; i < this.shape.length - 1; i++) {
      line(this.shape[i].x, this.shape[i].y, this.shape[i + 1].x, this.shape[i + 1].y);
      strokeWeight(2);
      noFill();
    }
    endShape();
  }
  //dots
  this.show2 = function() {
    strokeWeight(1)
    point(this.pos.x, this.pos.y);
  }
}
function Magnet(x, y, n) {
  this.pos = createVector(x, y);
  this.n = n;

  this.show = function() {
    noStroke();
    //color for each magnet
    if (n == 0) {
      fill("green");
    }
    if (n == 1) {
      fill("purple");
    }
    if (n == 2) {
      fill("orange");
    }
    if (n == 3) {
      fill("blue");
    }
    if (n == 4) {
      fill("red");
    }
    if (n == 5) {
      fill("yellow");
    }
    strokeWeight(4);
    circle(this.pos.x, this.pos.y, 10);

  }
}

如有任何帮助,我们将不胜感激!

我找到问题了!所以显然在 p5.js 中你必须小心你的向量计算。例如,如果您执行以下操作:

[some variable] = [Vector].add([anotherVector].mult(2)); 

[Vector] 和 [anotherVector] 都改变了它们的值。现在我想起来是有道理的...
事实上,它似乎仍然有点“逼真”,而且我设法用它生成了一些漂亮的图片(比如这张 1 and this one 2),这对我来说仍然很神秘,但我想有时候数字会发挥它们的魔力; )

运行它: Code Preview

如果你想改变一些variables/edit: p5.js Web Editor