/* This file is part of JOP, the Java Optimized Processor see <http://www.jopdesign.com/> Copyright (C) 2010, Wolfgang Puffitsch <wpuffits@mail.tuwien.ac.at> This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package cruiser.model; public class CarModel extends Thread { volatile long timestep = 0; public final static double TIME_SCALE = 0.005; // seconds final static double GRAVITY = 9.81; // meters per queare seconds final static double AIR_DENSITY = 1.2; // kilograms per cubic meter final static double REFERENCE_AREA = 2.25; // square meters final static double CD_FACTOR = 0.33; // air drag coefficient final static double CR_FACTOR = 0.025; // surface drag coefficient final static double MASS = 1550.0; // kilograms final static double MAX_ENGINE_FORCE = 8000.0; // cap maximum force (just a guess, accelerating with 0.5G) final static double MAX_ENGINE_POWER = 100*1000.0; // kilowatts final static double CLUTCH_LIMIT = 4.0; // upper limit for clutch in meters per second private double throttle = 0.0; // 0..1 final static double MAX_BRAKE_FORCE = 15000.0; // kilonewton (just a guess, braking with 1.0G) private double brake = 0.0; // 0..1 private double incline = 0.0; // road steepness, -0.5..0.5, more than that would probably flip the car... private double targetSpeed = 0.0; // just for debugging private double speed = 0.0; // meters per second private double distance = 0.0; // meters private double acceleration = 0.0; // meters per square second public void setThrottle(double t) { // limit throttle to valid range throttle = Math.max(0.0, Math.min(t, 1.0)); // System.err.println("new throttle: "+throttle); } public void setBrake(double b) { // limit brake to valid range brake = Math.max(0.0, Math.min(b, 1.0)); // System.err.println("new brake: "+brake); } public void setIncline(double d) { // limit incline to valid range incline = Math.max(-0.5, Math.min(d, 0.5)); } public void setTargetSpeed(double t) { // limit incline to valid range targetSpeed = t; } public double getSpeed() { return speed; } double windForce() { // drag rises with the square of the speed return 0.5*(speed*speed)*AIR_DENSITY*CD_FACTOR*REFERENCE_AREA; } double rollForce() { int direction = Double.compare(speed, 0.0); // mass times gravitational force if (direction > 0) { return CR_FACTOR*MASS*GRAVITY; } else if (direction < 0) { return -CR_FACTOR*MASS*GRAVITY; } // no roll force if we don't roll return 0.0; } double gravityForce() { return MASS*GRAVITY*incline; } double clutchFactor() { if (Double.compare(Math.abs(speed), CLUTCH_LIMIT) < 0) { return 1.0/(1.0+CLUTCH_LIMIT-Math.abs(speed)); } return 1.0; } double engineForce() { // limit maximum force from the engine if (Double.compare(speed, 0.0) == 0) { if (Double.compare(throttle, 0.0) > 0) { return MAX_ENGINE_FORCE; } else { return 0.0; } } return Math.min(MAX_ENGINE_FORCE, MAX_ENGINE_POWER*clutchFactor()*throttle/Math.abs(speed)); } double brakeForce() { // the force of the brake depends on the current direction int direction = Double.compare(speed, 0.0); if (direction > 0) { return brake*MAX_BRAKE_FORCE; } else if (direction < 0) { return -brake*MAX_BRAKE_FORCE; } else { // if we don't move, we work only against gravity if (Double.compare(brake, 0.0) > 0) { // limit the force against gravity with actually applied brake value return Math.min(Math.max(-brake*MAX_BRAKE_FORCE, -gravityForce()), brake*MAX_BRAKE_FORCE); } else { return 0.0; } } } public void run() { for (timestep = 0;; timestep++) { long startTime = System.currentTimeMillis(); // acceleration = \Delta speed = force / mass double acc = (engineForce()-brakeForce()-windForce()-rollForce()-gravityForce()); acceleration = acc / MASS; // System.err.println(speed*3.6+" "+acceleration+" "+engineForce()+" "+brakeForce()+" "+windForce()+" "+rollForce()+" "+gravityForce()); if (Double.compare(speed, 0.0) > 0) { speed = Math.max(speed+acceleration*TIME_SCALE, 0.0); } else if (Double.compare(speed, 0.0) < 0) { speed = Math.min(speed+acceleration*TIME_SCALE, 0.0); } else { speed += acceleration*TIME_SCALE; } // just for checking how far we've gone yet distance += speed * TIME_SCALE; // debugging output System.err.println(timestep*TIME_SCALE+" "+speed*3.6+" "+distance+" "+acceleration+" "+incline+" "+targetSpeed); long elapsedTime = System.currentTimeMillis() - startTime; try { if (elapsedTime < TIME_SCALE*1000) { sleep((int)(TIME_SCALE*1000-elapsedTime)); } } catch (InterruptedException exc) { // ignore } } } }