## ----setup, echo=FALSE-------------------------------------------------------- knitr::opts_chunk$set(message=FALSE, fig.path='figures/') hasData <- requireNamespace("asteRiskData", quietly = TRUE) if (!hasData) { evaluateExtraChunks <- FALSE msg <- strwrap("Note: some examples in this vignette require that the `asteRiskData` package be installed. The system currently running this vignette does not have that package installed, so code examples will not be evaluated.") msg <- paste(msg, collapse="\n") message(msg) } else { evaluateExtraChunks <- TRUE library(asteRiskData) } ## ----tidy = TRUE, eval = FALSE------------------------------------------------ # install.packages("asteRisk") ## ----tidy = TRUE, eval = TRUE------------------------------------------------- library(asteRisk) ## ----tidy = TRUE-------------------------------------------------------------- # Read the provided file with 29 benchmark TLE, which contains objects with # a variety of orbital parameters test_TLEs <- readTLE(paste0(path.package("asteRisk"), "/testTLE.txt")) # TLE number 17 contains a state vectors for Italsat 2 test_TLEs[[17]] # It is also possible to directly parse a character vector with 2 or 3 elements, # where each element is a string representing a line of the TLE, to obtain the # same result: italsat2_lines <- c("ITALSAT 2", "1 24208U 96044A 06177.04061740 -.00000094 00000-0 10000-3 0 1600", "2 24208 3.8536 80.0121 0026640 311.0977 48.3000 1.00778054 36119") italsat2_TLE <- parseTLElines(italsat2_lines) italsat2_TLE test_TLEs[[17]]$inclination == italsat2_TLE$inclination ## ----tidy = TRUE-------------------------------------------------------------- # Read the provided test RINEX navigation files for both GPS and GLONASS: testGPSnav <- readGPSNavigationRINEX(paste0(path.package("asteRisk"), "/testGPSRINEX.txt")) testGLONASSnav <- readGLONASSNavigationRINEX(paste0(path.package("asteRisk"), "/testGLONASSRINEX.txt")) # Count the number of positional messages in each file: length(testGPSnav$messages) length(testGLONASSnav$messages) ## ----tidy = TRUE-------------------------------------------------------------- # Element 11 of the set of test TLE contains an orbital state vector for # satellite MOLNIYA 1-83, launched from the USSR in 1992 and decayed in 2007 molniya <- test_TLEs[[11]] 1/molniya$meanMotion # From the inverse of the mean motion, we can see that the orbital period is # approximately half a day, in accordance with a Molniya orbit # Let´s use the SDP4 model to calculate the position and velocity of the # satellite for a full orbital period every 10 minutes. It is important to # provide the mean motion in radians/min, the inclination, anomaly, # argument of perigee and longitude of the ascending node in radians, and # the target time as an increment in minutes for the epoch time targetTimes <- seq(0, 720, by=10) results_position_matrix <- matrix(nrow=length(targetTimes), ncol=3) results_velocity_matrix <- matrix(nrow=length(targetTimes), ncol=3) for(i in 1:length(targetTimes)) { new_result <- sgdp4(n0=molniya$meanMotion*((2*pi)/(1440)), e0=molniya$eccentricity, i0=molniya$inclination*pi/180, M0=molniya$meanAnomaly*pi/180, omega0=molniya$perigeeArgument*pi/180, OMEGA0=molniya$ascension*pi/180, Bstar=molniya$Bstar, initialDateTime=molniya$dateTime, targetTime = targetTimes[i]) results_position_matrix[i,] <- new_result[[1]] results_velocity_matrix[i,] <- new_result[[2]] } last_molniya_propagation <- new_result results_position_matrix = cbind(results_position_matrix, targetTimes) colnames(results_position_matrix) <- c("x", "y", "z", "time") # Let´s verify that the SDP4 algorithm was automatically chosen last_molniya_propagation$algorithm ## ----tidy = TRUE, eval = FALSE------------------------------------------------ # # We can visualize the resulting trajectory using a plotly animation to confirm # # that indeed a full revolution was completed and that the orbit is highly # # eccentric. # # library(plotly) # library(lazyeval) # library(dplyr) # # # In order to create the animation, we must first define a function to create # # the accumulated dataframe required for the animation # # accumulate_by <- function(dat, var) { # var <- f_eval(var, dat) # lvls <- plotly:::getLevels(var) # dats <- lapply(seq_along(lvls), function(x) { # cbind(dat[var %in% lvls[seq(1, x)], ], frame = lvls[[x]]) # }) # bind_rows(dats) # } # # accumulated_df <- accumulate_by(as.data.frame(results_position_matrix), ~time) # # orbit_animation <- plot_ly(accumulated_df, x = ~x, y=~y, z=~z, type = "scatter3d", # mode="marker", opacity=0.8, line=list(width = 6, # color = ~time, # reverscale = FALSE), # frame= ~frame) # # orbit_animation <- animation_opts(orbit_animation, frame=50) # # orbit_animation <- layout(orbit_animation, scene = list( # xaxis=list(range=c(min(results_position_matrix[,1]), max(results_position_matrix[,1]))), # yaxis=list(range=c(min(results_position_matrix[,2]), max(results_position_matrix[,2]))), # zaxis=list(range=c(min(results_position_matrix[,3]), max(results_position_matrix[,3]))) # )) # # orbit_animation ## ----tidy = TRUE, eval = evaluateExtraChunks---------------------------------- # Let us convert the last propagation previously calculated for the MOLNIYA 1-83 # satellite into the ITRF frame. In order to do so, it is required to provide # a date-time string indicating the time for the newly calculated position and # velocity. Since this was 720 minutes after the epoch for the original state # vector, we can just add 12 hours to it molniya$dateTime new_dateTime <- "2006-06-25 12:33:43" ITRF_coordinates <- TEMEtoITRF(last_molniya_propagation$position, last_molniya_propagation$velocity, new_dateTime) # Let us now convert the previously calculated set of TEME coordinates to # geodetic latitude and longitude geodetic_matrix <- matrix(nrow=nrow(results_position_matrix), ncol=3) for(i in 1:nrow(geodetic_matrix)) { new_dateTime <- as.character(as.POSIXct(molniya$dateTime, tz="UTC") + 60*targetTimes[i]) new_geodetic <- TEMEtoLATLON(results_position_matrix[i, 1:3]*1000, new_dateTime) geodetic_matrix[i,] <- new_geodetic } colnames(geodetic_matrix) <- c("latitude", "longitude", "altitude") # We can then visualize the ground track of the satellite library(ggmap) ggmap(get_map(c(left=-180, right=180, bottom=-80, top=80), source = "stamen")) + geom_segment(data=as.data.frame(geodetic_matrix), aes(x=longitude, y=latitude, xend=c(tail(longitude, n=-1), NA), yend=c(tail(latitude, n=-1), NA)), na.rm=TRUE) + geom_point(data=as.data.frame(geodetic_matrix), aes(x=longitude, y=latitude), color="blue", size=0.3, alpha=0.8) ## ----tidy = TRUE, eval = evaluateExtraChunks---------------------------------- # The HPOP requires as input the satellite mass, the effective areas subjected # to solar radiation pressure and atmospheric drag, and the drag and # reflectivity coefficients. # The mass and cross-section of Molniya satellites are approximately 1600 kg and # 15 m2, respectively. We will use the cross-section to approximate the # effective areafor both atmospheric drag and radiation pressure. # Regarding the drag and reflectivity coefficients, while their values vary # for each satellite and orbit, 2.2 and 1.2 respectively can be used as # approximations. molniyaMass <- 1600 molniyaCrossSection <- 15 molniyaCd <- 2.2 molniyaCr <- 1.2 # As initial conditions, we will use the initial conditions provided in the # same TLE for MOLNIYA 1-83 used previously for the SGP4/SDP4 propagator. # We first need to calculate the initial position and velocity in the GCRF # ECI frame of reference from the provided orbital elements. # As an approximation, we will use the results obtained for t = 0 with the # SGP4/SDP4 propagator. We convert those into the GCRF frame of reference. # It should be noted that such an approximation introduces an error due to # a mismatch between the position derivative calculated at each propagation # point through SGP4/SDP4 and the actual velocity of the satellite. GCRF_coordinates <- TEMEtoGCRF(results_position_matrix[1,1:3]*1000, results_velocity_matrix[1,1:3]*1000, molniya$dateTime) initialPosition <- GCRF_coordinates$position initialVelocity <- GCRF_coordinates$velocity # Let´s use the HPOP to calculate the position each 2 minutes during a period # of 3 hours targetTimes <- seq(0, 10800, by=120) hpop_results <- hpop(initialPosition, initialVelocity, molniya$dateTime, targetTimes, molniyaMass, molniyaCrossSection, molniyaCrossSection, molniyaCr, molniyaCd) # Now we can calculate and plot the corresponding geodetic coordinates geodetic_matrix_hpop <- matrix(nrow=nrow(hpop_results), ncol=3) for(i in 1:nrow(geodetic_matrix_hpop)) { new_dateTime <- as.character(as.POSIXct(molniya$dateTime, tz="UTC") + targetTimes[i]) new_geodetic <- GCRFtoLATLON(as.numeric(hpop_results[i, 2:4]), new_dateTime) geodetic_matrix_hpop[i,] <- new_geodetic } colnames(geodetic_matrix_hpop) <- c("latitude", "longitude", "altitude") library(ggmap) ggmap(get_map(c(left=-180, right=180, bottom=-80, top=80), source = "stamen")) + geom_segment(data=as.data.frame(geodetic_matrix_hpop), aes(x=longitude, y=latitude, xend=c(tail(longitude, n=-1), NA), yend=c(tail(latitude, n=-1), NA)), na.rm=TRUE) + geom_point(data=as.data.frame(geodetic_matrix_hpop), aes(x=longitude, y=latitude), color="blue", size=0.3, alpha=0.8)