| Title: | Read and Process 'FPOD' and 'CPOD' Data |
| Version: | 1.0.1 |
| Date: | 2026-04-30 |
| Description: | Read 'FPOD' and 'CPOD' data into 'R' directly from the 'FPOD' data files (i.e. .CP1, .CP3, .FP1 and .FP3 files). The 'FPOD' data files contain binary data, so they can't trivially be read into 'R' using the usual approach, e.g. fread() or read.csv(). This package decodes the binary data and imports all the data in one go (i.e. header/metadata, clicks, 'KERNO' classifications, environmental data and pseudo-WAV data). It is then trivial to aggregate data as you please, e.g. detection-positive-minutes per time block. The advantage of handling data processing in 'R' is a long topic, but suffice it to say that it 1) simplifies things (many fewer steps, as different vars have to be exported in multiple goes in the official 'FPOD' app), and more importantly, 2) makes data processing transparent and reproducible. References: Pirotta et al. 2014 <doi:10.1111/1365-2435.12146>. |
| License: | MIT + file LICENSE |
| Encoding: | UTF-8 |
| RoxygenNote: | 7.3.3 |
| LinkingTo: | Rcpp |
| Imports: | Rcpp (≥ 1.1.0), data.table |
| Suggests: | knitr, mixtools, rmarkdown, testthat (≥ 3.0.0) |
| Depends: | R (≥ 3.5) |
| Config/testthat/edition: | 3 |
| VignetteBuilder: | knitr |
| URL: | https://github.com/supermoan/fpod |
| BugReports: | https://github.com/supermoan/fpod/issues |
| NeedsCompilation: | yes |
| Packaged: | 2026-05-07 11:21:56 UTC; a21997 |
| Author: | André Moan [aut, cre, cph] |
| Maintainer: | André Moan <andre.moan@hi.no> |
| Repository: | CRAN |
| Date/Publication: | 2026-05-12 18:20:07 UTC |
fpod: Read and Process 'FPOD' and 'CPOD' Data
Description
Read 'FPOD' and 'CPOD' data into 'R' directly from the 'FPOD' data files (i.e. the .CP1, .CP3, .FP1 and .FP3 files). The FPOD data files contain binary data, so they can't trivially be read into 'R' using the usual approach (e.g. fread or read.csv). This package decodes the binary data and imports all the data in one go (i.e. header/metadata, clicks, 'KERNO' classifications, environmental data and pseudo-WAV data). It is then trivial to aggregate data as you please, e.g. detection-positive-minutes per time block. The advantage of handling data processing in 'R' is a long topic, but suffice it to say that it 1) simplifies things (many fewer steps, as different vars have to be exported in multiple goes in the official 'FPOD' app), and more importantly, 2) makes data processing transparent and reproducible. References: Pirotta et al. 2014 https://doi.org/10.1111/1365-2435.12146.
Details
For more information, see:
vignette 1 - getting started: Type
vignette("fpod", package = "fpod")vignette 2 - advanced usage: Type
vignette("advanced-usage", package = "fpod")help functions for any of the functions listed under
See Alsopackage website at https://supermoan.github.io/fpod/
Author(s)
André Moan andre.moan@hi.no ORCID
See Also
fp_read(), fp_summarize(), fp_find_buzzes(), fp_plot()
Get path to fpod example
Description
Get path to fpod example
Usage
fp_example(path = NULL)
Arguments
path |
Name of the file. If NULL, all example files are listed. |
Value
A character vector, containing the path(s) that matched, or the empty string, "", if none matched.
Examples
# get a list all example files
fp_example()
# get the path for this particular file
fp_example("gullars_period1.FP3")
Finds harbor porpoise feeding buzzes
Description
This function uses one of two methods to classify NBHF clicks into one of two classes: feeding buzz or non feeding buzz.
Usage
fp_find_buzzes(x, method = "clicks")
Arguments
x |
a data.table where each row is a click, as the "clicks" element in
the list object returned by |
method |
the method to use to find feeding buzzes - "clicks" or "trains". See details. |
Details
Note that the so-called "feeding buzzes" are usually considered to represent a combination of feeding buzzes and social calls. Even so, the classifications resulting from both of these methods are commonly used as a proxy of foraging activity.
The two available methods are:
-
clicksmethod: any inter-click-interval (ICI) less than 20 milliseconds is considered a NBHF feeding buzz. -
trainsmethod: buzzes are identified using a mixture Gaussian model, with the number of components k=3. All clicks associated with the first component are considered a NBHF feeding buzz. This method requires the package mixtools to work.
Value
An integer vector of the same length as nrow(x), where the values
indicate that that click can be considered a feeding buzz (value = 1) or not (value = 0).
References
Pirotta, E., Thompson, P.M., Miller, P.I., Brookes, K.L., Cheney, B., Barton, T.R., Graham, I.M. and Lusseau, D. (2014), Scale-dependent foraging ecology of a marine top predator modelled using passive acoustic data. Funct Ecol, 28: 206-217. https://doi.org/10.1111/1365-2435.12146
Examples
# first read some FPOD data
fn <- fp_example("gullars_period1.FP3")
dat <- fp_read(fn)
# extract porpoise clicks of quality Hi and Mod
nbhf <- dat$clicks[species == "NBHF" & quality_level >= 2]
# then add a 'feeding buzz' column to the clicks data.table
nbhf$buzz <- fp_find_buzzes(nbhf, method = "clicks")
Plot waveform and spectrum for a click
Description
This function constructs and plots the waveform and spectrum for a click for which extra information has been recorded (IPI and SPL values for up to 21 cycles). By default, FPODs collect extra data for about 1% of detected clicks.
Usage
fp_plot(x, click_no = NULL, legend.pos = "topleft")
Arguments
x |
A list object, as returned from |
click_no |
integer. The click number. If NULL, then all clicks are plotted, in sequential order, one at a time. |
legend.pos |
character/logical. If character; a single keyword specifying the legend position.
This parameter is passed as |
Details
According to the FPOD software guide, extra data are stored for a small percentage of clicks (about 1%). The clicks to record are selected by a "real-time train detection algorithm" running on the FPOD. The information stored is the amplitude and timing (at 250 nanosecond resolution) of the peak of the soundwave. This allows for the reconstruction of the waveform by fitting sine waves to the points stored.
Note that there's an option in the FPOD app to configure the FPOD to record
all clicks rather than just a small sample..
Value
Invisibly returns a numeric vector with the frequency values used for plotting
See Also
Examples
# read a FP3 file
fn <- fp_example("gullars_period1.FP3")
dat <- fp_read(fn)
# get the click number of the first five clicks for which we have WAV data.
first5 <- head(unique(dat$wav$click_no))
# plot one of them. Here, we plot number three
fp_plot(dat, first5[3])
# If the legend covers the curve, we can move it somewhere else.
fp_plot(dat, first5[3], legend.pos = "topright")
# If we only want to plot clicks that meet certain criteria, we have to do that
# manually. For example, we can plot 9 random NBHF clicks:
nbhf_clicks <- dat$clicks[species == "NBHF" & has_wav == TRUE, click_no]
old.mfrow = par()$mfrow
par(mfrow = c(3,3)) # we'll do 3 by 3 panels
for (i in sample(nbhf_clicks, size = 9)) {
fp_plot(dat, click_no = i, legend.pos = FALSE)
}
par(mfrow = old.mfrow) # reset graphics device to whatever it was before
Read FPOD data
Description
This function reads an FPOD or CPOD data file (FP1, FP3, CP1, CP3) into R.
Usage
fp_read(file, tz = "", simplify = TRUE, amp = "extended")
Arguments
file |
a character string. The path to the FPOD (or CPOD) data file. |
tz |
a character string. The time zone specification to be used for
calculating dates. Passed unchanged to |
simplify |
logical. If TRUE, simplifies the clicks data.table by
stripping away some columns, such as |
amp |
a character string. With |
Details
The clicks data.frame contains the following columns:
pod: the ID number of the pod
time: The time and date of the click, at microsecond resolution. Note that R might only display dates and times to a second precision, but any date or time calculations will use the full precision.
minute: minutes elapsed, since starting the FPOD
microsec: microseconds elapsed, since the start of the minute.
click_no: an ID number that uniquely identifies the click.
train_id: an ID number from the KERNO classifier, reset for each minute.
species: the species classification from the KERNO classifier
quality_level: the quality level of the classification, 0 (?/echo), 1 (Lo), 2 (Mod) or 3 (Hi).
echo: TRUE if the KERNO classifier thinks this click might be an echo of another click that has already been classified.
ncyc: number of cycles in click. This is a proxy for the click duration.
pkat: the number of the cycle with the highest amplitude
clk_ipi_range: range of inter-peak-intervals (IPIs) among cycles in click
ipi_pre_max: the IPI before pkat, in 250 nanosecond units
ipi_at_max: the IPI at pkat, in 250 nanosecond units
khz: The frequency (in kHz) of the peak cycle.
amp_at_max: the peak amplitude (SPL) of the loudest cycle
amp_reversals: the number of amplitude reversals
duration: click duration
has_wav: TRUE if there is a pseudo-WAV recorded for this click.
Value
A list, with one or more of the following data.frames (or data.tables, if available):
header: a list with pod name, coordinates, starting time, stopping time, user notes, etc.
clicks: A data.frame (or data.table) with data about each click. See details.
wav (only FPx files): pseudo-wav data - inter-peak-intervals (in 250 ns units) and raw amplitudes for a subset of clicks
env: misc data, angle from vertical (in degrees), ambient temperature (in deg C), battery voltage per stack (in units of volts), which battery column is in use, and the pod on/off state.
See Also
fp_find_buzzes(), fp_summarize()
Examples
# read a FP3 file
fn <- fp_example("gullars_period1.FP3")
dat <- fp_read(fn)
# show misc. information (pod number, deployment date, etc.)
dat$header
# show battery levels and recorded temperatures for each minute
dat$env
# tally up the number of clicks in each species category
table(dat$clicks$species)
Calculates minute-resolution summaries of clicks
Description
Calculates minute-resolution summaries of clicks
Usage
fp_summarize(x)
Arguments
x |
data.table where each row is a click, as the "clicks" element in
the list object returned by |
Value
A data.table with three or four columns:
time: POSIXct timestamp of the start of the 1-minute time chunk, in YYYY-mm-dd HH:MM format
dpm: detection-positive-minutes, 1 if at least one click is registered during the time chunk; 0 otherwise.
bpm: buzz-positive-minutes, 1 if at least one feeding buzz is registered during the time chunk, 0 otherwise. Note that bpm is only available if there is a 'buzz' column in the clicks data.table, e.g. from first calling
fp_find_buzzes()
See Also
fp_find_buzzes(), lubridate::floor_date()
Examples
# first read some FPOD data
fn <- fp_example("gullars_period1.FP3")
dat <- fp_read(fn)
# extract porpoise clicks of quality Hi and Mod
nbhf <- dat$clicks[species == "NBHF" & quality_level >= 2]
# get a simple summary, with timestamp, degC and dpm.
dpm <- fp_summarize(nbhf)
# If we also wanted buzz-positive-minutes, we could do this first.
nbhf$buzz <- fp_find_buzzes(nbhf, method = "clicks")
# This time, when we call fp_summarize, it should detect that there's a
# buzz column, and automatically calculate feeding-positive-minutes as well.
dpm <- fp_summarize(nbhf)
# Once we have DPMs, we can easily aggregate these into coarser time chunks
dpm_per_hour <- dpm[, .(dpm = sum(dpm)),
.(date = as.POSIXct(trunc(time, unit = "hours")))] # per hour
dpm_per_day <- dpm[, .(dpm = sum(dpm)),
.(date = as.Date(time))] # per day
dpm_per_month <- dpm[, .(dpm = sum(dpm)),
.(date = as.POSIXct(trunc(time, unit = "months")))] # per month