The gapctd package includes modules (filters and operations) for processing CTD data that are based on modules in SBE Data Processing (SBEDP) software. The gapctd modules replicate the output of SBEDP modules. However, the gapctd modules do not always include the full range of processing options that are available in SBEDEP modules because the gapctd modules are intended for limited use cases.
Modules accept and return ctd
objects and are designed to be interchangable (i.e., the order in which they are used can be swapped). This document describes the modules and demonstrates their use for processing CTD data.
Read-in the example CTD deployment file (.cnv) as a ctd
object using the read.oce
function from the oce package. The deployment file contains five variable columns that are populated in the oce object. A sixth field, salinity (simply called 'salinity'), is derived when the data are read-in using read.oce
.
| CTD File (.cnv) Variable | ctd
object Variable | Description |
|------|------|------|
| timeS | timeS | Time, Elapsed [seconds] |
| tv290C | temperature | Temperature [ITS-90, deg C] |
| prdM | pressure | Pressure, Strain Gauge [db] |
| c0S/m | conductivity | Conductivity [S/m] |
| flag | flag | Data quality flag |
| - | salinity | Practical Salinity [PSS-78] |
The file includes data from the entire deployment but only the downcast will be used for this demonstration. The oce::ctdTrim
function is used to automatically detect and remove scan data that were not in the downcast.
library(gapctd) ctd_data <- oce::read.oce(file = system.file("extdata/example/2021_06_24_0001_raw.cnv", package = "gapctd")) dc <- oce::ctdTrim(ctd_data, method = "sbe") # Assign correct time zone for CTD data (survey time) dc@metadata$startTime <- lubridate::force_tz(dc@metadata$startTime, tz = "America/Anchorage")
library(gapctd) ctd_data <- oce::read.oce(file = system.file("extdata/example/2021_06_24_0001_raw.cnv", package = "gapctd")) dc <- oce::ctdTrim(ctd_data, method = "sbe") # Assign correct time zone for CTD data (survey time) dc@metadata$startTime <- lubridate::force_tz(dc@metadata$startTime, tz = "America/Anchorage") # Generate standard oce plot plot(dc)
plot(dc)
The median_filter()
module is based on the median filter option in the SBEDP Window Filter (Wfilter) module. It calculates the median for selected channels within a specified scan window. Below, the median window filter is applied to temperature and conductivity channels for five (5) scan windows (corresponding with 1.25 seconds for the SBE19plus V2) and salinity is recalculated.
dc_1 <- gapctd::median_filter(dc, variables = c("temperature", "conductivity"), window = c(5,5)) dc_1@data$salinity <- oce::swSCTp(dc_1) # Calculate salinity par(mfrow = c(1,2)) plot(dc, which = 1, type = 'l') text(x = 31.56, y = 35, labels = "(1) Raw Downcast") plot(dc_1, which = 1, type = 'l') text(x = 31.56, y = 35, labels = "(2) Median Filter\nT+C")
The lowpass_filter()
module is based on the SBEDP Filter module. Below, the filter is applied to temperature, conductivity, and pressure channels with time constants of 0.5 s, 0.5 s, and 1 s, respectively. Salinity is then recalculated.
dc_2 <- gapctd::lowpass_filter(dc_1, variables = c("temperature", "conductivity", "pressure"), time_constant = c(0.5, 0.5, 1), freq_n = 0.25) # scan interval dc_2@data$salinity <- oce::swSCTp(dc_2) # Calculate salinity
par(mfrow = c(1,2)) plot(dc_1, which = 1, type = 'l') text(x = 31.56, y = 35, labels = "(2) Median Filter\nT+C") plot(dc_2, which = 1, type = 'l') text(x = 31.56, y = 35, labels = "(3) Low pass filter")
The align_var()
module is based on the SBEDP Align (AlignCTD) module. The module shifts channel data in time and interpolates between measurements when alignment parameters are not factors of the scan interval. In the example below, temperature is advanced by 0.5 seconds and salinity is recalculated. Plots showing a close-up of the section between 10 and 12 dbar.
dc_3 <- gapctd::align_var(dc_2, variables = "temperature", offset = -0.5) dc_3@data$salinity <- oce::swSCTp(dc_3) # Calculate salinity
par(mfrow = c(1,2)) plot(dc_2, which = 1, type = 'l', plim = c(12,10)) text(x = 31.55, y = 11.85, labels = "(3) Low pass filter") plot(dc_3, which = 1, type = 'l', plim = c(12,10)) text(x = 31.55, y = 11.85, labels = "(4) Align T")
The conductivity_correction()
module is based on the SBEDP Conductivity Cell Thermal Mass Correction (CellTM) module. The module implements a discrete time filter on conductivity based on the sample interval (freq_n), the initial conductivity error (alpha_C), and a time decay constant (beta_C). The function uses the sample interval in the data to estimate the sample interval if it is not provided.
Below, the conductivity correction is applied using the typical parameters recommended by the CTD manufacturer and salinity is recalculated.
dc_4 <- gapctd::conductivity_correction(dc_3, alpha_C = 0.04, beta_C = 1/8, freq_n = 0.25) dc_4@data$salinity <- oce::swSCTp(dc_4)
par(mfrow = c(1,2)) plot(dc_3, which = 1, type = 'l') text(x = 31.58, y = 35, labels = "(4) Align T") plot(dc_4, which = 1, type = 'l') text(x = 31.58, y = 35, labels = "(5) Correct C")
The slowdown()
module flags (but does not remove) scans where the CTD slowed below a user-specified speed threshold. To account for variable profiling speeds in trawl-mounted CTDs, the function also excludes the surface and bottom from flagging. This module is similar SBEDP module 'loop edit.'
dc_5 <- gapctd::slowdown(dc_4, min_speed = 0.1, window = 5, cast_direction = "downcast", exclude_bottom = 2)
par(mfrow = c(1,2)) plot(dc_4, which = 1, type = 'l') text(x = 31.58, y = 35, labels = "(5) Correct C") plot(dc_5, which = 1, type = 'l') text(x = 31.58, y = 35, labels = "(6) Slowdown")
Note that slowdown()
flags slowdowns and reversals but does not remove them. As such, the plots above are identical even though slowdowns and reversals were flagged in the data:
dc_4@data$flag[409:415] dc_5@data$flag[409:415]
The derive_eos()
module uses functions from the oce package to calculate the following variables from scan data:
| Variable | Description | Method | oce
function |
|------|------|------|------|
| depth | Depth [m] | EOS-80 | swDepth() |
| salinity | Practical salinity [PSS-78] | EOS-80 | swSCTp(eos="unesco") |
| density | In-situ density [kg m^-3] | EOS-80 | swRho() |
| absolute_salinity | Absolute salinity | TEOS-10 | swSCTp(eos="gsw") |
| N2 | Squared buoyancy frequency [s^-2] | | swN2() |
dc_6 <- gapctd::derive_eos(dc_5) head(as.data.frame(dc_6@data))
The bin_average()
module is based on the SBDEP Bin Average (BinAvg) module. The module calculates means of variables by depth or pressure bin, with bad scan (flag < 0) data excluded. Binning can be performed by pressure or depth bins and surface data can be excluded based on a user-specified depth or pressure threshold (default = 0.5). In the example below, means are calculated for 1 m depth bins and data from < 0.5 m depth are excluded.
dc_7 <- gapctd::bin_average(dc_6, by = "depth", bin_width = 1)
par(mfrow = c(1,2)) plot(dc_5, which = 1, type = 'l') text(x = 31.58, y = 35, labels = "(6) Slowdown") plot(dc_7, which = 1, type = 'l') text(x = 31.58, y = 35, labels = "(7) Bin average")
The whole processing workflow can be run using pipe operators (native |>
or magrittr %>%
).
dc_8 <- dc |> gapctd::median_filter(variables = c("temperature", "conductivity"), window = c(5,5)) |> gapctd::lowpass_filter(variables = c("temperature", "conductivity", "pressure"), time_constant = c(0.5, 0.5, 1), freq_n = 0.25) |> gapctd::align_var(variables = "temperature", offset = -0.5) |> gapctd::conductivity_correction(alpha_C = 0.04, beta_C = 1/8) |> gapctd::slowdown(min_speed = 0.1, window = 5, cast_direction = "downcast") |> gapctd::derive_eos() |> gapctd::bin_average(by = "depth", bin_width = 1)
plot(dc_7, which = 1, type = 'l') text(x = 31.58, y = 35, labels = "(7) Bin average") plot(dc_8, which = 1, type = 'l') text(x = 31.58, y = 35, labels = "(8) Piped")
The modules above can be used with any ctd
object data from any CTD. However, some modules are specifically been developed for processing GAP's CTD data, and their use is demonstrated below.
| Module | Purpose |
|------|------|
| append_haul_data()
| Adds haul metadata from RACEBASE to ctd objects based on CTD time stamps and event time stamps in RACEBASE. |
| assign_metadata_fields()
| Assigns metadata fields to downcast or upcast fields based on user-specified cast_direction |
| section_oce()
| Extracts a section (downcast, bottom, or upcast) from a ctd object based on scan time stamps and event time stamps in metadata fields. |
# Haul data from the same vessel/cruise/CTD as the data file ex_haul <- readRDS(file = system.file("extdata/example/HAUL_DATA_162_202101_202102.rds", package = "gapctd")) dc@metadata$startTime <- lubridate::force_tz(dc@metadata$startTime, tz = "America/Anchorage") dc_9 <- dc |> gapctd:::append_haul_data(haul_df = ex_haul) |> gapctd:::assign_metadata_fields(cast_direction = "downcast") |> gapctd:::section_oce(by = "datetime", cast_direction = "downcast") |> gapctd::median_filter(variables = c("temperature", "conductivity"), window = c(5,5)) |> gapctd::lowpass_filter(variables = c("temperature", "conductivity", "pressure"), time_constant = c(0.5, 0.5, 1), freq_n = 0.25) |> gapctd::align_var(variables = "temperature", offset = -0.5) |> gapctd::conductivity_correction(alpha_C = 0.04, beta_C = 1/8) |> gapctd::slowdown(min_speed = 0.1, window = 5, cast_direction = "downcast") |> gapctd::derive_eos() |> gapctd::bin_average(by = "depth", bin_width = 1) plot(dc_9)
The modules for working with GAP CTD data appended location data to the metadata object so now the location of the cast can be shown in the standard oce plots.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.