Simulate Terminal Velocity - simulation

I am working on building a little game program like this one for a sky diving sim and I have got a lot of the equations down but my terminal velocity is way too high for the given alt for any of this. I have been looking at this and gone over it the only thing I can think of is that I have one of the measurements wrong or something. Any help will be appreciated with this.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace GasLaws
{
class Program
{
static void Main(string[] args)
{
double temperature;
double airPressure;
double airDensity;
double tV;
double alt;
//constants
const double gasCont = 287.05;
const double startTemp = 15; //this is C ground level
const double aidRate = 0.0065; //adiobatic rate for temperature by elevation
//Human Constannts
const double drag = 0.7; //in meters
const double area = 7.5; //ft^2
const double wieght = 175;
Console.WriteLine("Enter the alt in feet");
int tempint = Int32.Parse(Console.ReadLine());
alt = (double)tempint * 0.3048; //convert feet to meters
Console.WriteLine("Alt = " + alt + " m");
//calculate air pressur
airPressure = AirPressure(alt);
temperature = CalTemp(startTemp, alt, aidRate);
airDensity = AirDensity(airPressure, gasCont, temperature);
tV = TerminalVelocity(wieght, drag, airDensity, area);
//pasue screen for a second
Console.ReadLine();
}
//p = 101325(1-2.25577 * 10^-5 * alt) ^5
//this calculates correctly
private static double AirPressure(double al)
{
double tempAlt = 1 - 2.25577 * 0.00001 * al;
Console.WriteLine("Inside eq = " + tempAlt);
tempAlt = Math.Pow(tempAlt, 5 );
Console.WriteLine("Power of 5 = " + tempAlt);
tempAlt = 101325 * tempAlt;
Console.WriteLine("Pressure is = " + tempAlt + " Pascal");
return tempAlt;
}
//temperature calculation
// use adiobatic rate to calculate this
//this is right
private static double CalTemp(double t, double al, double rate) //start temperature and altitude
{
double nTemp = t;
for (int i = 0; i < al; i++)
{
nTemp -= rate;
}
Console.WriteLine("Temperature in for loop = " + nTemp);
return nTemp;
}
//claculate like this
//D Pressure / gas constant * temperature
//this works fine
private static double AirDensity(double pres, double gas, double temp)
{
temp = temp + 273.15; //convert temperautre to Kelvans
double dens = pres / (gas * temp);
dens = dens / 1000;
Console.WriteLine("PResure = " + pres);
Console.WriteLine("Gas cont = " + gas);
Console.WriteLine("Temperture = " + temp);
Console.WriteLine("Air Density is: " + dens);
return dens;
}
private static double TerminalVelocity(double w, double cd, double p, double a)
{
double v = (2 * w) / (cd * p * a) ;
v = Math.Sqrt(v);
Console.WriteLine("Terminal Velocity = " + v);
return v;
}
}
}

Your formula doesn't seem to include gravitational acceleration, and you are also mixing SI and US/imperial units. What unit will your calculated velocity have? It would probably be easier if you stay with SI units only. Another thing that looks a little strange is this line:
const double drag = 0.7; //in meters
The drag coefficient is a dimensionless number. It shouldn't have a physical unit (like meter).
The correct formula is:
v = sqrt((2 * m * g) / (d * A * C))
The variables, with corresponding SI units, are:
m [kg] - Mass of falling body.
g [m/s^2] - Gravitational acceleration.
d [kg/m^3] - Air density.
A [m^2] - Projected area.
C [-] - Drag coefficient.
If you use these units, the formula will yield the velocity in [m/s]. As an example. let's try the following values with units as above: m=80, g=9.8, d=1, A=0.7, C=0.7
This gives the terminal velocity v = 57 m/s which seems reasonable.

Related

How to modify this code to return Geopoint

I would like this code to return a newly constructed geopoint.
I need this,
GeoPoint prjTest=new GeoPoint(vxi+x,vyi+y);
to stick somewhere and return prjTest. I'm new to programming and I don't know well synthax.I tried many things, I can keep guessing for a long time. Please help. Thanks.
public class ProjectileTest
{
public ProjectileTest(float vi, float angle) /** renamed velocity -> vi */
{
//Starting location
double xi = 0, yi = 100;
final double gravity = -9.81;
//timeSlice declares the interval before checking the new location.
double timeSlice = 0.001; /** renamed time -> timeSlice */
double totalTime = 0; /** renamed recordedTime -> totalTime */
double vxi = vi * Math.cos(Math.toRadians(angle)); /** renamed xSpeed -> vxi */
double vyi = vi * Math.sin(Math.toRadians(angle)); /** renamed ySpeed -> vyi */
//This (secondsTillImpact) seems to give a very accurate time whenever the angle is positive.
double secondsTillImpact = Math.sqrt(2 * yi / -(gravity));
/** Not sure I agree. Does this formula take into account the upward motion
* of the projectile along its parabolic arc? My suspicion is that this
* formula only "works" when the initial theta is: 180 <= angle <= 360.
*
* Compare with the result predicted by quadratic(). Discarding the zero
* intercept which can't work for us (i.e. the negative one, because time
* only moves forward) leaves us with an expected result very close to the
* observed result.
*/
double y;
double x;/** Current position along the y-axis */
do {
// x = x + (xSpeed * time);
x = vxi * totalTime; /** Current position along the x-axis */
// y = y + (ySpeed * time);
y = yi + vyi * totalTime + .5 * gravity * (totalTime * totalTime);
// ySpeed = ySpeed + (gravity * time);
double vy = vyi + gravity * totalTime; /** Current velocity of vector y-component */
System.out.println("X: " + round2(x) + " Y: " + round2(y) + " YSpeed: " + round2(vy));
totalTime += timeSlice;
}
while (y > 0);
////////////////////////////++++++++ GeoPoint prjTest=new GeoPoint(vxi+x,vyi+y);
System.out.println("Incorrectly expected seconds: " + secondsTillImpact + "\nResult seconds: " + totalTime);
quadratic((.5 * gravity), vyi, yi);
}
public double round2(double n) {
return (int) (n * 100.0 + 0.5) / 100.0;
}
public void quadratic(double a, double b, double c) {
if (b * b - 4 * a * c < 0) {
System.out.println("No roots in R.");
} else {
double dRoot = Math.sqrt(b * b - 4 * a * c); /** root the discriminant */
double x1 = (-b + dRoot) / (2 * a); /** x-intercept 1 */
double x2 = (-b - dRoot) / (2 * a); /** x-intercept 2 */
System.out.println("x-int one: " + x1 + " x-int two: " + x2);
}
}
}

How do i make objects that are attracted to each other not bounce into oblivion in Unity3D?

so I'm trying to make a program that allows asteroids in a field to be attracted to each other like this:
https://www.youtube.com/watch?v=iAWZwTWJmhM
I have two programs to do this, one randomly generates asteroids, the other applies gravitational force to each object. the problem is that the asteroids will get faster as they get closer until they are bullet speed and the applied forces causes them to shoot away from each other and disappear. Is there a way to make them negate their forces on contact. I tried Rigidbody.isKinematic but that makes the asteroids still instead of rotating like they would in space. ill post the code below but here are the two projects I'm using the code from.
https://www.youtube.com/watch?v=Ouu3D_VHx9o
https://www.youtube.com/watch?v=6rTfZ2ox2_g
Code for asteroid spawner. I added in the random scale generator.:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AsteroidFieldGenerator : MonoBehaviour
{
public Transform AsteroidPrefab;
public int fieldRadius = 50;
public int asteroidCount = 60;
public float SizeMinPercent = 1;
public float SizeMaxPercent = 100;
// Start is called before the first frame update
void Start()
{
for (int loop = 0; loop < asteroidCount; loop++)
{
Instantiate(AsteroidPrefab, Random.insideUnitSphere * fieldRadius, Quaternion.identity);
AsteroidPrefab.transform.localScale = Vector3.one * (Random.Range(SizeMinPercent, SizeMaxPercent) / 100);
}
}
// Update is called once per frame
void Update()
{
}
}
Program for applying gravity:
'''
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Attractor : MonoBehaviour
{
const float G = 667.4f;
public static List<Attractor> Attractors;
public Rigidbody rb;
void FixedUpdate()
{
foreach (Attractor attractor in Attractors)
{
if (attractor != this)
Attract(attractor);
}
}
void OnEnable()
{
if (Attractors == null)
Attractors = new List<Attractor>();
Attractors.Add(this);
}
void OnDisable()
{
Attractors.Remove(this);
}
void Attract(Attractor objToAttract)
{
Rigidbody rbToAttract = objToAttract.rb;
Vector3 direction = rb.position - rbToAttract.position;
float distance = direction.magnitude;
if (distance == 0f)
return;
float forceMagnitude = G * (rb.mass * rbToAttract.mass) / Mathf.Pow(distance, 2);
Vector3 force = direction.normalized * forceMagnitude;
if (distance == 0)
force = force * 0;
rbToAttract.AddForce(force);
}
}
'''
You have to apply damping (resistance) forces, similar to say atmospheri resistance (air drag). Then the total energy of the system will decrease, which make it more likely that the particles cluster together. So basically, the equations of motion should be something like
F_grv[i,j,:] = G*mj*mi * (x[j,:] - x[i,:]) / norm(x[i,:] - x[j,:])^3
F_res[i,j,:] = - R( norm(x[i,:] - x[j,:]) ) * norm(v[i,:])^a * v[i,:]
R(u) = non-negative function that rapidly decreases when u goes away from 0,
and increasing rapidly when u gets very close to 0.
a is some positive number, say 1 or 2 or more.
dx[i,:]/dt = v[i,:]
dv[i,:]/dt = (1/mi) * sum(F_grv[i,j,:] + F_res[i,j] for j=1:n)
Here is a matlab code for the case of one particle orbiting a center of gravity with the standard Newtonian gravitational force acting on it plus a velocity dependent damping force:
function gravity_damping()
t = 0;
x0 = [5;1];
x_start = [-1; 10];
v_start = [0.15; 0.];
x = x_start;
v = v_start;
h = 0.3;
n = 700;
k0 = 7;
lambda = 2;
power1 = 10;
power2 = 2;
hold on
grid on
axis([-7 8 -3 12])
plot(x0(1), x0(2), 'ro');
for k = 1:n
t = t+h;
x = x + h*v/2;
v = v + h*F_grv(x-x0, 1, 1) + h*F_res(x-x0, v, k0, lambda, power1, power2);
x = x + h*v/2;
plot(x(1), x(2), 'bo');
pause(0.1)
end
end
function dvdt = F_grv(x_x0, mass, gr_const)
dvdt = - gr_const * mass * (x_x0) / norm(x_x0)^3;
end
function dvdt = F_res(x_x0, v, k0, a, power1, power2)
dvdt = - (k_res(norm(x_x0), k0, a, power1) * norm(v)^power2) * v;
end
function coeff = k_res(u, k0, a, power)
coeff = k0/(1 + (a*u)^(power));
end

How to get the points (coordinates) on 2D Line?

When I plot point1(p1) and point2(p2), the line between p1 and p2 is drawn. I wanna know a set of the points making the line.
For example, I wanna get x, y coordinates (as array type: x[], y[]). Is there any algorithms or code?
Here's what I have come up with:
It is fair to say that we need to use the slope formula, y = m*x + b to find the slope so we can plot our points along that line. We need the following:
(x1, y1)
(x2, y2)
to find the following:
m = (y2 - y1) / (x2 - x1)
b = y1 - (m * x1)
minX = min(x1, x2) used for limiting our lower bound
maxX = max(x1, x2) used for limiting our upper bound
Now that everything is set, we can plot our line pixel by pixel and obtain all (x,y) coordinates we need. The logic is simple:
let x loop from minX to maxX and plug it in y = m*x + b (we already have all the variables except y). Then, store the (x,y) pair.
I have used Java for coding this logically and visually. Also, I used LinkedList instead of arrays (because I we can't know the number of points we will obtain).
I have also drawn what Java would draw (in blue) and my approach (in red). They are almost perfectly the exact output and coordinates. The image below is zoomed 5x the original size.
Note! The above explanation is what you would use if the line is not vertical (because the slope would be undefined, division by zero). If it is, then you will plug y (instead of x) values and find the x (instead of y) value from the following formula x = (y - b) / m (instead of y = m*x + b). Though, the code takes care of vertical lines.
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.util.LinkedList;
import javax.swing.JFrame;
public class LineDrawing extends Canvas {
int x1 = 5;
int y1 = 10;
int x2 = 105;
int y2 = 100;
double m = ((double) (y2 - y1)) / ((double) (x2 - x1));//slope
double b = y1 - (m * ((double) x1));//vertical shift
//Takes care of the domain we will loop between.
//min and max will be assigned minX and maxX if the line is not vertical.
//minY and maxY are assigned to min and max otherwise.
int minX = Math.min(x1, x2);//minimum x value we should consider
int maxX = Math.max(x1, x2);//maximum x value we should consider
int minY = Math.min(y1, y2);//minimum y value we should consider
int maxY = Math.max(y1, y2);//maximum y value we should consider
int min = 0;
int max = 0;
boolean plugX = true;//if true, the line is not vertical.
LinkedList<Point> points = new LinkedList<>();//Store all points here
public LineDrawing() {
if (x1 == x2) {//plug the y value instead the x, this is a vertical line.
plugX = false;
min = minY;
max = maxY;
} else {//dont change and plug x values.
min = minX;
max = maxX;
}
}
#Override
public void paint(Graphics g) {
super.paint(g);
//Draw the line, using default java drawLine in blue.
g.setColor(Color.BLUE);
g.drawLine(x1, y1, x2, y2);
//change the color to red, it will draw our verison.
g.setColor(Color.RED);
//Draw the points, point by point on screen.
//Plug m, x, and b in the formula y = m*x + b
//to obtain the y value.
//OR
//Plug m, y, and b in the formula x = (y - b) / m
//to obtain the x value if vertical line.
//Then plot (x,y) coordinate on screen and add the point to our linkedList.
for (int i = min; i <= max; i++) {
int obtained = 0;
if (plugX) {//not a vertical line
obtained = (int) Math.round((m * i + b));
System.out.println("x = " + i + " , y = " + obtained);
points.add(new Point(i, obtained));
//Uncomment to see the full blue line.
g.drawLine(i, obtained, i, obtained);
} else {//vertical line
obtained = (int) Math.round((double) (i - b) / (double) m);
System.out.println("x = " + x1 + " , y = " + i);
g.drawLine(x1, i, x1, i);//Uncomment to see the full blue line.
points.add(new Point(x1, i));
}
}
//Print out the number of points as well as the coordinates themselves.
System.out.println("Total points: " + points.size());
for (int i = 0; i < points.size(); i++) {
System.out.println(i + " ( " + points.get(i).x
+ ", " + points.get(i).y + " )");
}
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setSize(120, 150);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new LineDrawing());
frame.setVisible(true);
}
}

How to reset a variable back to 0 after use in a loop in NXC

For some odd reason the variable "angle" will not reset back to 0 when the loop ends.
All of the math is just calculating c = sqrt(a^2 + b^2 - 2abCos(theta)) the robot won't do all of the math in one line.
In the full code a and b are both changing variables and are based on ultrasonic sensor input.
The sub may be called up to 3 different times and the angle variable needs to start at 0 each time the sub is called.
I have tried putting float angle = 0; or just angle = 0; in every spot imaginable but nothing works. I have even tried using int angle = 0; in multiple places.
int angle, a, b, c, csqr, theta, cosTheta, aSqrd, bSqrd, atmb, twoab;
#define pi 3.14159265359
sub calculate()
{
repeat(2)
{
float a = 172.42;
float angle = angle + 3;
float theta = ((angle)*(pi/180));
float b = 172.42;
float cosTheta = cos(theta);
float aSqrd = pow(a, 2);
float bSqrd = pow(b, 2);
float atmb = (a * b);
float twoab = (2 * atmb);
float csqr = ((aSqrd + bSqrd) - (twoab * cosTheta));
float c = sqrt(csqr);
NumOut(0,0,angle);
Wait(3000);
ClearScreen();
}
float angle = 0;
}
task main()
{
calculate();
ClearScreen();
calculate();
}
Because float angle is local to the calculate method and hides the int angle in global scope. The int angle is not initialized to anything.
You have an uninitialized variable in the repeat(2) loop.
float angle = angle + 3;

Transform screen coordinates to model coordinates

I've got some sort of newbie question.
In my application (processingjs) i use scale() and translate() to allow the user to zoom and scroll through the scene. As long as i keep the scale set to 1.0 i've got no issues. BUT whenever i use the scale (i.e. scale(0.5)) i'm lost...
I need the mouseX and mouseY translated to the scene coordinates, which i use to determine the mouseOver state of the object I draw on the scene.
Can anybody help me how to translate these coordinates?
Thanks in advance!
/Richard
Unfortunately for me this required a code modification. I'll look at submitting this to the Processing.JS code repository at some point, but here's what I did.
First, you'll want to use modelX() and modelY() to get the coordinates of the mouse in world view. That will look like this:
float model_x = modelX(mouseX, mouseY);
float model_y = modelY(mouseX, mouseY);
Unfortunately Processing.JS doesn't seem to calculate the modelX() and modelY() values correctly in a 2D environment. To correct that I changed the functions to be as follows. Note the test for mv.length == 16 and the section at the end for 2D:
p.modelX = function(x, y, z) {
var mv = modelView.array();
if (mv.length == 16) {
var ci = cameraInv.array();
var ax = mv[0] * x + mv[1] * y + mv[2] * z + mv[3];
var ay = mv[4] * x + mv[5] * y + mv[6] * z + mv[7];
var az = mv[8] * x + mv[9] * y + mv[10] * z + mv[11];
var aw = mv[12] * x + mv[13] * y + mv[14] * z + mv[15];
var ox = 0, ow = 0;
var ox = ci[0] * ax + ci[1] * ay + ci[2] * az + ci[3] * aw;
var ow = ci[12] * ax + ci[13] * ay + ci[14] * az + ci[15] * aw;
return ow !== 0 ? ox / ow : ox
}
// We assume that we're in 2D
var mvi = modelView.get();
// NOTE that the modelViewInv doesn't seem to be correct in this case, so
// having to re-derive the inverse
mvi.invert();
return mvi.multX(x, y);
};
p.modelY = function(x, y, z) {
var mv = modelView.array();
if (mv.length == 16) {
var ci = cameraInv.array();
var ax = mv[0] * x + mv[1] * y + mv[2] * z + mv[3];
var ay = mv[4] * x + mv[5] * y + mv[6] * z + mv[7];
var az = mv[8] * x + mv[9] * y + mv[10] * z + mv[11];
var aw = mv[12] * x + mv[13] * y + mv[14] * z + mv[15];
var oy = ci[4] * ax + ci[5] * ay + ci[6] * az + ci[7] * aw;
var ow = ci[12] * ax + ci[13] * ay + ci[14] * az + ci[15] * aw;
return ow !== 0 ? oy / ow : oy
}
// We assume that we're in 2D
var mvi = modelView.get();
// NOTE that the modelViewInv doesn't seem to be correct in this case, so
// having to re-derive the inverse
mvi.invert();
return mvi.multY(x, y);
};
I hope that helps someone else who is having this problem.
Have you tried another method?
For example, assume that you are in a 2D environment, you can "map" all the frame in a sort of matrix.
Something like this:
int fWidth = 30;
int fHeight = 20;
float objWidth = 10;
float objHeight = 10;
void setup(){
fWidth = 30;
fHeight = 20;
objWidth = 10;
objHeight = 10;
size(fWidth * objWidth, fHeight * objHeight);
}
In this case you will have a 300*200 frame, but divided in 30*20 sections.
This allows you to move in somewhat ordered way your objects.
When you draw an object you have to give his sizes, so you can use objWidth and objHeight.
Here's the deal: you can make a "zoom-method" that edit the value of the object sizes.
In this way you drew a smaller/bigger object without editing any frame property.
This is a simple example because of your inaccurate question.
You can do it [in more complex ways], in a 3D environment too.