From 93f4e3e81d16907bc039c7e50fb4ff53f8148263 Mon Sep 17 00:00:00 2001 From: lukasadrion Date: Wed, 21 Jan 2026 00:21:50 +0100 Subject: [PATCH] :memo: add more documentation --- src/main.Rmd | 204 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 142 insertions(+), 62 deletions(-) diff --git a/src/main.Rmd b/src/main.Rmd index 823e4fb..d1dfb3d 100644 --- a/src/main.Rmd +++ b/src/main.Rmd @@ -1,5 +1,6 @@ --- title: "Topic 8 - Flight Trajectory Analysis" +subtitle: "Erik Neller, Patrik Mišura, Lukas Adrion" output: pdf_document: default html_document: default @@ -308,25 +309,74 @@ generateInterpretation <- function(trajectory_stats_df) { } ``` -# Example Usage (Documentation) -This section demonstrates how to use all functions defined above. Each step is explained and executed with real flight data from Frankfurt Airport (EDDF). +# Abstract -## Step 1: Load Credentials +This project implements an R-based application for the retrieval, processing, and statistical analysis of aircraft trajectories. Flight data is obtained from the OpenSky Network API, transformed into analyzable trajectory objects using the `trajr` package, and subsequently characterized using established movement ecology metrics. The methodology enables quantitative comparison of flight paths through parameters such as path length, straightness index, and fractal dimension. -The `getCredentials()` function loads API credentials from environment variables. +# Introduction + +## Background + +The analysis of movement trajectories constitutes a fundamental aspect of spatial data science, with applications ranging from animal behavior studies to transportation network optimization. In the context of aviation, trajectory analysis provides insights into flight efficiency, airspace utilization, and routing patterns. + +## Objectives + +The primary objectives of this project are: + +1. **Data Acquisition**: Implement robust methods for retrieving real-time flight trajectory data from the OpenSky Network +2. **Trajectory Characterization**: Apply established metrics from movement ecology to quantify flight path properties +3. **Statistical Analysis**: Perform comparative analysis across multiple flights to identify patterns and distributions + +## Theoretical Framework + +The `trajr` package, originally developed for animal movement analysis, provides a comprehensive toolkit for trajectory characterization. Key metrics employed in this analysis include: + +- **Path Length**: Total distance traveled along the trajectory +- **Diffusion Distance**: Euclidean displacement from origin to destination +- **Straightness Index**: Ratio of diffusion distance to path length (range 0-1) +- **Fractal Dimension**: Measure of path complexity (1 = straight line, approaching 2 = space-filling curve) + +# Methodology + +## Data Source + +Flight trajectory data is obtained from the OpenSky Network, a community-based receiver network providing open access to air traffic surveillance data. The API provides: + +- Aircraft state vectors (position, velocity, heading) +- Historical flight tracks +- Airport departure and arrival information + +## Data Processing Pipeline + +The analysis workflow consists of the following stages: + +1. **Authentication**: Establish connection to OpenSky API using credentials +2. **Query Execution**: Retrieve departure information for specified airport and time window +3. **Track Retrieval**: Obtain detailed waypoint data for individual flights +4. **Coordinate Transformation**: Convert geographic coordinates to metric distances +5. **Trajectory Construction**: Create `trajr` trajectory objects for analysis +6. **Statistical Computation**: Calculate trajectory metrics and aggregate statistics + +# Implementation + +The following section will demonstrate the implementation of the methodology using R code snippets. +The full analysis is also available in the GUI-based Shiny application. + +## Step 1: API Authentication + +The `getCredentials()` function retrieves API credentials from environment variables, ensuring secure credential management. ```r creds <- getCredentials( client_id = Sys.getenv("OPENSKY_CLIENT_ID"), client_secret = Sys.getenv("OPENSKY_CLIENT_SECRET") ) - ``` -## Step 2: Fetch Airport Departures +## Step 2: Data Acquisition -Use `getAirportDepartures()` to get recent departures from Frankfurt Airport. +Recent departures from Frankfurt Airport (ICAO: EDDF) are queried for a two-hour time window. This airport was selected due to its high traffic volume, ensuring sufficient data availability. ```{r demo-departures} time_now <- Sys.time() @@ -336,12 +386,12 @@ departures <- getAirportDepartures( endTime = time_now - hours(1), credentials = creds ) -cat("Found", length(departures), "departures from Frankfurt Airport (EDDF)\n") +cat("Departures retrieved:", length(departures), "\n") ``` -## Step 3: Retrieve Flight Track +## Step 3: Track Data Retrieval -The `getAircraftTrack()` function fetches detailed track data for a specific aircraft. We use the first available departure. +The `getAircraftTrack()` function retrieves detailed waypoint data for individual aircraft. The function iterates through available departures until valid track data is obtained. ```{r demo-track} route_df <- NULL @@ -353,88 +403,89 @@ if (length(departures) > 0) { dep_time <- departures[[i]][["departure_time"]] route_df <- getAircraftTrack(icao, dep_time, creds) if (!is.null(route_df) && nrow(route_df) >= 3) { - cat("Successfully retrieved track for aircraft:", icao, "\n") - cat("Number of track points:", nrow(route_df), "\n") + cat("Aircraft ICAO24:", icao, "\n") + cat("Track points acquired:", nrow(route_df), "\n") break } } } if (is.null(route_df)) { - cat("No valid track data found\n") + cat("No valid track data available\n") } ``` -## Step 4: Visualize Geographic Route +## Step 4: Spatial Visualization -Plot the flight path on a simple lat/lon coordinate system. +The geographic trajectory is visualized in a Cartesian coordinate system. Green and red markers indicate departure and current/final position, respectively. ```{r demo-route-plot, fig.width=7, fig.height=5} if (!is.null(route_df)) { plot(route_df$lon, route_df$lat, type = "o", pch = 20, col = "blue", - main = paste("Geographic Route of Aircraft", icao), - xlab = "Longitude", ylab = "Latitude") + main = paste("Flight Trajectory -", icao), + xlab = "Longitude (°)", ylab = "Latitude (°)") points(route_df$lon[1], route_df$lat[1], pch = 17, col = "green", cex = 2) points(route_df$lon[nrow(route_df)], route_df$lat[nrow(route_df)], pch = 15, col = "red", cex = 2) - legend("topright", legend = c("Start", "End", "Path"), pch = c(17, 15, 20), col = c("green", "red", "blue")) + legend("topright", legend = c("Origin", "Destination", "Trajectory"), + pch = c(17, 15, 20), col = c("green", "red", "blue")) } else { - cat("No route data available for plotting\n") + cat("Insufficient data for visualization\n") } ``` -## Step 5: Visualize Altitude Profile +## Step 5: Vertical Profile Analysis -Plot the altitude over time to see climb, cruise, and descent phases. +The altitude profile reveals distinct flight phases: climb, cruise, and descent. This temporal representation provides insight into vertical movement patterns. ```{r demo-altitude-plot, fig.width=7, fig.height=4} if (!is.null(route_df)) { time_minutes <- (route_df$time - route_df$time[1]) / 60 plot(time_minutes, route_df$alt, type = "l", col = "red", lwd = 2, - main = paste("Altitude Profile of Aircraft", icao), - xlab = "Time (minutes)", ylab = "Altitude (meters)") + main = paste("Altitude Profile -", icao), + xlab = "Elapsed Time (min)", ylab = "Barometric Altitude (m)") grid() } else { - cat("No route data available for altitude plot\n") + cat("Insufficient data for altitude analysis\n") } ``` -## Step 6: Convert to Trajectory Object +## Step 6: Trajectory Object Construction -The `getTrajFromRoute()` function converts the route into a trajr trajectory object for analysis. +The `getTrajFromRoute()` function transforms geographic coordinates into a metric coordinate system and constructs a `trajr` trajectory object. This transformation is necessary for accurate distance calculations. ```{r demo-trajectory-plot, fig.width=7, fig.height=5} if (!is.null(route_df)) { trj <- getTrajFromRoute(route_df) - plot(trj, main = paste("Trajectory of Aircraft", icao)) - cat("Trajectory created with", nrow(trj), "points\n") + plot(trj, main = paste("Metric Trajectory -", icao)) + cat("Trajectory object created with", nrow(trj), "waypoints\n") } else { - cat("No route data available for trajectory conversion\n") + cat("Insufficient data for trajectory construction\n") } ``` -## Step 7: Calculate Trajectory Statistics (Single Flight) +## Step 7: Single Flight Characterization -The `calculateTrajectoryStats()` function computes key metrics. Use `format = "table"` for a readable display. +The `calculateTrajectoryStats()` function computes comprehensive trajectory metrics. The table format provides a clear overview of individual flight characteristics. ```{r demo-stats-table} if (!is.null(route_df)) { stats_table <- calculateTrajectoryStats(route_df, icao = icao, format = "table") - knitr::kable(stats_table, caption = paste("Trajectory Statistics for", icao)) + knitr::kable(stats_table, caption = paste("Trajectory Metrics for Aircraft", icao)) } else { - cat("No route data available for statistics\n") + cat("Insufficient data for statistical analysis\n") } ``` -## Step 8: Analyze Multiple Flights +## Step 8: Multi-Flight Data Collection -Retrieve track data for up to 5 departures to enable statistical comparison. +To enable statistical inference, trajectory data is collected for multiple flights. The algorithm attempts to retrieve valid track data for up to five departures in this example. ```{r demo-multiple-tracks} flight_data <- list() successful_flights <- 0 if (length(departures) > 0) { - max_attempts <- min(10, length(departures)) # Try up to 10 departures to get 5 valid tracks + max_attempts <- min(10, length(departures)) for (i in seq_len(max_attempts)) { icao_temp <- departures[[i]][["ICAO24"]] @@ -447,7 +498,8 @@ if (length(departures) > 0) { if (!is.null(stats)) { flight_data[[length(flight_data) + 1]] <- stats successful_flights <- successful_flights + 1 - cat("Flight", successful_flights, "- ICAO:", icao_temp, "- Points:", nrow(route_df_temp), "\n") + cat("Flight", successful_flights, "| ICAO:", icao_temp, + "| Waypoints:", nrow(route_df_temp), "\n") } } @@ -456,20 +508,22 @@ if (length(departures) > 0) { if (length(flight_data) > 0) { all_flights_stats <- do.call(rbind, flight_data) - cat("\nTotal flights analyzed:", nrow(all_flights_stats), "\n") + cat("\nSample size (n):", nrow(all_flights_stats), "flights\n") } else { all_flights_stats <- NULL - cat("No valid flight tracks found\n") + cat("No valid trajectories obtained\n") } } else { all_flights_stats <- NULL - cat("No departures available\n") + cat("No departure data available\n") } ``` -## Step 9: Display All Flight Statistics +# Results -Show the raw statistics for all analyzed flights. +## Individual Flight Metrics + +The following table presents computed metrics for all successfully analyzed flights. ```{r demo-all-stats-table} if (!is.null(all_flights_stats)) { @@ -481,73 +535,99 @@ if (!is.null(all_flights_stats)) { display_stats$mean_velocity_kmh <- round(display_stats$mean_velocity_kmh, 1) display_stats$fractal_dimension <- round(display_stats$fractal_dimension, 4) - knitr::kable(display_stats, caption = "Statistics for All Analyzed Flights", - col.names = c("ICAO24", "Distance (km)", "Path (km)", - "Straightness", "Duration (min)", "Velocity (km/h)", "Fractal Dim")) + knitr::kable(display_stats, caption = "Computed Trajectory Metrics", + col.names = c("ICAO24", "Displacement (km)", "Path Length (km)", + "Straightness", "Duration (min)", "Velocity (km/h)", "Fractal Dim.")) } else { - cat("No flight data available\n") + cat("No data available for tabulation\n") } ``` -## Step 10: Summary Statistics +## Descriptive Statistics -The `calculateStatsSummary()` function generates descriptive statistics across multiple flights. +The `calculateStatsSummary()` function computes central tendency and dispersion measures for each trajectory parameter. ```{r demo-summary-stats} if (!is.null(all_flights_stats) && nrow(all_flights_stats) >= 2) { summary_stats <- calculateStatsSummary(all_flights_stats) - knitr::kable(summary_stats, caption = "Summary Statistics Across All Flights") + knitr::kable(summary_stats, caption = "Descriptive Statistics Summary") } else { - cat("Need at least 2 flights for summary statistics\n") + cat("Minimum sample size (n >= 2) not met\n") } ``` -## Step 11: Boxplots +## Distribution Analysis: Boxplots -The `createBoxplots()` function visualizes the distribution of each trajectory parameter. +Boxplots provide a robust visualization of parameter distributions, displaying median, interquartile range, and potential outliers. The red diamond indicates the arithmetic mean. ```{r demo-boxplots, fig.width=10, fig.height=8} if (!is.null(all_flights_stats) && nrow(all_flights_stats) >= 2) { createBoxplots(all_flights_stats) } else { - cat("Need at least 2 flights for boxplots\n") + cat("Minimum sample size (n >= 2) not met\n") } ``` -## Step 12: Density Plots +## Distribution Analysis: Kernel Density Estimation -The `createDensityPlots()` function shows the probability distribution of each parameter. +Density plots employ kernel density estimation to approximate the probability distribution of each parameter. Vertical lines indicate mean (red, dashed) and median (green, dotted). ```{r demo-density, fig.width=10, fig.height=8} if (!is.null(all_flights_stats) && nrow(all_flights_stats) >= 3) { createDensityPlots(all_flights_stats) } else { - cat("Need at least 3 flights for density plots\n") + cat("Minimum sample size (n >= 3) not met for density estimation\n") } ``` -## Step 13: Histograms +## Distribution Analysis: Histograms -The `createHistograms()` function displays histograms with density overlays. +Histograms with overlaid density curves provide an alternative visualization of parameter distributions. ```{r demo-histograms, fig.width=10, fig.height=8} if (!is.null(all_flights_stats) && nrow(all_flights_stats) >= 3) { createHistograms(all_flights_stats) } else { - cat("Need at least 3 flights for histograms\n") + cat("Minimum sample size (n >= 3) not met for histogram analysis\n") } ``` -## Step 14: Interpretation +## Parameter Interpretation -The `generateInterpretation()` function provides a text-based analysis of the trajectory statistics. +The `generateInterpretation()` function provides contextual analysis of the computed trajectory metrics. ```{r demo-interpretation} if (!is.null(all_flights_stats) && nrow(all_flights_stats) >= 2) { interpretation <- generateInterpretation(all_flights_stats) cat(interpretation) } else { - cat("Need at least 2 flights for interpretation\n") + cat("Minimum sample size (n >= 2) not met for interpretation\n") } ``` +# Discussion + +## Key Findings + +The trajectory analysis reveals several characteristics typical of commercial aviation: + +1. **High Straightness Values**: Commercial flights generally exhibit straightness indices approaching 1.0, indicating efficient direct routing between waypoints. + +2. **Low Fractal Dimension**: Values close to 1.0 confirm that flight paths approximate straight lines, consistent with fuel-efficient routing principles. + +3. **Velocity Patterns**: Mean velocities below typical cruise speeds (800-900 km/h) reflect the inclusion of departure and arrival phases in the trajectory data. + +## Limitations + +- **Temporal Resolution**: Track data granularity varies based on ADS-B receiver coverage +- **Sample Size**: Statistical inference is limited by the number of available flights with complete track data + +# Conclusion + +This project demonstrates the successful application of movement ecology metrics to aviation trajectory analysis. The implemented R framework provides a reproducible methodology for flight path characterization and statistical comparison. The `trajr` package proves suitable for aircraft trajectory analysis, offering robust metrics originally developed for biological movement studies. + +# References + +- OpenSky Network: https://opensky-network.org/ +- McLean, D.J. & Skowron Volponi, M.A. (2018). trajr: An R package for characterisation of animal trajectories. Ethology, 124(6), 440-448: https://CRAN.R-project.org/package=trajr +