def _retrieve_result(self, altitude_cm): """Calls NRLMSISE library's main function""" if self.last_alt == altitude_cm: return self.inp.alt = altitude_cm / 1e5 gtd7(self.inp, self.flags, self.output) self.last_alt = altitude_cm
def calculateDragAcceleration(stateVec, ecpoh, satMass): """ Calculate the acceleration due to atmospheric draf acting on the satellite at a given state (3 positions and 3 velocities) and epoch. Use NRLMSISE2000 atmospheric model with globally defined solar activity proxies: F10_7A - 81-day average F10.7. F10_7 - daily F10.7 for the previous day. MagneticIndex - daily magnetic index AP. NRLMSISEaph - nrlmsise_00_header.ap_array with magnetic values.# Arguments ---------- numpy.ndarray of shape (1,6) with three Cartesian positions and three velocities in an inertial reference frame in metres and metres per second, respectively. epoch - float corresponding to the epoch at which the rate of change is to be computed. Returns ---------- numpy.ndarray of shape (1,3) with three Cartesian components of the acceleration in m/s2 given in an inertial reference frame. """ # " Prepare the atmospheric density model inputs. " # #TODO - calculate the altitude, latitude, longitude altitude_km = numpy.linalg.norm( stateVec[:3] ) / 1000.0 #TODO this isn't altitude in km, but radius in km. Is this OK? NRLMSISEinput = nrlmsise_00_header.nrlmsise_input(year=0, doy=0, sec=0.0, alt=altitude_km, g_lat=0.0, g_long=0.0, lst=0.0, f107A=F10_7A, f107=F10_7, ap=MagneticIndex, ap_a=NRLMSISEaph) nrlmsise_00_header.lstCalc( NRLMSISEinput) # Calculate the local solar time. " Use the calculated atmospheric density to compute the drag force. " NRLMSISEoutpt = nrlmsise_00_header.nrlmsise_output() nrlmsise_00.gtd7(NRLMSISEinput, NRLMSISEflags, NRLMSISEoutpt) atmosphericDensity = NRLMSISEoutpt.d[ 5] / 1000.0 # Change from gm/cm3 to kg/m3 dragForce = -0.5 * atmosphericDensity * dragArea * Cd * numpy.power( stateVec[3:], 2) # Drag foce in Newtons. return dragForce / satMass
def get_density(self, altitude_cm): self.input.alt = altitude_cm / 1e5 gtd7(self.input, self.flags, self.output) return self.output.d[5]
def NRLMSISE_00(pos, time, pos_type='eci'): ''' Courtesy of Ellie Sansom ''' """ Inputs: inertial position and time Outputs: [altitude, temp, atm_pres, atm density, sos, dyn_vis] """ from nrlmsise_00_header import nrlmsise_input, nrlmsise_output, nrlmsise_flags from nrlmsise_00 import gtd7 time = Time(time, format='jd', scale='utc') # Convert ECI to LLH coordinates if pos_type == 'eci': Pos_LLH = ECEF2LLH(ECI2ECEF_pos(pos, time)) elif pos_type == 'ecef': Pos_LLH = ECEF2LLH(pos) elif pos_type == 'llh': Pos_LLH = pos else: print('NRLMSISE_00 error: Invalid pos_type') exit() g_lat = np.rad2deg(Pos_LLH[0][0]) g_long = np.rad2deg(Pos_LLH[1][0]) alt = Pos_LLH[2][0] # Break up time into year, day of year, and seconds of the day yDay = time.yday.split(':') yr = float(yDay[0]) doy = float(yDay[1]) sec = float(yDay[2]) * 60 * 60 + float(yDay[3]) * 60 + float(yDay[4]) # Assign our variables into the nrmsise inputs Input = nrlmsise_input(yr, doy, sec, alt / 1000, g_lat, g_long) Output = nrlmsise_output() Flags = nrlmsise_flags() # Switches for i in range(1, 24): Flags.switches[i] = 1 # GTD7 atmospheric model subroutine gtd7(Input, Flags, Output) # Temperature at alt [deg K] T = Output.t[1] # Molecular number densities [m-3] He = Output.d[0] # He O = Output.d[1] # O N2 = Output.d[2] # N2 O2 = Output.d[3] # O2 Ar = Output.d[4] # Ar H = Output.d[6] # H N = Output.d[7] # N # ano_O = Output.d[8] # Anomalous oxygen sum_mass = He + O + N2 + O2 + Ar + H + N # Molar mass He_mass = 4.0026 # g/mol O_mass = 15.9994 # g/mol N2_mass = 28.013 # g/mol O2_mass = 31.998 # g/mol Ar_mass = 39.948 # g/mol H_mass = 1.0079 # g/mol N_mass = 14.0067 # g/mol # Molecular weight of air [kg/mol] mol_mass_air = (He_mass * He + O_mass * O + N2_mass * N2 + O2_mass * O2 + Ar_mass * Ar + H_mass * H + N_mass * N) / (1000 * sum_mass) # Total mass density [kg*m-3] po = Output.d[5] * 1000 Ru = 8.3144621 # Universal gas constant [J/(K*mol)] R = Ru / mol_mass_air # Individual gas constant [J/(kg*K)] #287.058 # Ideal gas law atm_pres = po * T * R # Speed of sound in atm sos = 331.3 * np.sqrt(1 + T / 273.15) # Dynamic viscosity (http://en.wikipedia.org/wiki/Viscosity) C = 120 #Sutherland's constant for air [deg K] mu_ref = 18.27e-6 # Reference viscosity [[mu_Pa s] * e-6] T_ref = 291.15 # Reference temperature [deg K] dyn_vis = mu_ref * (T_ref + C) / (T + C) * (T / T_ref)**1.5 return T, atm_pres, po, sos, dyn_vis
def __init__(self, h, doy=172, year=0, sec=29000, g_lat=60, g_long=120, lst=16, f107A=150, f107=150, ap=4): # Cantera Solution object self.gas = ct.Solution('air.xml') # Discretised altitude steps self.h = h # Average molecular diameter of gas self.d = 4E-10 self.steps = len(h) self.output = [nrl_head.nrlmsise_output() for _ in range(self.steps)] self.input = [nrl_head.nrlmsise_input() for _ in range(self.steps)] self.flags = nrl_head.nrlmsise_flags() self.aph = nrl_head.ap_array() # Set magnetic values array for index in range(7): self.aph.a[index] = 100 # Output in metres (as opposed to centimetres) self.flags.switches[0] = 0 # Set other flags to TRUE (see docstring of nrlmsise_00_header.py) for index in range(24): self.flags.switches[index] = 1 for index in range(self.steps): self.input[index].doy = doy self.input[index].year = year self.input[index].sec = sec self.input[index].alt = self.h[index] / 1000 self.input[index].g_lat = g_lat self.input[index].g_long = g_long self.input[index].lst = lst self.input[index].f107A = f107A self.input[index].f107 = f107 self.input[index].ap = ap #self.input[index].ap_a = self.aph # Run NRLMSISE00 model for index in range(self.steps): nrlmsise.gtd7(self.input[index], self.flags, self.output[index]) # Pre-allocate memory self.rho = np.zeros(self.steps) self.T = np.zeros(self.steps) self.a = np.zeros(self.steps) self.k = np.zeros(self.steps) self.mu = np.zeros(self.steps) self.cp = np.zeros(self.steps) self.cv = np.zeros(self.steps) # Extract density and temperature for index in range(self.steps): self.rho[index] = self.output[index].d[5] self.T[index] = self.output[index].t[1] # Query Cantera for gas state for index, alt in enumerate(self.h): self.gas.TD = self.T[index], self.rho[index] self.cp[index] = self.gas.cp self.cv[index] = self.gas.cv self.mu[index] = self.gas.viscosity # Perfect gas constant for air (J/kgK) self.R = self.cp - self.cv # Ratio of specific heats (J/kgK) self.k = self.cp / self.cv # Pressure and speed of sound self.p = self.rho * self.T * self.R self.a = fcl.speed_of_sound(self.k, self.R, self.T) print 'ATMOSPHERIC MODEL COMPUTED (NRLMSISE00)' return None