Call Density Estimate using auxiliary information from sonar equation
Source:R/callDensityEstimate.R
cde.RdApplies the auxiliary information methods of Castro et. al. (2024)/Harris (2012) to obtain call density, \(\hat{D_c}\) using the cannonical density equation: $$D_c = \frac{N_c(1-c)}{kTA\hat{p}_a}$$ and sonar equations $$SNR = RL - NL$$ $$RL = SL - TL$$ where:
\(\hat{D_c}\) is call density
\(N_c\) is number of calls
\(c\) is false discovery rate
\(k\) is number of sensors (here always 1)
\(T\) is the duration of data analysed
\(A\) is the study area (in km\^2)
\(\hat{p}_a\) is the probability of detection in the study area.
\(\hat{p}_a\) is estimated via pDetInArea, a Monte Carlo simulation using
auxiliary information for the sonar equation, so requires:
SL - Distribution of source levels (mean, sd, samplesize)
TL - Transmission loss model
NL - Distribution of noise levels
snrDetFun - a model of the relationship between SNR and probability of detection either via a capture history table or supplied detection function
Usage
cde(
Nc,
capHistTab,
SL,
TL,
T = 1,
A = 1,
k = 1,
season = "year",
snrDetFun = NULL,
NL = NULL,
modelType = "scam",
numKnots = 5,
output.resolution.m = 100,
outerloop = 10,
transectFile = NULL,
simResultsFile = NULL,
paFile = NULL,
truncationDistance = max(TL[, 1]),
snrTruncationThreshold = -Inf,
NcIsTruncated = FALSE,
siteCode = "",
densityResultsFile = NULL,
parallel = FALSE,
groundTruthCol = "detect_table1",
observerCol = "detect_table2",
snrColName = "SNR",
signalCol = "signalRMSdB",
noiseCol = "noiseRMSdB",
timeCol = NULL,
returnDetFun = FALSE,
returnPdetDetail = FALSE
)Arguments
- Nc
Total count of true positive detections for call density estimate
- capHistTab
Capture history table used to derive false positive rate. Can also be used to derive probability of detection as a function of SNR for estimating \(p_a\) if snrDetFun is not specified.
Must contain columns
detect_table1anddetect_table2.detect_table1is always read as ground truth (0 = false positive, 1 = true positive) anddetect_table2as the detector under investigation – this is inherited unconditionally fromfalseDiscoveryRate()andcapHist2snrInfo(), which cde calls internally and which do not expose a way to override these column names from here.For an observer-ground (OG) analysis, where one trusted observer stands in for ground truth,
detect_table1is that observer's own detections, and this holds without any extra work.For an adjudicated capture-recapture (CR) analysis, where two observers are both fallible and neither is ground truth, this requires a deliberate construction step:
detect_table1must be overwritten with the adjudicator's verdict (true call vs false positive) before the table is passed to cde, not left as one of the two raw observers being compared. Getting this wrong does not error – it silently computes a false discovery rate for one observer against the other, which is not a meaningful quantity and will not match the true rate. Seevignette("callDensity_snrThreshold"), section "Calculate call densities", for a worked example of this construction.- SL
List containing distribution of source level parameters. SL must contain named elements named: mean, sd, and sampleSize.
- TL
Data.frame of transmission losses for Monte Carlo simulation. The first column must contain the ranges, the remaining columns contain transmission losses (in dB) for each radial transect at that range.
- A
Scalar indicating the area for the call density estimate (default=1)
- k
Number of sensors (default=1)
- season
TimeCode specifying month, season, or year for outputs. Timecodes follow the same form as those from the World Ocean Atlas.
- snrDetFun
(Optional) Linear-model like structure (GLM,GAM,SCAM,VGLM,etc) specifying the SNR-detection function to use. If this is not included, then the SNR-detection function will be derived from the capture history table.
- NL
(Optional and Experimental/Unsupported) list or data.frame containing distribution of noise level parameters. Must contain items named: mean, sd, and sampleSize (similar to SL). If not provided, NL will be estimated from the capture history table (and snrDetFun).
- modelType
Either 'glm','gam','scam',or 'vglm' indicating which type of model to use for estimating probability of detection as a function of SNR (default='scam')
- numKnots
Number of knots to use wor modelling detection function vs SNR (only if model types 'gam' or 'scam') default = 5
- output.resolution.m
Spatial resolution along radial transects for estimating probability of detection in area. Default = 100
- outerloop
Number of bootstrap iterations for Monte Carlo simulation
- transectFile
(Optional) Output text file name where probability of detection will be saved. This includes the probability of detection at each output.resolution.m step, so potentially yields a large file (hundreds of MB). Default is to not write this information to disk.
- simResultsFile
(Optional) Name of output text file where Monte Carlo Simulation parameters and results will be saved. Default is to not write this information to disk.
- paFile
(Optional) Name of output text file where mean probability of detection per transect and overall area will be saved. Default is to not write this information to disk.
- truncationDistance
scalar or matrix of truncation distances. If a matrix is provided, then the dimensions should be 1xN with each column corresponding to a radial transect and N being the the total number of transects.
- snrTruncationThreshold
(Experimental) scalar SNR in dB below which the probability of detection is forcibly set to zero. Use this when the detection function is not identified at low SNR, which happens when the two observers stop contributing overlapping detections (recaptures) there. Set it where the recaptures run out, not where the sample runs out.
Truncation must be applied consistently to every term that counts detections.
cand the detection function are truncated by cde;Nccannot be, because cde receives it as a number, so you must truncate it yourself and confirm withNcIsTruncated.Ais unchanged, and the noise level is estimated from the untruncated sample, because noise is a property of the ocean rather than of the threshold.The returned density is that of all calls, not of above-threshold calls. The fraction of calls arriving above the threshold, q(theta), is supplied by SL, TL and NL, and cancels between
Ncandp_a. Truncation therefore buys accuracy at the cost of precision:Ncshrinks.- NcIsTruncated
Logical confirmation that
Nccounts only detections with SNR >=snrTruncationThreshold. Required (and only used) whensnrTruncationThresholdis finite. cde never sees the detectionsNcwas counted from, so it cannot verify this itself, and an untruncatedNcpaired with a truncatedp_ainflatesDcsilently.- siteCode
(Optional) string containing a code or label associated with the site. Default is ” (i.e. blank).
- densityResultsFile
(Optional) name of csv file where final call density results will be written as a data.frame
- parallel
Logical. If TRUE, the Monte Carlo simulation inside pDetInArea runs in parallel via future.apply::future_lapply, using whatever future plan is currently active. Set the plan before calling cde(), e.g.
future::plan(future.callr::callr, workers = 30). Default FALSE (serial).Parallel execution provides significant speedups for computationally expensive models (e.g. VGLM/VGAM detection functions from the VGAM package), where each Monte Carlo iteration involves multiple calls to
VGAM::predict. For lightweight models (e.g. scam, gam, glm), the per-iteration work is too fast relative to the overhead of dispatching to and collecting from parallel workers, andparallel=TRUEwill typically be slower than serial execution.As a rule of thumb: use
parallel=TRUEfor VGLM-based detection functions (modelType='vglm') andparallel=FALSE(the default) for everything else.- groundTruthCol
Column in
capHistTabtreated as ground truth, forwarded tofalseDiscoveryRate()andchtToSNRinfo. Default'detect_table1', matching original behaviour. For a native matchbox table with adjudicated verdicts, pass'verdict'(or'detect_verdict'– both resolve the same column).- observerCol
Column(s) in
capHistTabfor the detector(s) under evaluation, forwarded the same way asgroundTruthCol. Default'detect_table2'(a single column, matching original behaviour). Pass a vector of columns for a union call density estimate across several detectors –Ncthen must be a union count too (seeunionDetections), andsnrDetFun(if supplied already fitted) must havewhichObserver = "any"set, matching this same set of detectors – cde() checks this pairing and refuses to silently combine a unioncwith a single-detectorp_aor vice versa.- snrColName
Column in
capHistTabholding SNR, forwarded tofalseDiscoveryRate(). Default'SNR'(uppercase), matching original behaviour – raw simulation/detection tables typically carry lowercasesnrinstead (seenotes/cde_pipeline_handover.md's "column-name trap"), so passsnrColName = 'snr'for those.- signalCol, noiseCol
Column(s) in
capHistTabholding signal and noise level, forwarded tochtToSNRinfo. Default'signalRMSdB'/'noiseRMSdB', matching original behaviour – a single, already-consolidated column per table. A genuine matchbox- native (orsimsTocaptureHistoryTable-built) table instead carries one such column per observer, suffixed (signalRMSdB_observer1,signalRMSdB_observer2, ...) – pass the relevant observers' columns as a vector, e.g.signalCol = c('signalRMSdB_observer1', 'signalRMSdB_observer2'), andchtToSNRinfo()averages them per event the same way it already does for any other multi-observer signal/noise input.- timeCol
Column in
capHistTabto derive time/season from, forwarded tochtToSNRinfo. DefaultNULLauto-detects't0'(matchbox-native) else't'(legacy), matching original behaviour. Raw simulation tables carry'datetime'instead of either – passtimeCol = 'datetime'for those, rather than relying on the auto-detection growing a third implicit guess.- returnDetFun
Logical, default
FALSE. IfTRUE, the detection function actually used to computepa/Dc– whichever was passed in assnrDetFun, or the onecde()fit internally whensnrDetFun=NULL– is attached to the returned data.frame as the"detFun"attribute (retrieve withattr(result, "detFun")). Off by default so this is purely opt-in: the return value's shape and content are unchanged for every existing caller unless they ask for this.- returnPdetDetail
Logical, default
FALSE. IfTRUE, the full result of the internalpDetInArea()call – including the per-transect detail ($meanOfAllTransects) needed to plot probability of detection as a function of range, not just the singlepavaluecde()itself returns – is attached as the"pDetResults"attribute. Off by default, same reasoning asreturnDetFun.Requires the future.apply package. If not installed, falls back to serial execution with a warning.
Value
cde returns a data.frame containing the results of the call
density estimate \(\hat{D}_c\), intermediate results such as \(p_a,
c\), coefficient of variation of these terms, and the input parameters.
If returnDetFun/returnPdetDetail are set, the
corresponding extra objects are attached as attributes on this same
data.frame (see those parameters) rather than changing its shape.
Details
cde estimates call density with all parameters included as function
arguments. This is in contrast to the previous operation, i.e. where a
data.frame of parameters was used to indicate which files to load from disk.
Here no parameter file/data.frame is used, so all data and parameters are
must already be objects in memory;