Package {fpod}


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:

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 fp_read(). Each row must minimally have a POSIXct column time, with nanosecond precision.

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:

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 fp_read().

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 x when calling legend(). See legend() for details. If legend.pos is logical and FALSE, then the legend is suppressed.

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

fp_read()

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 as.POSIXct().

simplify

logical. If TRUE, simplifies the clicks data.table by stripping away some columns, such as clk_ipi_range, ipi_pre_max, amp_reversals, duration, and has_wav.

amp

a character string. With amp="extended", higher values are extrapolated from the duration of clipping and the IPI. For any other values of amp, the compressed SPL values recorded by the FPOD are used directly.

Details

The clicks data.frame contains the following columns:

Value

A list, with one or more of the following data.frames (or data.tables, if available):

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 fp_read(). Each row must minimally have a POSIXct column time. The return value of fp_read() is also accepted with a warning, provided that the clicks data.table is present .

Value

A data.table with three or four columns:

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