/** This is a 2-dimensional ballistics / aerospace simulation that accurately models air resistance (using the U.S. Standard Atmosphere as implemented in StandardAtmosphere.frink ) and the curvature of the earth (in 2 dimensions.) ` It can be used to model anything from orbital decay to hypervelocity meteor impacts to orbital decay due to atmosphere. Using the defaults below, an orbit of a small iron sphere starts approximately circularly at an altitude of 180 km above earth's surface and decays over the course of several days until reeentry. The variant meteorCrater.frink models a hypervelocity impactor for Meteor Crater, Arizona and shows the huge amount of energy radiated by pushing through atmosphere. */ use StandardAtmosphere.frink // h0 is height above ground (initial height) // Highest X-15 flight, flight 149, 22 August 1963 // https://en.wikipedia.org/wiki/List_of_X-15_flights h0 = 354200. ft h = h0 // m1 is the mass of the projectile // https://en.wikipedia.org/wiki/North_American_X-15 //m1 = 33500 lb // Gross weight m1 = 14600. lb // Empty weight // Cd is drag coefficient of projectile // // THERE IS LOTS OF DATA HERE FOR THE X-15 // https://citeseerx.ist.psu.edu/document?repid=rep1&type=pdf&doi=e65b16435676e88edffaaba028ee0d03abc2bd93 Cd = 0.0645 // area is area of projectile in direction of travel. // area of a sphere can be calculated from mass and density as: // area = (3/4)^(2/3) m1^(2/3) pi^(1/3) density^(-2/3) // // https://frinklang.org/fsp/solve2.fsp?equations=area+%3D+pi+radius%5E2%0D%0Avolume+%3D+4%2F3+pi+radius%5E3%0D%0Adiameter+%3D+2+radius%0D%0Amass+%3D+volume+density%0D%0A%0D%0A&solveFor=&f=on&ev=on&sel_area=L&val_area=33+cm%5E2&sel_density=L&val_density=7+water&sel_diameter=S&val_diameter=&sel_mass=L&val_mass=1+kg&sel_pi=L&val_pi=3.141592653589793238&sel_radius=S&val_radius=&sel_volume=S&val_volume=&resultAs=cm&solved=on&showorig=on //density = 7 g/cm^3 //area = (3/4)^(2/3) m1^(2/3) pi^(1/3) density^(-2/3) // THERE IS LOTS OF DATA HERE FOR THE X-15 // https://citeseerx.ist.psu.edu/document?repid=rep1&type=pdf&doi=e65b16435676e88edffaaba028ee0d03abc2bd93 area = 13.60 ft^2 //println["Area is " + (area->"cm^2")] //area = 0.7 m^2 // Initial velocity in the x direction (horizontal) // (Orbital velocity can be found as v = sqrt[G planetmass / r] ) vx = 3794 mph // Initial velocity in the y direction (vertical, positive is up) vy = 0 km/s planetmass = earthmass r = earthradius // x and y are a cartesian coordinate system with the center of the planet // at x=0 m, y=0 m. The projectile typically begins its journey at x=0 and // at a given height-above-ground. x = 0 m y = r + h initialGeopotentialHeight = (r * h) / (r + h) //println["Geopotential height = " + (geopotentialHeight -> "ft")] initialGeopotentialEnergy = m1 gravity initialGeopotentialHeight initialKineticEnergy = 1/2 m1 sqrt[vx^2 + vy^2]^2 timestep = .1 s t = 0 s // Energy lost to drag Edrag = 0 J g = new graphics p = new polyline do { // l is distance from center of earth l2 = x^2 + y^2 l = sqrt[l2] h = l - r // Angle with respect to center of the earth alpha = arctan[x,y] // Force due to gravity fg = - G m1 planetmass / l2 // Acceleration due to gravity ag = fg / m1 agx = ag sin[alpha] agy = ag cos[alpha] // Atmospheric drag v2 = vx^2 + vy^2 v = sqrt[v2] // Angle of travel (0 is in x direction, 90 degrees in y direction) theta = arctan[vy, vx] [temp, pressure] = StandardAtmosphere.getTemperatureAndPressure[h] density = StandardAtmosphere.getDensity[h, temp, pressure] fdrag = 1/2 density v2 Cd area adrag = -fdrag / m1 adragx = adrag cos[theta] adragy = adrag sin[theta] t = t + timestep // Total acceleration axtotal = agx + adragx aytotal = agy + adragy atotal = sqrt[axtotal^2 + aytotal^2] dvx = axtotal timestep dvy = aytotal timestep vx = vx + dvx vy = vy + dvy dx = vx timestep dy = vy timestep // Energy lost to drag // E = f * d = f * v * t dragpow = fdrag v Edrag = Edrag + fdrag v timestep x = x + dx y = y + dy p.addPoint[x/m,-y/m] geopotentialHeight = (r * h) / (r + h) geopotentialEnergy = m1 gravity geopotentialHeight kineticEnergy = 1/2 m1 (vx^2 + vy^2) totalEnergy = geopotentialEnergy + kineticEnergy // println["agx=$agx\tagy=$agy"] // println["adragx=$adragx\tadragy=$adragy"] // println[format[t,"s",3] + "\t" + format[x,"m",3] + "\t" + format[y,"m", 3] + "\t" + format[h,"m",3] + "\t" + format[agx,"gee",3] + "\t" + format[agy,"gee",3]] if t mod (1 s) == 0 s println[format[t,"s",3] + "\t" + format[x,"m",3] + "\t" + format[y,"m", 3] + "\t" + format[h,"m",3] + "\t" + format[adragx,"gee",8] + "\t" + format[adragy,"gee",8] + "\t" + format[adrag,"gee",8] + "\t" + format[vx,"mph",3] + "\t" + format[vy,"mph",3] + "\t" + format[v,"mph",3] + "\t" + format[Edrag, "J", 3] + "\t" + format[dragpow,"W", 3]] } while h >= 0 ft initialEnergy = initialGeopotentialEnergy + initialKineticEnergy println["Initial potential energy = $initialGeopotentialEnergy"] println["Initial kinetic energy = $initialKineticEnergy"] println["Initial total energy = " + (initialGeopotentialEnergy + initialKineticEnergy)] println["Final kinetic energy = " + (1/2 m1 v2)] println["Energy lost to drag = $Edrag"] println["Fraction of energy lost to drag = " + format[Edrag / initialEnergy, "percent", 4]] [left, top, right, bottom] = getBoundingBox[p] g.saveClip[] g.clipRectSides[left,top,right,bottom] g.color[0,0,1] g.fillEllipseCenter[0,0,2 earthradius/m, 2 earthradius/m] g.color[0,0,0] g.add[p] g.restoreClip[] g.font["SansSerif", 10 km/m] g.caption[formatFix[x,"miles", 0]] g.caption[formatFix[h0,"miles", 0], "left", 90 deg] g.show[] g.write["X-15.png",400,undef] // Frink solver: // https://frinklang.org/fsp/solve2.fsp?equations=E+%3D+mass+gravity+height%0D%0AE+%3D+1%2F2+mass+velocity%5E2%0D%0Adistance+%3D+height+glideslope%0D%0A&solveFor=&f=m&ev=on&sel_distance=S&val_distance=&sel_E=S&val_E=&sel_glideslope=L&val_glideslope=+4&sel_gravity=L&val_gravity=196133%2F20000+m+s%5E-2&sel_height=S&val_height=+&sel_mass=S&val_mass=+&sel_velocity=L&val_velocity=4554.+mph&resultAs=miles&solved=on&showorig=on glideslope = 4/1 maxdistance = glideslope v^2 / (2 gravity) println["Maximum distance at glideslope of $glideslope:1 is " + format[maxdistance, "miles", 0]]