---
title: "Flight Statistics"
output:
  html_notebook: 
    code_folding: hide
    toc: yes
    number_sections: yes
    toc_float: 
        collapsed: false
---

[Flight Summary](flight_summary.nb.html)

[Flight Analysis](flight_analysis.nb.html)

Data normalized across several flight logs, spanning from `r min(levels(flight_data$Flight))` to `r max(levels(flight_data$Flight))`, excepting NS54, NS55, and NS68 (NS54 is reserved for a flight still in development, and both NS55 and NS68 failed to record location data).

Overall average calculations exclude the following flights due to failure or anomaly: `r average_excluded_flights`.

Sea level descent rate is averaged from descent rate below `r sea_level_descent_rate_threshold` meters.

```{r setup}
require(ggplot2)
require(directlabels)
require(reshape2)
require(scales)

source("setup.R")

flight_times <- read_flight_times("flight_times.txt")
flight_data <- read_flight_data("flight_data/")

average_excluded_flights <- c("NS56", "NS74")
sea_level_descent_rate_threshold = 300
```

# Flight Records

## Maximum Values by Flight

Maximum values for each recorded flight.

```{r maximum_values_by_flight, fig.height=7.4164079, fig.width=12}
maximum_values_by_flight <-
    data.frame(
        Flight = flight_times$Flight,
        Burst_Altitude_m = NA,
        Landing_Distance_m = NA,
        Ascent_Rate_m_s = NA,
        Descent_Rate_m_s = NA,
        Ground_Speed_m_s = NA
    )

for (current_flight in levels(flight_data$Flight))
{
    maximum_values_by_flight[maximum_values_by_flight$Flight == current_flight, 2:6] <- c(
        mean(flight_data[flight_data$DateTime == flight_times[flight_times$Flight == current_flight, "Burst_Time"], "Altitude_m"], na.rm = TRUE),
        mean(flight_data[flight_data$DateTime == flight_times[flight_times$Flight == current_flight, "Landing_Time"], "Downrange_Distance_m"], na.rm = TRUE),
        max(flight_data[flight_data$Flight == current_flight, "Ascent_Rate_m_s"], na.rm = TRUE),
        min(flight_data[flight_data$Flight == current_flight, "Ascent_Rate_m_s"], na.rm = TRUE),
        max(flight_data[flight_data$Flight == current_flight, "Ground_Speed_m_s"], na.rm = TRUE)
    )
}

maximum_values_by_flight[is.na(maximum_values_by_flight)] <- NA

rmarkdown::paged_table(maximum_values_by_flight)

ggplot(melt(maximum_values_by_flight, id.vars = "Flight"),
       aes(
           x = Flight,
           y = value,
           fill = rep_len(
               as.factor(flight_times$Balloon_Mass_kg[flight_times$Flight %in% Flight]),
               length.out = length(Flight)
           )
       )) + geom_col() + facet_grid(variable ~ ., scales = "free_y") +
    theme(
        legend.position = c(1.03, 1.03),
        legend.direction = "horizontal",
        legend.justification = "right",
        axis.title.x = element_blank(),
        axis.title.y = element_blank()
    ) + labs(title = "Maximum Values by Flight", fill = "Balloon Mass (kg)")
```

## Program Records

Maximum values across all recorded flights.

```{r overall_records}
overall_records <-
    data.frame(
        Record = c(
            "Highest Altitude (m)",
            "Farthest Downrange Distance (m)",
            "Fastest Ascent Rate (m/s)",
            "Fastest Descent Rate (m/s)",
            "Fastest Ground Speed (m/s)"
        ),
        Flight = factor(levels = levels(flight_times$Flight), NA),
        Value = numeric(5),
        DateTime = as.POSIXct(numeric(5), origin = "1970-01-01")
    )

overall_records[1, 2:3] <-
    c(as.character(flight_data[flight_data$Altitude_m == max(flight_data$Altitude_m, na.rm = TRUE), "Flight"]), round(max(flight_data$Altitude_m, na.rm = TRUE)))

overall_records[1, 4] <-
    as.POSIXct(flight_data[flight_data$Altitude_m == max(flight_data$Altitude_m, na.rm = TRUE), "DateTime"], tz = Sys.timezone())

overall_records[2, 2:3] <-
    c(as.character(flight_data[flight_data$Downrange_Distance_m == max(flight_data$Downrange_Distance_m, na.rm = TRUE), "Flight"]), round(max(flight_data$Downrange_Distance_m, na.rm = TRUE)))

overall_records[2, 4] <-
    as.POSIXct(flight_data[flight_data$Downrange_Distance_m == max(flight_data$Downrange_Distance_m, na.rm = TRUE), "DateTime"], tz = Sys.timezone())

overall_records[3, 2:3] <-
    c(as.character(flight_data[flight_data$Ascent_Rate_m_s == max(flight_data$Ascent_Rate_m_s, na.rm = TRUE), "Flight"]), round(max(flight_data$Ascent_Rate_m_s, na.rm = TRUE)))

overall_records[3, 4] <-
    as.POSIXct(flight_data[flight_data$Ascent_Rate_m_s == max(flight_data$Ascent_Rate_m_s, na.rm = TRUE), "DateTime"], tz = Sys.timezone())

overall_records[4, 2:3] <-
    c(as.character(flight_data[flight_data$Ascent_Rate_m_s == min(flight_data$Ascent_Rate_m_s, na.rm = TRUE), "Flight"]), round(min(flight_data$Ascent_Rate_m_s, na.rm = TRUE)))

overall_records[4, 4] <-
    as.POSIXct(flight_data[flight_data$Ascent_Rate_m_s == min(flight_data$Ascent_Rate_m_s, na.rm = TRUE), "DateTime"], tz = Sys.timezone())

overall_records[5, 2:3] <-
    c(as.character(flight_data[flight_data$Ground_Speed_m_s == max(flight_data$Ground_Speed_m_s, na.rm = TRUE), "Flight"]), round(max(flight_data$Ground_Speed_m_s, na.rm = TRUE)))

overall_records[5, 4] <-
    as.POSIXct(flight_data[flight_data$Ground_Speed_m_s == max(flight_data$Ground_Speed_m_s, na.rm = TRUE), "DateTime"], tz = Sys.timezone())

rmarkdown::paged_table(overall_records)
```

# Averages

## Overall Averages

```{r overall_averages}
overall_averages <-
    data.frame(
        Statistic = c(
            "Burst Altitude (m)",
            "Landing Distance (m)",
            "Ascent Rate (m/s)",
            "Descent Rate (m/s)",
            "Ground Speed (m/s)",
            "Sea Level Descent Rate (m/s)"
        ),
        Mean = 0
    )

overall_averages[overall_averages$Statistic == "Burst Altitude (m)", "Mean"] <-
    mean(maximum_values_by_flight$Burst_Altitude_m[!(maximum_values_by_flight$Flight %in% average_excluded_flights)], na.rm = TRUE)

overall_averages[overall_averages$Statistic == "Landing Distance (m)", "Mean"] <-
    mean(maximum_values_by_flight$Landing_Distance_m[!(maximum_values_by_flight$Flight %in% average_excluded_flights)], na.rm = TRUE)

overall_averages[overall_averages$Statistic == "Ascent Rate (m/s)", "Mean"] <-
    mean(flight_data$Ascent_Rate_m_s[flight_data$Ascent_Rate_m_s > 0 &
                                         !(flight_data$Flight %in% average_excluded_flights)], na.rm = TRUE)
overall_averages[overall_averages$Statistic == "Descent Rate (m/s)", "Mean"] <-
    mean(flight_data$Ascent_Rate_m_s[flight_data$Ascent_Rate_m_s < 0 &
                                         !(flight_data$Flight %in% average_excluded_flights)], na.rm = TRUE)
overall_averages[overall_averages$Statistic == "Ground Speed (m/s)", "Mean"] <-
    mean(flight_data$Ground_Speed_m_s[!(flight_data$Flight %in% average_excluded_flights)], na.rm = TRUE)

overall_averages[overall_averages$Statistic == "Sea Level Descent Rate (m/s)", "Mean"] <-
    mean(flight_data$Ascent_Rate_m_s[flight_data$Altitude_m < 300 &
                                         flight_data$Ascent_Rate_m_s < 0 &
                                         flight_data$Ground_Speed_m_s > 2 &
                                         !(flight_data$Flight %in% average_excluded_flights)], na.rm = TRUE)

rmarkdown::paged_table(overall_averages)
```
excluding `r average_excluded_flights`

## Averages by Flight

```{r averages_by_flight, fig.height=7.4164079, fig.width=12}
averages_by_flight <-
    data.frame(
        Flight = flight_times$Flight,
        Ascent_Rate_m_s = 0,
        Descent_Rate_m_s = 0,
        Ground_Speed_m_s = 0,
        Sea_Level_Descent_Rate_m_s = 0
    )

for (current_flight in averages_by_flight$Flight)
{
    averages_by_flight[averages_by_flight$Flight == current_flight, 2:5] <-
        c(
            mean(flight_data$Ascent_Rate_m_s[flight_data$Flight == current_flight &
                                                 flight_data$Ascent_Rate_m_s > 0], na.rm = TRUE),
            mean(flight_data$Ascent_Rate_m_s[flight_data$Flight == current_flight &
                                                 flight_data$Ascent_Rate_m_s < 0], na.rm = TRUE),
            mean(flight_data$Ground_Speed_m_s[flight_data$Flight == current_flight], na.rm = TRUE),
            mean(flight_data$Ascent_Rate_m_s[flight_data$Ascent_Rate_m_s < 0 &
                                                flight_data$Altitude_m < sea_level_descent_rate_threshold &
                                                flight_data$Ground_Speed_m_s > 2 &
                                                flight_data$Flight %in% current_flight], na.rm = TRUE)
        )
}

rm(current_flight)

averages_by_flight[is.na(averages_by_flight)] <- NA

rmarkdown::paged_table(averages_by_flight)

ggplot(melt(averages_by_flight,
            id.vars = "Flight"),
       aes(
           x = Flight,
           y = value,
           fill = rep_len(
               as.factor(flight_times$Balloon_Mass_kg[flight_times$Flight %in% Flight]),
               length.out = length(Flight)
           )
       )) +
    geom_col() +
    facet_grid(variable ~ ., scales = "free_y") +
    labs(title = "Averages by Flight", fill = "Balloon Mass (kg)") +
    theme(
        legend.position = c(1.03, 1.03),
        legend.direction = "horizontal",
        legend.justification = "right",
        axis.title.x = element_blank(),
        axis.title.y = element_blank()
    )
```

```{r average_ground_speed_vs_time_of_year, fig.height=7.4164079, fig.width=12}
ggplot(averages_by_flight,
       aes(
           x = as.Date(format(flight_times$Date, format = "%m-%d"), format = "%m-%d"),
           y = Ground_Speed_m_s,
           fill = rep_len(
               as.factor(flight_times$Balloon_Mass_kg[flight_times$Flight %in% Flight]),
               length.out = length(Flight)
           )
       )) +
    geom_col(width = 2, position = "dodge") + 
    geom_point(size = 0.1) +
    scale_x_date(
        date_breaks = "1 month",
        labels = date_format("%b"),
        limits = as.Date(c("01-01", "12-31"), format = "%m-%d"),
        expand = c(0, 0)
    ) +
    geom_dl(aes(label = gsub("NS", "", Flight)),
            method = list(cex = 0.8, dl.trans(y = y + 0.2), "top.bumpup")) +
    labs(title = "Average Ground Speed vs Time of Year",
         x = "Time of Year",
         y = "Average Ground Speed (m/s)",
         fill = "Balloon Mass (kg)") +
    theme(
        legend.position = c(1, 1.03),
        legend.direction = "horizontal",
        legend.justification = "right"
    )
```


## Averages by Balloon Mass

```{r averages_by_balloon_mass, fig.height=7.4164079, fig.width=12}
averages_by_balloon_mass <-
    data.frame(
        Balloon_Mass_kg = unique(flight_times$Balloon_Mass_kg),
        Burst_Altitude_m = 0,
        Landing_Distance_m = 0,
        Ascent_Rate_m_s = 0,
        Descent_Rate_m_s = 0,
        Ground_Speed_m_s = 0,
        Sea_Level_Descent_Rate_m_s = 0
    )


averages_by_balloon_mass <-
    averages_by_balloon_mass[complete.cases(averages_by_balloon_mass$Balloon_Mass_kg),]
averages_by_balloon_mass <-
    averages_by_balloon_mass[order(averages_by_balloon_mass$Balloon_Mass_kg), ]
row.names(averages_by_balloon_mass) <- NULL

for (current_balloon_mass in averages_by_balloon_mass$Balloon_Mass_kg)
{
    current_flights <-
        flight_times[!(flight_times$Flight %in% average_excluded_flights) &
                         flight_times$Balloon_Mass_kg == current_balloon_mass &
                         !is.na(flight_times$Balloon_Mass_kg), "Flight"]
    
    averages_by_balloon_mass[averages_by_balloon_mass$Balloon_Mass_kg == current_balloon_mass, 2:7] <-
        c(
            mean(maximum_values_by_flight$Burst_Altitude_m[maximum_values_by_flight$Flight %in% current_flights], na.rm = TRUE),
            mean(maximum_values_by_flight$Landing_Distance_m[maximum_values_by_flight$Flight %in% current_flights], na.rm = TRUE),
            mean(averages_by_flight$Ascent_Rate_m_s[averages_by_flight$Flight %in% current_flights], na.rm = TRUE),
            mean(averages_by_flight$Descent_Rate_m_s[averages_by_flight$Flight %in% current_flights], na.rm = TRUE),
            mean(averages_by_flight$Ground_Speed_m_s[averages_by_flight$Flight %in% current_flights], na.rm = TRUE),
            mean(averages_by_flight$Sea_Level_Descent_Rate_m_s[averages_by_flight$Flight %in% current_flights], na.rm = TRUE)
        )
}

rm(current_balloon_mass, current_flights)

rmarkdown::paged_table(averages_by_balloon_mass)

ggplot(
    melt(averages_by_balloon_mass,
         id.vars = "Balloon_Mass_kg"),
    aes(
        x = as.factor(Balloon_Mass_kg),
        y = value,
        fill = as.factor(Balloon_Mass_kg)
    )
) +
    geom_col() +
    facet_wrap(facets = "variable", scales = "free_y") +
    labs(title = "Averages by Balloon Mass", fill = "Balloon Mass (kg)") +
    theme(
        legend.position = c(1, 1.07),
        legend.direction = "horizontal",
        legend.justification = "right",
        axis.title.x = element_blank(),
        axis.title.y = element_blank()
    )
```
excluding `r average_excluded_flights`

# Mass Ratios

```{r calculate_mass_ratios}
mass_ratios <- flight_times[c(1, 7:9)]

mass_ratios$Balloon_Mass_Ratio <-
    mass_ratios$Balloon_Mass_kg / mass_ratios$Total_Mass_kg
mass_ratios$Helium_Mass_Ratio <-
    mass_ratios$Helium_Mass_kg / mass_ratios$Total_Mass_kg
mass_ratios$Helium_Balloon_Ratio <-
    mass_ratios$Helium_Mass_kg / mass_ratios$Balloon_Mass_kg

rmarkdown::paged_table(mass_ratios)
```

## Mass vs Flight Statistics

```{r mass_vs_flight_statistics, fig.height=7.4164079, fig.width=12}
ggplot(
    melt(
        melt(
            merge(averages_by_flight[c(1, 2, 5)],
                  mass_ratios[c(1, 2:4)],
                  by = c("Flight")),
            id.vars = c(
                "Flight",
                "Balloon_Mass_kg",
                "Ascent_Rate_m_s",
                "Sea_Level_Descent_Rate_m_s"
            ),
            variable.name = "mass_type",
            value.name = "mass"
        ),
        id.vars = c("Flight", "Balloon_Mass_kg", "mass_type", "mass"),
        variable.name = "value_type",
        value.name = "value"
    ),
    aes(
        x = mass,
        y = value,
        colour = as.factor(Balloon_Mass_kg)
    )
) +
    geom_point(size = 0.1) +
    facet_grid(value_type ~ mass_type, scales = "free") +
    geom_dl(aes(label = gsub("NS", "", Flight)),
            method = list(cex = 0.8, "visualcenter", "bumpup")) +
    theme(
        legend.position = c(1.03, 1.07),
        legend.direction = "horizontal",
        legend.justification = "right",
        axis.title.x = element_blank(),
        axis.title.y = element_blank()
    ) +
    guides(col = guide_legend(override.aes = list(shape = 15, size = 7))) +
    labs(title = "Mass vs Flight Statistics", colour = "Balloon Mass (kg)")
```

## Mass Ratios vs Flight Statistics

```{r mass_ratios_vs_flight_statistics, fig.height=7.4164079, fig.width=12}
ggplot(
    melt(
        melt(
            merge(
                merge(averages_by_flight[c(1, 2)],
                      mass_ratios[c(1:4)],
                      by = "Flight"),
                maximum_values_by_flight[c(1, 2)],
                by = "Flight"
            ),
            id.vars = c(
                "Flight",
                "Balloon_Mass_kg",
                "Ascent_Rate_m_s",
                "Burst_Altitude_m"
            ),
            variable.name = "ratio_type",
            value.name = "ratio"
        ),
        id.vars = c("Flight", "Balloon_Mass_kg", "ratio_type", "ratio"),
        variable.name = "value_type",
        value.name = "value"
    ),
    aes(
        x = ratio,
        y = value,
        colour = as.factor(Balloon_Mass_kg)
    )
) +
    geom_point(size = 0.1) +
    facet_grid(value_type ~ ratio_type, scales = "free") +
    geom_dl(aes(label = gsub("NS", "", Flight)),
            method = list(cex = 0.8, "visualcenter", "bumpup")) +
    theme(
        legend.position = c(1.03, 1.07),
        legend.direction = "horizontal",
        legend.justification = "right",
        axis.title.x = element_blank(),
        axis.title.y = element_blank()
    ) +
    guides(col = guide_legend(override.aes = list(shape = 15, size = 7))) +
    labs(title = "Mass Ratios vs Flight Statistics", colour = "Balloon Mass (kg)")
```

```{r teardown, include=FALSE}
rm(read_flight_times, read_flight_data)

rm(small.box.labels)
#rm(flight_times)
#rm(flight_data)

#rm(averages_by_balloon_mass, averages_by_flight, maximum_values_by_flight, mass_ratios, overall_averages, overall_records)
```

