How to accurately model wind as a force, without a terminal velocity

edited August 2014 in Questions about Code

I'm making my way through The Nature of Code (awesome book btw), and I came across a problem while making a sketch of some falling balls with wind.

Here is my sketch:

float centerX, centerY;
PVector gravity, wind;
ArrayList movers;
int moverCount = 10;
boolean limitVelocity = true;
float maxYSpeed = 10;
float maxXSpeed = 10;

void setup()
{
  ellipseMode(RADIUS);
  size(600, 600);
  centerX = width/2;
  centerY = height/2;

  movers = new ArrayList<Mover>();
  for (int i=0; i < moverCount; i++)
  {
    float mass = random(1, 10);
    movers.add(new Mover(new PVector(i * 25, 10), null, null,  mass, mass));
  }

  wind = new PVector(1, 0);
}

void draw()
{
  background(0);
  for (int i=0; i < moverCount; i++)
  {
    Mover mover = (Mover)movers.get(i);
    gravity = new PVector(0, .1 * mover.mass);
    mover.ApplyForce(gravity);
    mover.ApplyForce(wind);
    mover.Update();
    mover.Wrap();
    mover.Display();
  }
}

class Mover
{
  public float mass;
  private PVector pos;
  private PVector vel;
  private PVector acc;
  private float r;
  private color c;

  Mover(PVector pos, PVector vel, PVector acc, float mass, float r)
  {
    if (pos == null)
      this.pos = new PVector(centerX, centerY);
    else
      this.pos = pos;

    if (vel == null)
      this.vel = new PVector();
    else
      this.vel = vel;

    if (acc == null)
      this.acc = new PVector();
    else
      this.acc = acc;

    this.mass = mass;
    this.r = r;
    c = color(random(255), random(255), random(255));
  }

  void ApplyForce(PVector force)
  {
    PVector f = PVector.div(force.get(), mass);
    acc.add(f);
  }

  void Update()
  {
    vel.add(acc);
    if (limitVelocity)
    {
      //limitting X and Y seperately to keep objects falling uniformly
      vel.x = constrain(vel.x, -maxXSpeed, maxXSpeed);
      vel.y = constrain(vel.y, 0, maxYSpeed);
    }
    pos.add(vel);
    acc.mult(0);
  }

  void Display()
  {
    fill(c);
    ellipse(pos.x, pos.y, r, r);
  }

  void Wrap()
  {
    if (pos.x < 0)
      pos.x = width;
    if (pos.x > width)
      pos.x = 0;
    if (pos.y < 0)
      pos.y = height;
    if (pos.y > height)
      pos.y = 0;
  }
}

Now here is the problem. When you set "limitVelocity" to false the objects get faster and faster in both the x and y direction. This makes sense for gravity because it is a constant acceleration. It doesn't make sense for wind however. According to common sense, an object being blown at a constant wind speed will never accelerate above the wind speed. But under this model above, using "ApplyForce" will continually increase the velocity. I don't just want to artificially clamp the x speed at the wind speed, because that doesn't seem right, and what if there are other forces acting on the balls (like say magnetism)?

How can I model this accurately? I'd especially like to hear from Daniel Shiffman on this one!

Thanks!

Answers

  • edited August 2014 Answer ✓

    Well, truth is, if you would keep blowing on something, it would go faster and faster until it reaches relativistic speed! That is, unless there is something else working on it. On Earth, there is always friction by air (even in the best vacuums we try to achieve in the lab). So, what you need to do is implement this friction force. It is proportional to velocity (well, it is a function of velocity, depending on the object's shape this can be quite complex, see aerodynamics etc. but let's just assume it's a linear function). Do this in the same way as you did gravity and wind.

    Because the air friction (or drag) is proportional to velocity, the force becomes stronger when you go faster, while the wind is constant. This means there will be a point where the two forces cancel each other out so the acceleration is 0 and the velocity constant: this is the proper definition of terminal velocity.

    float dragCoefficient = -1; //Play around until you find a good value
    PVector drag = new PVector(dragCoefficient*mover.vel.x, dragCoefficient*mover.vel.y);
    mover.ApplyForce(drag);
    

    Small remark: by convention, method names always use a lower case letter for the first word: applyForce(). This is to distinguish them from class names and initialisations, but of course it doesn't matter to the compiler.

  • Thanks! That makes sense. This also made me realize that objects of different mass actually do fall at different speeds when drag is taken into account! Greater mass means greater terminal velocity. We normally don't notice this difference because it is so slight. I'm playing with the numbers to find values that make it behave realistically.

    Regarding the naming conventions, I've been programming a lot of C# lately, so it's difficult to break the habit of capitalizing method names.

  • edited August 2014

    I came across this again by accident and wanted to justify this one thing. The wind and drag forces are actually just one force so if you wanted it to be a realistic physical model it's probably better to do it that way. This means the wind force replaces the drag force but now it's dependent on the velocity of the particle. When the particle is stationary, the wind force is what it's now (1,0). When the particle moves at the same speed and in the same direction as the wind, the force should be 0.

        float dragCoefficient = 10/mover.r; //Play around until you find a good value
        PVector drag = new PVector(dragCoefficient*wind.x-mover.vel.x, dragCoefficient*wind.y-mover.vel.y);
        mover.ApplyForce(drag);
    

    It's even more fun if you make the wind dependent on time (with a little viz line):

      wind = new PVector( sin(float(frameCount)/60), cos(float(frameCount)/60));
      pushMatrix();
      translate(100,50);
      rotate(wind.heading());
      strokeWeight(5);
      stroke(255,0,0);
      line(0,0,40,0);
      popMatrix();
      noStroke();
    

    The model I described in my first post isn't incorrect, it just assumes the wind is blowing equally hard on all particles regardless of their velocity (as if somebody in an airship is racing after them and blowing on them).

Sign In or Register to comment.