def ipvPlot3DMoon(self): import ipyvolume as ipv lunarPositions = np.zeros((self.history.datetime.shape[0], 3)) for idx in range(0, self.history.datetime.shape[0]): lunarPositions[idx, :] = models.lunarPositionAlmanac2013( self.history.datetime[idx]) / 1e3 ipv.pylab.plot(lunarPositions[:, 0], lunarPositions[:, 2], lunarPositions[:, 1]) ipv.pylab.scatter(np.array([lunarPositions[-1, 0]]), np.array([lunarPositions[-1, 2]]), np.array([lunarPositions[-1, 1]]), color="gray", marker="sphere")
def plot(self, item, itemHistory=None, **kwargs): useDate = False for key in kwargs: if key == "useDate": useDate = kwargs[key] if item == "coe": # PLOTTING CLASSICAL ORBITAL ELEMENTS titles = ["a", "e", "i", "$\omega$", "$\Omega$", "$\\nu$"] ylabels = ["[km]", "", "[°]", "[°]", "[°]", "[°]"] timeAxis = self.history.datetime if useDate else self.history.t / 60 / 60 / 24 fig, axes = plt.subplots(3, 2, figsize=(10, 8), sharex=True) for i in range(0, 6): for j in range(0, len(self.history.maneuverIdxs) - 1): maneuverSlice = slice(self.history.maneuverIdxs[j], self.history.maneuverIdxs[j + 1]) if i in [2, 3, 4, 5]: axes[int((i - i % 2) / 2), i % 2].plot( timeAxis[maneuverSlice], self.history.coe[maneuverSlice, i] * 180 / np.pi) else: if i == 0: axes[int((i - i % 2) / 2), i % 2].plot( timeAxis[maneuverSlice], self.history.coe[maneuverSlice, i] / 1000) else: axes[int((i - i % 2) / 2), i % 2].plot( timeAxis[maneuverSlice], self.history.coe[maneuverSlice, i]) axes[int((i - i % 2) / 2), i % 2].set_title(titles[i] + " " + ylabels[i]) if useDate: fig.autofmt_xdate() axes[int((i - i % 2) / 2), i % 2].xaxis.set_major_formatter( mdates.DateFormatter('%Y-%m-%d')) else: if i in [4, 5]: axes[int((i - i % 2) / 2), i % 2].set_xlabel("Tiempo [días]") axes[int((i - i % 2) / 2), i % 2].yaxis.get_major_formatter().set_scientific(False) axes[int((i - i % 2) / 2), i % 2].yaxis.get_major_formatter().set_useOffset(False) axes[int((i - i % 2) / 2), i % 2].grid(b=True) if i in [0, 1]: axes[int((i - i % 2) / 2), i % 2].yaxis.get_major_formatter().set_scientific(True) axes[int((i - i % 2) / 2), i % 2].yaxis.get_major_formatter().set_useOffset(True) if item == "secularCoe": # PLOTTING CLASSICAL ORBITAL ELEMENTS titles = ["a", "e", "i", "$\omega$", "$\Omega$", "$\\nu$"] ylabels = ["[km]", "", "[°]", "[°]", "[°]", "[°]"] timeAxis = self.history.datetime if useDate else self.history.tSecular / 60 / 60 / 24 fig, axes = plt.subplots(3, 2, figsize=(10, 8), sharex=True) for i in range(0, 5): if i in [2, 3, 4]: axes[int((i - i % 2) / 2), i % 2].plot( timeAxis, self.history.secularCoe[:, i] * 180 / np.pi) else: if i == 0: axes[int((i - i % 2) / 2), i % 2].plot(timeAxis, self.history.secularCoe[:, i] / 1e3) else: axes[int((i - i % 2) / 2), i % 2].plot(timeAxis, self.history.secularCoe[:, i]) axes[int((i - i % 2) / 2), i % 2].set_title(titles[i] + " " + ylabels[i]) if (useDate): fig.autofmt_xdate() axes[int((i - i % 2) / 2), i % 2].xaxis.set_major_formatter( mdates.DateFormatter('%Y-%m-%d')) axes[int((i - i % 2) / 2), i % 2].yaxis.get_major_formatter().set_scientific(False) axes[int((i - i % 2) / 2), i % 2].yaxis.get_major_formatter().set_useOffset(False) axes[int((i - i % 2) / 2), i % 2].grid(b=True) if item == "3d-trajectory": for key in kwargs: if key == "ax": axExtern = kwargs["ax"] #Plot 3D Trajectory if 'axExtern' not in locals(): fig = plt.figure(figsize=(10, 10)) ax = fig.add_subplot(111, projection='3d') else: ax = axExtern markers = np.zeros([len(self.history.maneuverIdxs) - 1, 3]) for i in range(0, len(self.history.maneuverIdxs) - 1): maneuverSlice = slice(self.history.maneuverIdxs[i], self.history.maneuverIdxs[i + 1]) ax.plot3D(self.history.r[maneuverSlice, 0] / 1000, self.history.r[maneuverSlice, 1] / 1000, self.history.r[maneuverSlice, 2] / 1000, linewidth=1) markers[i, :] = self.history.r[ self.history.maneuverIdxs[i], :] / 1000 ax.plot3D(markers[:, 0], markers[:, 1], markers[:, 2], "k.") if 'axExtern' not in locals(): auxiliary.set_axes_equal(ax) ax.set_aspect("equal") scale_x = 1.2 scale_y = 1.2 scale_z = 1.2 ax.get_proj = lambda: np.dot( Axes3D.get_proj(ax), np.diag( [scale_x, scale_y, scale_z, 1])) figXLim = ax.get_xlim() figYLim = ax.get_ylim() figZLim = ax.get_zlim() xx, yy = np.meshgrid(figXLim, figYLim) z = np.array([[0, 0], [0, 0]]) ax.plot_surface(xx, yy, z, alpha=0.3, color="lightgray") ax.set_title("Satellite Trajectory [km]") ax.set_xlabel("X [km]") ax.set_ylabel("Y [km]") ax.set_zlabel("Z [km]") return ax if item == "orbitalEnergy": fig, ax = plt.subplots(figsize=(10, 4)) moonDistances = np.array([]) for num, date in enumerate(self.history.datetime): moonVector = models.lunarPositionAlmanac2013(date) moonDistances = np.append( moonDistances, np.linalg.norm(moonVector - self.history.r[num])) earthEnergy = np.linalg.norm( self.history.v, axis=1 )**2 / 2 - constants.mu_E / np.linalg.norm(self.history.r, axis=1) moonEnergy = np.linalg.norm( self.history.v, axis=1)**2 / 2 - constants.mu_M / moonDistances ax.plot(self.history.datetime, earthEnergy, label="Earth Energy") ax.plot(self.history.datetime, moonEnergy, label="Moon Energy") fig.legend() fig.autofmt_xdate() ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d')) plt.grid() #fig, ax = plt.subplots(figsize=(10,4)) #ax.plot(self.history.datetime,moonDistances); if item == "energyUsage": timeAxis = self.history.datetime if useDate else self.history.t / 60 / 60 / 24 fig, ax = plt.subplots(figsize=(10, 4)) PSolarPanels = np.diff( self.history.energy["solar panels"]) / np.diff(self.history.t) PThruster = np.diff(self.history.energy["thruster"]) / np.diff( self.history.t) POtherDevices = np.ones((len(self.history.t))) * ( self.spacecraft.solarPanels.nominalPower) * 0.6 EBattery = self.history.energy["battery"] / 60 / 60 ax.plot(timeAxis[:-1], PSolarPanels, linewidth=1, label="Potencia Paneles Solares") ax.plot(timeAxis[:-1], PThruster, linewidth=1, label="Potencia Propulsor") ax.plot(timeAxis, POtherDevices, linewidth=1, label="Potencia Otros Dispositivos") ax.set_ylabel("Potencia [W]") #ax.set_ylim([-1,2]) if useDate: fig.autofmt_xdate() ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d')) else: ax.set_xlabel("Tiempo [días]") ax.yaxis.set_major_formatter(mticker.ScalarFormatter()) ax.yaxis.get_major_formatter().set_scientific(False) ax.yaxis.get_major_formatter().set_useOffset(False) ax2 = ax.twinx() ax2.plot(timeAxis, EBattery, linewidth=1, label="Energía Baterías", color="purple") ax2.set_ylabel("Energía [Wh]") h1, l1 = ax.get_legend_handles_labels() h2, l2 = ax2.get_legend_handles_labels() ax2.legend(h1 + h2, l1 + l2) ax2.set_ylim([-2, self.spacecraft.battery.energy + 2]) ax2.grid() #ax2.set_ylim([-.5,.5]) if item == "singleItem": timeAxis = self.history.datetime if useDate else self.history.t / 60 / 60 / 24 if np.isscalar(itemHistory) and itemHistory == None: raise Exception("History Data not specified.") else: fig, ax = plt.subplots(figsize=(10, 4)) for i in range(0, len(self.history.maneuverIdxs) - 1): maneuverSlice = slice(self.history.maneuverIdxs[i], self.history.maneuverIdxs[i + 1]) ax.plot(timeAxis[maneuverSlice], itemHistory[maneuverSlice], linewidth=1) if useDate: fig.autofmt_xdate() ax.xaxis.set_major_formatter( mdates.DateFormatter('%Y-%m-%d')) ax.yaxis.set_major_formatter(mticker.ScalarFormatter()) ax.yaxis.get_major_formatter().set_scientific(False) ax.yaxis.get_major_formatter().set_useOffset(False) else: ax.set_xlabel("Time [days]") plt.grid() mplcursors.cursor(hover=True)
def calculatePerturbations(self, t, r, v, propMass): p = [0, 0, 0] if self._PERTURBATION_ATMDRAG_: z = np.linalg.norm(r) - constants.Re #Atmospheric Drag vrel = v - np.cross(constants.wE, r) rho = models.USSA76(z) #rhoMin, rhoMax = models.HarrisPriester(z) #rho = rhoMax #rho = models.MSISE90(z,"mean") #rhoMin = models.MSISE90(z,"low") #rhoMax = models.MSISE90(z,"high") #rho = models.mixAtmosphericModels(self.history.datetime[0]+timedelta(seconds=t),rhoMin,rhoMax) Fd = -0.5 * rho * np.linalg.norm(vrel) * vrel * ( 1 / self.spacecraft.BC(self.spacecraft.dryMass + propMass)) p = p + Fd if self._PERTURBATION_J2_: J2 = 0.00108263 zz = r[2] rNorm = np.linalg.norm(r) bigTerm = np.array([ 1 / rNorm * (5 * zz**2 / rNorm**2 - 1), 1 / rNorm * (5 * zz**2 / rNorm**2 - 1), 1 / rNorm * (5 * zz**2 / rNorm**2 - 3) ]) #J2 Gravity Gradient FJ2 = ( 3 / 2 ) * J2 * constants.mu_E * constants.Re**2 / rNorm**4 * bigTerm * r p = p + FJ2 if self._PERTURBATION_SOLARPRESS_: #u-hat vector pointing from Sun to Earth and Sun position vector uhat, rS = models.solarPosition(self.history.datetime[0] + timedelta(seconds=t)) #Solar Radiation Pressure PSR = 4.56e-6 #Absorbing Area As = self.spacecraft.area #Shadow function rSNorm = np.linalg.norm(rS) rNorm = np.linalg.norm(r) theta = np.arccos(np.dot(rS, r) / (rSNorm * rNorm)) theta1 = np.arccos(constants.Re / rNorm) theta2 = np.arccos(constants.Re / rSNorm) if (theta1 + theta2 > theta): nu = 1 else: nu = 0 #Radiation Pressure Coefficient (lies between 1 and 2) Cr = self.spacecraft.Cr #Spacecraft mass mass = self.spacecraft.dryMass + propMass #Radiation Pressure acceleration FR = -nu * PSR * Cr * As / mass * uhat p = p + FR if self._PERTURBATION_MOON_: r_m = models.lunarPositionAlmanac2013(self.history.datetime[0] + timedelta(seconds=t)) r_ms = r_m - r #pMoon = constants.mu_M*(r_ms/np.linalg.norm(r_ms)**3-r_m/np.linalg.norm(r_m)**3) #F(q) formula from F.3 Appendix Curtis 2013 # c = b - a; a << b # F = 1 - c**3/b**2 qq = np.dot(r, (2 * r_m - r)) / np.linalg.norm(r_m)**2 Fq = (qq**2 - 3 * qq + 3) * qq / (1 + (1 - qq)**(3 / 2)) pMoon = constants.mu_M / np.linalg.norm(r_ms)**3 * (Fq * r_m - r) p = p + pMoon if self._PERTURBATION_SUN_: uhat, r_s = models.solarPosition(self.history.datetime[0] + timedelta(seconds=t)) r_sunSat = r_s - r #F(q) formula from F.3 Appendix Curtis 2013 # c = b - a; a << b # F = 1 - c**3/b**2 qq = np.dot(r, (2 * r_s - r)) / np.linalg.norm(r_s)**2 Fq = (qq**2 - 3 * qq + 3) * qq / (1 + (1 - qq)**(3 / 2)) pSun = constants.mu_S / np.linalg.norm(r_sunSat)**3 * (Fq * r_s - r) p = p + pSun return p