问题描述
我一直在模拟磁摆(供参考的Magnetic Pendulum)。现在,我有一个关于如何计算力/加速度的问题:
在示例中,您可以在线找到磁摆(例如上面提供的摆锤)以及其他物理力和加速度计算,这些力是在起始位置计算的,该位置是根据时间步长dt更新的,然后是当时的新力计算t + dt以获得新位置,依此类推。基本的数值积分很有意义。
但是,我注意到,如果以这种方式计算力,事情将不会像人们期望的那样进行。例如:当钟摆被磁铁吸引时,它会刚好停在特定的磁铁上,甚至会变硬,您可能会希望它稍微“飞越” 。因此,我为每个力引入了三个变量,这三个变量是以前所有力的总和,现在看来它可以正常工作。 我想知道
- 我使用的力的计算方法在物理模拟中很有意义,并且
- 如果不是,那我在做什么错?因为它似乎对其他人有用。
这是我的代码:
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和这张2)这一事实对我来说还是很神秘的,但是我猜猜有时候数字只是在发挥作用;)
运行它: Code Preview
如果要更改一些变量/编辑: p5.js Web Editor