磁摆的力计算和数值积分

4

我一直在模拟一个磁力摆(Magnetic Pendulum 作为参考)。现在,我对如何计算力/加速度有一个问题:
在线上可以找到关于磁力摆的例子(如上面提供的链接),以及其他物理力和加速度计算的示例,在开始时计算出力,在时间步长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);

  }
}

非常感谢您的帮助!


1
这是一个好问题和有用的答案,但是您需要将答案发布为答案而不是作为对问题的编辑。请参见此处此处以供参考。 - William Miller
1
不需要在标题中加入[solved] :) 当系统允许时,您可以接受自己的答案来正确标记此问题为已解决。干杯! - Tim Lewis
2
@WilliamMiller 谢谢你的建议!现在应该已经修复了。 - Eioer
1个回答

1
我发现问题所在!在p5.js中,向量计算需要小心。例如,如果你做了这样的事情:
[some variable] = [Vector].add([anotherVector].mult(2)); 

两个向量 [Vector] 和 [anotherVector] 都会改变它们的值。现在我想一想,这是有道理的...
事实上,它仍然似乎以某种“真实”的方式工作,并且我成功地生成了一些美丽的图片(例如这张 1 和这张 2),但我猜有时候数字就是魔法 ;)

运行代码: Code Preview

如果你想更改一些变量/编辑: p5.js Web Editor


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接