UNPKG

s2-tools

Version:

A collection of geospatial tools primarily designed for WGS84, Web Mercator, and S2.

380 lines 12 kB
import { earthRadius, j2, j3oj2, pi, twoPi, vkmpersec, x2o3, xke } from '../util/constants'; import { dpper } from './dpper'; import { dspace } from './dspace'; /** * procedure sgp4 * * this procedure is the sgp4 prediction model from space command. this is an * updated and combined version of sgp4 and sdp4, which were originally * published separately in spacetrack report //3. this version follows the * methodology from the aiaa paper (2006) describing the history and * development of the code. * * author : david vallado 719-573-2600 28 jun 2005 * * inputs : * tle - initialised structure from sgp4init() call. * tsince - time since epoch (minutes) * * outputs : * r - position vector km * v - velocity km/sec * return code - non-zero on error. * 1 - mean elements, ecc >= 1.0 or ecc < -0.001 or a < 0.95 er * 2 - mean motion less than 0.0 * 3 - pert elements, ecc < 0.0 or ecc > 1.0 * 4 - semi-latus rectum < 0.0 * 5 - epoch elements are sub-orbital * 6 - satellite has decayed * * locals : * am - * axnl, aynl - * betal - * cosim , sinim , cosomm , sinomm , cnod , snod , cos2u , * sin2u , coseo1 , sineo1 , cosi , sini , cosip , sinip , * cosisq , cossu , sinsu , cosu , sinu * delm - * delomg - * dndt - * eccm - * emsq - * ecose - * el2 - * eo1 - * eccp - * esine - * argpm - * argpp - * omgadf - * pl - * r - * rtemsq - * rdotl - * rl - * rvdot - * rvdotl - * su - * t2 , t3 , t4 , tc * tem5, temp , temp1 , temp2 , tempa , tempe , templ * u , ux , uy , uz , vx , vy , vz * inclm - inclination * mm - mean anomaly * nm - mean motion * nodem - right asc of ascending node * xinc - * xincp - * xl - * xlm - * mp - * xmdf - * xmx - * xmy - * nodedf - * xnode - * nodep - * np - * * coupling : * getgravconst- * dpper * dspace * * references : * hoots, roehrich, norad spacetrack report //3 1980 * hoots, norad spacetrack report //6 1986 * hoots, schumacher and glover 2004 * vallado, crawford, hujsak, kelso 2006 * @param sat - the satellite object to propagate * @param tsince - the time since the epoch * @returns - the position and velocity of the satellite or an error report */ export function sgp4(sat, tsince) { const { anomaly, motion, eccentricity, inclination, method, drag, mdot, perigee, argpdot, ascension, nodedot, nodecf, cc1, cc4, cc5, t2cof, isimp, omgcof, eta, xmcof, delmo, d2, d3, d4, sinmao, t3cof, t4cof, t5cof, irez, d2201, d2211, d3210, d3222, d4410, d4422, d5220, d5232, d5421, d5433, dedt, del1, del2, del3, didt, dmdt, dnodt, domdt, opsmode, gsto, xfact, xlamo, atime, xli, xni, } = sat; let { aycof, xlcof, con41, x1mth2, x7thm1 } = sat; let coseo1 = 0; let sineo1 = 0; let cosip; let sinip; let cosisq; let delm; let delomg; let eo1; let argpm; let argpp; let su; let t3; let t4; let tc; let tem5; let temp; let tempa; let tempe; let templ; let inclm; let mm; let nm; let nodem; let xincp; let xlm; let mp; let nodep; /* ------------------ set mathematical constants --------------- */ // sgp4fix divisor for divide by zero check on inclination // the old check used 1.0 + cos(pi-1.0e-9), but then compared it to // 1.5 e-12, so the threshold was changed to 1.5e-12 for consistency const temp4 = 1.5e-12; // ------- update for secular gravity and atmospheric drag ----- const xmdf = anomaly + mdot * tsince; const argpdf = perigee + argpdot * tsince; const nodedf = ascension + nodedot * tsince; argpm = argpdf; mm = xmdf; const t2 = tsince * tsince; nodem = nodedf + nodecf * t2; tempa = 1.0 - cc1 * tsince; tempe = drag * cc4 * tsince; templ = t2cof * t2; if (isimp !== 1) { delomg = omgcof * tsince; // sgp4fix use mutliply for speed instead of pow const delmtemp = 1.0 + eta * Math.cos(xmdf); delm = xmcof * (delmtemp * delmtemp * delmtemp - delmo); temp = delomg + delm; mm = xmdf + temp; argpm = argpdf - temp; t3 = t2 * tsince; t4 = t3 * tsince; tempa = tempa - d2 * t2 - d3 * t3 - d4 * t4; tempe += drag * cc5 * (Math.sin(mm) - sinmao); templ = templ + t3cof * t3 + t4 * (t4cof + tsince * t5cof); } nm = motion; let em = eccentricity; inclm = inclination; if (method === 'd') { tc = tsince; const dspaceOptions = { irez, d2201, d2211, d3210, d3222, d4410, d4422, d5220, d5232, d5421, d5433, dedt, del1, del2, del3, didt, dmdt, dnodt, domdt, argpo: perigee, argpdot, tc, gsto, xfact, xlamo, no: motion, atime, em, argpm, inclm, xli, mm, xni, nodem, nm, }; const dspaceResult = dspace(dspaceOptions, tsince); ({ em, argpm, inclm, mm, nodem, nm } = dspaceResult); } if (nm <= 0.0) { // sgp4fix add return return { type: 2, error: `error nm ${nm}`, }; } const am = (xke / nm) ** x2o3 * tempa * tempa; nm = xke / am ** 1.5; em -= tempe; // fix tolerance for error recognition // sgp4fix am is fixed from the previous nm check if (em >= 1.0 || em < -0.001) { // || (am < 0.95) // sgp4fix to return if there is an error in eccentricity return { type: 1, error: `error em ${em}`, }; } // sgp4fix fix tolerance to avoid a divide by zero if (em < 1.0e-6) { em = 1.0e-6; } mm += motion * templ; xlm = mm + argpm + nodem; nodem %= twoPi; argpm %= twoPi; xlm %= twoPi; mm = (xlm - argpm - nodem) % twoPi; // ----------------- compute extra mean quantities ------------- const sinim = Math.sin(inclm); const cosim = Math.cos(inclm); // -------------------- add lunar-solar periodics -------------- let ep = em; xincp = inclm; argpp = argpm; nodep = nodem; mp = mm; sinip = sinim; cosip = cosim; if (method === 'd') { const dpperParameters = { init: false, ep, inclp: xincp, nodep, argpp, mp, opsmode, }; const dpperResult = dpper(sat, dpperParameters, tsince); ({ ep, nodep, argpp, mp } = dpperResult); xincp = dpperResult.inclp; if (xincp < 0.0) { xincp = -xincp; nodep += pi; argpp -= pi; } if (ep < 0.0 || ep > 1.0) { // sgp4fix add return return { type: 3, error: `error ep ${ep}`, }; } } // -------------------- long period periodics ------------------ if (method === 'd') { sinip = Math.sin(xincp); cosip = Math.cos(xincp); aycof = -0.5 * j3oj2 * sinip; // sgp4fix for divide by zero for xincp = 180 deg if (Math.abs(cosip + 1.0) > 1.5e-12) { xlcof = (-0.25 * j3oj2 * sinip * (3.0 + 5.0 * cosip)) / (1.0 + cosip); } else { xlcof = (-0.25 * j3oj2 * sinip * (3.0 + 5.0 * cosip)) / temp4; } } const axnl = ep * Math.cos(argpp); temp = 1.0 / (am * (1.0 - ep * ep)); const aynl = ep * Math.sin(argpp) + temp * aycof; const xl = mp + argpp + nodep + temp * xlcof * axnl; // --------------------- solve kepler's equation --------------- const u = (xl - nodep) % twoPi; eo1 = u; tem5 = 9999.9; let ktr = 1; // sgp4fix for kepler iteration // the following iteration needs better limits on corrections while (Math.abs(tem5) >= 1.0e-12 && ktr <= 10) { sineo1 = Math.sin(eo1); coseo1 = Math.cos(eo1); tem5 = 1.0 - coseo1 * axnl - sineo1 * aynl; tem5 = (u - aynl * coseo1 + axnl * sineo1 - eo1) / tem5; if (Math.abs(tem5) >= 0.95) { if (tem5 > 0.0) { tem5 = 0.95; } else { tem5 = -0.95; } } eo1 += tem5; ktr += 1; } // ------------- short period preliminary quantities ----------- const ecose = axnl * coseo1 + aynl * sineo1; const esine = axnl * sineo1 - aynl * coseo1; const el2 = axnl * axnl + aynl * aynl; const pl = am * (1.0 - el2); if (pl < 0.0) { // sgp4fix add return return { type: 4, error: `error pl ${pl}`, }; } const rl = am * (1.0 - ecose); const rdotl = (Math.sqrt(am) * esine) / rl; const rvdotl = Math.sqrt(pl) / rl; const betal = Math.sqrt(1.0 - el2); temp = esine / (1.0 + betal); const sinu = (am / rl) * (sineo1 - aynl - axnl * temp); const cosu = (am / rl) * (coseo1 - axnl + aynl * temp); su = Math.atan2(sinu, cosu); const sin2u = (cosu + cosu) * sinu; const cos2u = 1.0 - 2.0 * sinu * sinu; temp = 1.0 / pl; const temp1 = 0.5 * j2 * temp; const temp2 = temp1 * temp; // -------------- update for short period periodics ------------ if (method === 'd') { cosisq = cosip * cosip; con41 = 3.0 * cosisq - 1.0; x1mth2 = 1.0 - cosisq; x7thm1 = 7.0 * cosisq - 1.0; } const mrt = rl * (1.0 - 1.5 * temp2 * betal * con41) + 0.5 * temp1 * x1mth2 * cos2u; // sgp4fix for decaying satellites if (mrt < 1.0) { return { type: 6, error: `decay condition ${mrt}`, }; } su -= 0.25 * temp2 * x7thm1 * sin2u; const xnode = nodep + 1.5 * temp2 * cosip * sin2u; const xinc = xincp + 1.5 * temp2 * cosip * sinip * cos2u; const mvt = rdotl - (nm * temp1 * x1mth2 * sin2u) / xke; const rvdot = rvdotl + (nm * temp1 * (x1mth2 * cos2u + 1.5 * con41)) / xke; // --------------------- orientation vectors ------------------- const sinsu = Math.sin(su); const cossu = Math.cos(su); const snod = Math.sin(xnode); const cnod = Math.cos(xnode); const sini = Math.sin(xinc); const cosi = Math.cos(xinc); const xmx = -snod * cosi; const xmy = cnod * cosi; const ux = xmx * sinsu + cnod * cossu; const uy = xmy * sinsu + snod * cossu; const uz = sini * sinsu; const vx = xmx * cossu - cnod * sinsu; const vy = xmy * cossu - snod * sinsu; const vz = sini * cossu; // --------- position and velocity (in km and km/sec) ---------- const r = { x: mrt * ux * earthRadius, y: mrt * uy * earthRadius, z: mrt * uz * earthRadius, }; const v = { x: (mvt * ux + rvdot * vx) * vkmpersec, y: (mvt * uy + rvdot * vy) * vkmpersec, z: (mvt * uz + rvdot * vz) * vkmpersec, }; return { position: r, velocity: v, }; } //# sourceMappingURL=sgp4.js.map