% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/crp.R
\name{crp}
\alias{crp}
\title{Canonical Response Parameterization (\verb{CRP})}
\usage{
crp(
  x,
  time,
  t_start = 0.015,
  t_end = 1,
  remove_artifacts = TRUE,
  artifact_interval = c("full", "tR"),
  artifact_p_threshold = 1e-05,
  threshold_quantile = 0.98,
  time_step = 5L,
  detect_onset = FALSE,
  onset_search_start = NULL
)
}
\arguments{
\item{x}{numeric matrix of single-trial evoked voltages with shape
\code{time x trials} (i.e. rows are timepoints, columns are trials);
the matrix orientation matches the variable \code{V} / \code{data} in
the MATLAB reference. At least two trials are required.}

\item{time}{numeric vector of length \code{nrow(x)} giving the
stimulus-aligned time (in seconds) of each row of \code{x}; must be
monotonically increasing and span \code{[t_start, t_end]}.}

\item{t_start, t_end}{numeric scalars, post-stimulation start and end times
(in seconds) defining the analysis window. Defaults match the MATLAB
illustration (\code{0.015 s} to \code{1 s}).}

\item{remove_artifacts}{logical; if \code{TRUE} (the default), an initial
\verb{CRP} pass is run to identify outlier/artifact trials, which are then
dropped before the final pass. See \sQuote{Details}.}

\item{artifact_interval}{character, one of \code{"full"} (the default,
matching the active option in the MATLAB illustration) or \code{"tR"};
selects whether per-trial outlier statistics are computed on the
projection magnitudes for the full window or only at the response
duration \eqn{\tau_R}.}

\item{artifact_p_threshold}{numeric, p-value threshold below which a
trial is flagged as artifact (provided its mean projection is also
below the cohort mean); defaults to \code{1e-5}.}

\item{threshold_quantile}{numeric in \code{(0, 1)}; the fraction of the
peak mean projection magnitude used to derive the duration-uncertainty
bounds \code{tau_R_lower} and \code{tau_R_upper}. Defaults to
\code{0.98} as in the manuscript.}

\item{time_step}{integer, sampling step (in samples) used when sweeping
candidate response duration; defaults to \code{5L}, matching the
MATLAB \code{t_step}. Larger values are faster but smooth the
projection profile.}

\item{detect_onset}{logical; if \code{TRUE}, estimate the response
\emph{onset} \eqn{\tau_{onset}} via a reverse cumulative-projection scan
(see \sQuote{Details}). The forward canonical shape and per-trial weights
are left unchanged; only the \emph{reported} canonical shape \code{C} is
restricted to the active response support \eqn{[\tau_{onset}, \tau_R]}.
The onset may fall before \code{t_start} (down to \code{onset_search_start}).
Defaults to \code{FALSE}.}

\item{onset_search_start}{numeric scalar or \code{NULL}; the earliest time
(in seconds) the onset scan may reach when \code{detect_onset = TRUE}.
\code{NULL} (the default) uses the first loaded time point, so the scan can
look across the entire signal before \eqn{\tau_R}. Raise it to keep the scan
away from an early stimulation artifact. Clamped into
\code{[min(time), t_end]}.}
}
\value{
A named list with the following elements:
\describe{
\item{\code{parameters}}{A list of single-trial parameterizations
(\code{crp_parms} in MATLAB):
\describe{
  \item{\code{C}}{Numeric vector, the reported canonical response shape
    \eqn{C(t)}, taken as the slice of \code{C_full} over its active support
    (so it shares identical values with \code{C_full}). By default this is
    \eqn{[t_{start}, \tau_R]}, where it equals the first eigenvector of the
    linear kernel PCA on \code{V_tR} (oriented to the mean trace, unit-norm,
    length \eqn{T_R}). When \code{detect_onset = TRUE} it is restricted to
    \eqn{[\tau_{onset}, \tau_R]} (so its norm is then \eqn{\le 1}). The
    matching time axis is \code{params_times}.}
  \item{\code{C_full}}{Numeric vector spanning the \emph{entire} loaded
    time range (every row of \code{time}, including any baseline at
    \eqn{t < 0}). Obtained by applying the trial-space \code{loading} to the
    full retained data, so \code{C_full} coincides exactly with the
    untrimmed forward \code{C} on \eqn{[t_{start}, \tau_R]} and extrapolates
    the shape everywhere else. Time axis is \code{params_times_full}.
    Outside \eqn{[t_{start}, \tau_R]} cross-trial consistency is not
    optimized, so those portions are more variable.}
  \item{\code{loading}}{Numeric vector of length \eqn{K} (retained
    trials), the trial-space loading \eqn{g = V_{tR}^\top C = s_1 v_1}
    recovered from the forward decomposition. Applying it to a
    time \eqn{\times} trials matrix and dividing by \eqn{\|g\|^2}
    reconstructs the canonical shape over that time range; this is how
    \code{C_full} is formed.}
  \item{\code{al}}{Numeric vector of length \eqn{K} (number of trials),
    the per-trial alpha coefficient \eqn{\alpha_k = C^\top V_k}: scalar
    projection of trial \eqn{k} onto \eqn{C(t)}. Larger magnitude means
    the trial resembles the canonical shape more strongly; sign reflects
    polarity relative to \eqn{C}.}
  \item{\code{al_p}}{Numeric vector of length \eqn{K}, alpha-prime
    \eqn{\alpha_k / \sqrt{T_R}}: \code{al} rescaled to remove the
    duration dependence from the unit-norm convention on \eqn{C}.
    Expressed in \eqn{\mu V} and comparable across electrodes or
    conditions with different \eqn{\tau_R}.}
  \item{\code{ep}}{Numeric matrix of shape \eqn{T_R \times K}, the
    per-trial residual \eqn{\epsilon_k(t) = V_k(t) - \alpha_k C(t)}
    after the shared component is removed, computed over the forward window
    \eqn{[t_{start}, \tau_R]} against the untrimmed forward canonical shape.
    Access trial \eqn{k} via \code{ep[, k]}. (When
    \code{detect_onset = TRUE} the reported \code{C} may be shorter than
    \eqn{T_R}; \code{ep} always stays on the full forward window.)}
  \item{\code{epep_root}}{Numeric vector of length \eqn{K},
    \eqn{\|\epsilon_k\| = \sqrt{\epsilon_k^\top \epsilon_k}}: L2 norm
    of the residual per trial. Smaller values indicate the canonical
    shape describes that trial more faithfully.}
  \item{\code{Vsnr}}{Numeric vector of length \eqn{K}, per-trial
    signal-to-noise \eqn{\alpha_k / \|\epsilon_k\|}. Values \eqn{> 1}
    indicate the canonical component is larger than the residual.}
  \item{\code{expl_var}}{Numeric vector of length \eqn{K}, per-trial
    explained variance \eqn{1 - \|\epsilon_k\|^2 / \|V_k\|^2}: fraction
    of each trial's energy accounted for by \eqn{\alpha_k C(t)}.
    Ranges in \eqn{[0, 1]}.}
  \item{\code{tR}}{Numeric scalar, response duration \eqn{\tau_R} in
    seconds: the time at which mean cross-trial projection magnitude is
    maximized.}
  \item{\code{params_times}}{Numeric vector, time axis for the reported
    \code{C}; length matches \code{C} (\eqn{T_R}, or the onset-trimmed
    support when \code{detect_onset = TRUE}).}
  \item{\code{params_times_full}}{Numeric vector, time axis for
    \code{C_full}; equals the full loaded \code{time} (every row,
    including the baseline at \eqn{t < 0}).}
  \item{\code{V_tR}}{Numeric matrix \eqn{T_R \times K}, trial matrix
    truncated to \eqn{\tau_R} - the data actually decomposed. Together
    with \code{ep} and \code{avg_trace_tR} it always spans the full
    forward window \eqn{[t_{start}, \tau_R]}, independently of
    \code{detect_onset}.}
  \item{\code{avg_trace_tR}}{Numeric vector of length \eqn{T_R}, simple
    trial average truncated to \eqn{\tau_R}.}
}}
\item{\code{projections}}{A list of projection-stage outputs
(\code{crp_projs} in MATLAB):
\describe{
  \item{\code{proj_tpts}}{Numeric vector, candidate duration time points
    (seconds) at which projection magnitudes were evaluated.}
  \item{\code{S_all}}{Numeric matrix; rows are non-redundant off-diagonal
    trial-pair projections, columns correspond to \code{proj_tpts}.
    Units: \eqn{\mu V \cdot s^{1/2}}.}
  \item{\code{mean_proj_profile}}{Numeric vector, mean of \code{S_all}
    across trial pairs at each candidate duration, the profile whose
    maximum defines \eqn{\tau_R}.}
  \item{\code{var_proj_profile}}{Numeric vector, variance of
    \code{S_all} across trial pairs at each candidate duration.}
  \item{\code{tR_index}}{Integer, column index into \code{S_all} and
    \code{proj_tpts} corresponding to \eqn{\tau_R}.}
  \item{\code{tR_sample}}{Integer, row (sample) index of \eqn{\tau_R}
    within the windowed data; \code{V[seq_len(tR_sample), ]} is the
    truncated trial matrix \code{V_tR}.}
  \item{\code{avg_trace_input}}{Numeric vector, simple trial average
    over the full analysis window (not truncated to \eqn{\tau_R}).}
  \item{\code{stat_indices}}{Integer vector, row indices of \code{S_all}
    used for the significance t-tests, constructed so each trial-pair
    comparison appears at most once.}
  \item{\code{t_value_tR}, \code{p_value_tR}}{t-statistic and one-sided
    p-value (H1: mean projection \eqn{> 0}) at \eqn{\tau_R}. Primary
    extraction-significance test reported in the manuscript.}
  \item{\code{t_value_full}, \code{p_value_full}}{Same test at the full
    analysis-window duration.}
}}
\item{\code{bad_trials}}{Integer vector of column indices into the
original \code{x} flagged and removed as artifacts; \code{integer(0)}
when none removed or when \code{remove_artifacts = FALSE}.}
\item{\code{tau_R}}{Numeric scalar, estimated response duration
\eqn{\tau_R} in seconds (convenience copy of \code{parameters$tR}).}
\item{\code{tau_R_lower}, \code{tau_R_upper}}{Numeric scalars, lower
and upper threshold-crossing times (seconds) bracketing \eqn{\tau_R}
at the \code{threshold_quantile} fraction of the peak mean projection
magnitude.}
\item{\code{tau_onset}, \code{tau_onset_lower},
\code{tau_onset_upper}}{Numeric scalars, the estimated response onset
time (seconds) and its lower/upper threshold-crossing bounds, from the
reverse projection scan; all \code{NA} unless \code{detect_onset = TRUE}.}
\item{\code{onset}}{List with the reverse-scan profile (\code{onset_tpts}
and \code{mean_proj_profile}, mapped onto original time); \code{NULL}
unless \code{detect_onset = TRUE} (also \code{NULL} when the search window
had too few samples).}
\item{\code{t_start}, \code{t_end}}{The analysis window used.}
\item{\code{sample_rate}}{Numeric, sampling rate inferred from
\code{time}.}
}
}
\description{
Parameterizes single-trial evoked responses (e.g. cortico-cortical evoked
potentials, \verb{CCEPs}) using the Canonical Response Parameterization
method (see 'Citation'). The function estimates the response
duration \eqn{\tau_R}, the time after stimulus at which the evoked
response has its most consistent, shared structure across trials.
The estimator is obtained from the time course of cross-trial projection
magnitudes, extracts the canonical response shape \eqn{C(t)} via a linear
kernel-trick PCA on the trial matrix truncated at \eqn{\tau_R}, and
reports per-trial weights, residuals, signal-to-noise, explained variance
and extraction-significance statistics.

This is an R translation of \code{CRP_method.m} (and the surrounding
artifact-rejection / duration-uncertainty logic in
\code{CRP_illustration.m}) from the upstream MATLAB reference
implementation; see \sQuote{References}.
}
\details{
Briefly, the algorithm proceeds in three stages:
\enumerate{
\item For a sweep of candidate durations \eqn{k}, compute pairwise
L2-normalized cross-projection magnitudes between trials truncated to
\eqn{[0, k]}. The duration that maximizes the mean projection magnitude
is taken as the response duration \eqn{\tau_R}.
\item Apply linear kernel-trick PCA to the trial matrix truncated to
\eqn{\tau_R}; the first principal component is the canonical response
shape \eqn{C(t)}.
\item Project \eqn{C(t)} into each trial to obtain per-trial weights
\eqn{\alpha_k}; the residual \eqn{\epsilon_k = V_k - \alpha_k C}
summarizes trial-by-trial deviation from the canonical shape.
}
Significance is assessed by a one-sided t-test on the off-diagonal
projection magnitudes against zero, restricted to a non-overlapping
subset of comparison pairs to avoid double-counting.

When \code{remove_artifacts = TRUE}, the function performs an initial
\verb{CRP} pass and runs an unpaired t-test for each trial comparing the
projections it participates in against all other off-diagonal
projections. Trials with \code{p < artifact_p_threshold} \emph{and}
mean projection below the cohort mean are dropped, and \verb{CRP} is re-run.

When \code{detect_onset = TRUE}, a complementary reverse pass estimates the
response \emph{onset}. The retained trials between \code{onset_search_start}
and \eqn{\tau_R} are time-reversed, and the same cumulative cross-projection
profile is computed growing backward from \eqn{\tau_R}. The backward
duration that maximizes cross-trial consistency marks \eqn{\tau_{onset}},
the time at which trials begin to share structure - useful when the response
is delayed by an unknown latency. Because the scan can extend before
\code{t_start}, the onset may be earlier than the analysis window. This pass
only locates a time: it re-uses the forward loading, so the canonical shape
and per-trial weights are unchanged (the reported \code{C} is merely sliced
to \eqn{[\tau_{onset}, \tau_R]}).

Time points whose data are not finite (any \code{NA}, \code{NaN} or
\code{Inf} across trials) are dropped before analysis. \code{t_start},
\code{t_end} and \code{onset_search_start} are clamped into the available
time range rather than triggering an error.
}
\examples{
set.seed(42)

# Synthetic CCEP-like data: shared canonical shape with per-trial scaling
n_time   <- 500L
n_trials <- 20L
tt <- seq(-0.5, 1, length.out = n_time)
canonical <- exp(-((tt - 0.10) / 0.05)^2) -
             0.5 * exp(-((tt - 0.30) / 0.10)^2)
V <- (outer(canonical, runif(n_trials, 0.5, 1.5)) +
       matrix(rnorm(n_time * n_trials, sd = 0.3), n_time, n_trials)) * 2

res <- crp(V, tt)

op <- par(mfrow = c(1, 3), mar = c(4.5, 4, 3, 1))
on.exit({ par(op) })

# ---- Panel 1: all trials (full window) + mean + C(t) overlay ----------
parms <- res$parameters
matplot(tt, V, type = "l", lty = 1,
        col = "#80808060", xlab = "Time (s)",
        ylab = expression(mu * V),
        main = expression("Canonical shape " * C(t)))
# scale C(t) to the amplitude of the mean trace for overlay;
# C(t) ends at tau_R so the line is cut off there naturally
C_scaled <- parms$C * max(abs(rowMeans(V))) / max(abs(parms$C))
lines(parms$params_times, C_scaled, col = "#FFFF0080", lwd = 3)

# Mean
lines(tt, rowMeans(V), col = "black", lwd = 1)
legend("topright", c("mean", "C(t) scaled"),
       col = c("black", "#FFFF00"), lty = c(1, 2), lwd = 2,
       bty = "n", cex = 0.8)

# ---- Panel 2: per-trial alpha-prime weights -----------------------------
barplot(sort(parms$al_p), col = "steelblue", border = NA, las = 1,
        xlab = "Trial (sorted)",
        ylab = expression(alpha * "'" ~ (mu * V)),
        main = expression("Per-trial " * alpha * "' (alpha-prime)"))
abline(h = c(0, mean(parms$al_p)), lty = 2)

# ---- Panel 3: mean projection profile with tau_R bounds ----------------
proj <- res$projections
plot(proj$proj_tpts, proj$mean_proj_profile, type = "l", lwd = 2,
     xlab = "Candidate duration (s)",
     ylab = expression(bar(S) ~ (mu * V \%.\% s^{0.5})),
     main = expression("Projection profile & " * tau[R]),
     las = 1)
abline(v = c(res$tau_R_lower, res$tau_R, res$tau_R_upper),
       col = c("cyan3", "orange2", "red"),
       lty = c(2, 1, 2), lwd = 2)
legend("topright",
       legend = expression(tau[lb], tau[R], tau[ub]),
       col = c("cyan3", "orange2", "red"),
       lty = c(2, 1, 2), lwd = 2, bty = "n")

par(op)

# ---- Onset detection (reverse scan) on the same data -------------------
res_onset <- crp(V, tt, detect_onset = TRUE)
c(tau_onset = res_onset$tau_onset, tau_R = res_onset$tau_R)

}
\references{
The \verb{CRP} algorithm is described in \doi{10.1371/journal.pcbi.1011105},
with a reference MATLAB implementation at
\url{https://github.com/kaijmiller/crp_scripts}. See
\code{citation("ravetools")} for the full bibliographic entry.
}
