如果你看到这则信息,这表示下载可汗学院的外部资源时遇到困难.

If you're behind a web filter, please make sure that the domains *.kastatic.org and *.kasandbox.org are unblocked.

主要内容

空气和流体阻力

当一个物体通过液体或者气体时,也会发生摩擦。这种力有很多不同的名字,但都表示同一个意思:黏力、阻力、流体阻力。虽然最终结果跟我们之前举的摩擦力的例子一样(物体变慢),但我们计算阻力的方式会稍有不同。让我们来看看公式:
Fd=12ρv2ACdv^
现在,让我们对此进行分解,看看在 ProcessingJS 进行有效的模拟需要些什么,将它变为一个更简单的公式。
  • Fd 是指阻力,是我们最终想要求出并传递到applyForce()函数的向量。
  • -1/2 是一个常数: -0.5。 这在 ProcessingJS 的世界里是无关紧要的,因为我们无论如何都会为其他的常量编造数值。然而,它是负数这一点是非常重要的,因为它在告诉我们这个力左右在速度的反方向(和摩擦力一样)。
  • ρ 是希腊字母 rho,指的是液体的密度,这是我们不需要担心的东西。我们可以简化问题并认为他是个常数,1。
  • v 是物体移动的速度。 我们知道这个! 物体的速度是速度向量的大小:velocity.mag()v2 只是表示 v 的平方或者 vv
  • A 指的是物体推动液体(或气体)的正面的面积。比如,一个空气动力学兰博基尼会比箱形的沃尔沃感受到更小的空气阻力。 然而,对于一个基础的模拟,我们可以将我们物体想成是圆形的并忽略掉这个因素。
  • Cd 是阻力系数,和摩擦力系数(μ)完全一样。这是个根据我们想要强阻力还是弱阻力来决定的常数。
  • v^ 眼熟吗? 应该是的。这指的是速度的单位向量,也就是velocity.normalize()。就像摩擦力一样,阻力是作用在速度的反方向的力。
现在,我们已经分析了公式中的每一个部分,并确定了简单模拟所需要的内容,我们可以将公式简化为:
或者:
// 我们公式的第一部分(大小): v^2 * Cd
var c = 0.1;
var speed = velocity.mag();
var dragMagnitude = c * speed * speed;

// 我们公式的第二部分(方向):v unit vector * -1 
var drag = velocity.get();
drag.normalize();
drag.mult(-1);

// 大小和向量一起!
drag.mult(dragMagnitude);
让我们在 Mover 对象中用一次加法来实现阻力。当我们做摩擦力例子的时候,摩擦力永远存在。只要一个对象在移动,摩擦力就会使他减速。在这里,我们向这个环境中引入一个因素——Mover对象在穿过一个液体。Liquid 对象将是一个长方形,我们会知道它的位置,宽度,高度,以及阻力系数——也就是说对象通过它是简单(像在空气中)还是困难(像在蜜糖中)?此外,它还应该包含一个在屏幕上绘制自己的函数(已经另外两个函数,我们一会就会看到)。
var Liquid = function(x, y, w, h, c) {
  this.x = x;
  this.y = y;
  this.w = w;
  this.h = h;
  this.c = c;
};

Liquid.prototype.display = function() {
  noStroke();
  fill(50);
  rect(this.x, this.y, this.w, this.h);
};
主程序现在会声明并初始化一个新的 Liquid 对象实例。请注意阻力系数很低(0.1),否则对象会很快定制移动(这可能是你哪一天想要的结果)。
var liquid = new Liquid(0, height/2, width, height/2, 0.1);
现在有一个有趣的问题:我们如何让 Mover 对象和 Liquid 对象讲话?换句话说,我们想要执行以下操作:
当一个 Mover 穿过液体时,它会遇到阻力。
…或者在面对对象的语言中(假设我们在循环访问具有索引 iMover 对象阵列):
//这个 Mover 在液体里吗?
if (liquid.contains(movers[i])) {
    // 计算它的阻力
    var dragForce = liquid.calculateDrag(movers[i]);
    // 将阻力作用到Mover上
    movers[i].applyForce(dragForce);
}
上面的代码告诉我们,我们还需要给 Liquid 对象类型加两个函数:(1)一个判断 Mover 对象是不是在 Liquid 对象里的函数,以及(2)一个计算作用在Mover 对象上的阻力的函数。
第一个很简单;我们可以直接使用条件语句来判断位置向量是否位于液体定义的三角形中。
Liquid.prototype.contains = function(m) {
    var p = m.position;
    return p.x > this.x && p.x < this.x + this.w &&
         p.y > this.y && p.y < this.y + this.h;
};
drag() 函数稍微复杂一些;但是,我们已经写了它的代码。这只是在实现我们的公式。阻力等于在速度相反的方向上阻力系数乘以 Mover 的速度的平方!
Liquid.prototype.calculateDrag = function(m) {
  // 大小是系数 * 速度的平方
  var speed = m.velocity.mag();
  var dragMagnitude = this.c * speed * speed;

  // 方向是速度的倒数
  var dragForce = m.velocity.get();
  dragForce.mult(-1);

  // 按比例缩放
  dragForce.normalize();
  dragForce.mult(dragMagnitude);
  return dragForce;
};
将这两个函数添加到 Liquid 对象类型后,我们就准备好将它们都放到一个程序中。
运行程序的时候,你会注意到我们在模拟球掉进水中的过程。对象只有在穿过窗口下方的深蓝色部分(代表液体)时才会减速。你还会主要到小的对象比大的减速要多。还记得牛顿第二定律吗?A = F / M。加速度等于力除以质量。一个巨大的物体会加速的比较少。而小的物体会加速更多。在这个情况下,我们谈论的加速度是由于阻力造成的减速。较小的物体会比大的物体减速更多。
“自然模拟”系列课程是由 Daniel Shiffman 的 "编程的本质" 衍生而来,基于 知识共享 著名-非商用性 3.0 本地化许可协议

想加入讨论吗?

尚无帖子。
你会英语吗?单击此处查看更多可汗学院英文版的讨论.