% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/dct_norm.R
\name{norm_dct_generic}
\alias{norm_dct_generic}
\title{Generic Formant DCT Normalization Procedure}
\usage{
norm_dct_generic(
  .data,
  ...,
  .token_id_col,
  .by = NULL,
  .param_col = NULL,
  .L = 0,
  .S = 1/sqrt(2),
  .by_formant = FALSE,
  .by_token = FALSE,
  .names = "{.formant}_n",
  .silent = opt("tidynorm.silent"),
  .drop_orig = FALSE,
  .call = caller_env()
)
}
\arguments{
\item{.data}{A data frame of formant DCT coefficients}

\item{...}{\code{\link[dplyr:dplyr_tidy_select]{<tidy-select>}} One or more unquoted
expressions separated by commas. These should target the vowel formant
data columns.}

\item{.token_id_col}{\code{\link[rlang:args_data_masking]{<data-masking>}} A column
that identifies token ids.}

\item{.by}{\code{\link[dplyr:dplyr_tidy_select]{<tidy-select>}} A selection of
columns to group by. Typically a column of speaker IDs.}

\item{.param_col}{A column identifying the DCT parameter number.}

\item{.L}{An expression defining the location parameter.
See Details for more information.}

\item{.S}{An expression defining the scale parameter.
See Details for more information.}

\item{.by_formant}{Whether or not the normalization method is formant
intrinsic.}

\item{.by_token}{Whether or not the normalization method is token
intrinsic}

\item{.names}{A \code{\link[glue:glue]{glue::glue()}} expression for naming the normalized
data columns. The \code{"{.formant}"} portion corresponds to the name of the original
formant columns.}

\item{.silent}{Suppress normalization information messages when running a \verb{norm_*()} function. (Defaults to \code{FALSE}, overwritable using option 'tidynorm.silent' or environment variable 'R_TIDYNORM_TIDYNORM_SILENT')}

\item{.drop_orig}{Should the originally targeted columns be dropped.}

\item{.call}{Used for internal purposes.}
}
\value{
A data frame of normalized DCT coefficients.
}
\description{
Generic Formant DCT Normalization Procedure
}
\details{
The following \verb{norm_dct_*} procedures were built on top of
\code{norm_dct_generic()}.
\itemize{
\item \link{norm_dct_lobanov}
\item \link{norm_dct_nearey}
\item \link{norm_dct_deltaF}
\item \link{norm_dct_wattfab}
\item \link{norm_dct_barkz}
}
\subsection{Normalizing DCT Coefficients}{

This will normalize vowel formant data that has already had the
Discrete Cosine Transform applied (see \link{dct}) with the following
procedure:
\enumerate{
\item Location \code{.L} and Scale \code{.S} expressions will be used to summarize
the zero\if{html}{\out{<sup>}}th\if{html}{\out{</sup>}} DCT coefficients.
\item These location and scale will be used to normalize the DCT coefficients.
}
\subsection{Location and Scale expressions}{

\link{norm_dct_generic} normalizes DCT coefficients directly.
If \eqn{F_k} is the k\if{html}{\out{<sup>}}th\if{html}{\out{</sup>}} DCT coefficient
the normalization procedure is

\deqn{
\hat{F}_k = \frac{F_k - L'}{\sqrt{2}S}
}
\deqn{
L' = \begin{cases}
   L & \text{for }k=0\\
   0 & \text{for }k>0
 \end{cases}
}

Rather than requiring users to remember to multiply expressions for \eqn{S}
by \eqn{\sqrt{2}}, this is done by \link{norm_dct_generic} itself, to allow greater
parallelism with how \link{norm_generic} works.

\strong{Note}: If you want to scale values by a constant in the normalization,
you'll need to divide the constant by \code{sqrt(2)}.

The expressions for calculating \eqn{L} and \eqn{S} can be
passed to \code{.L} and \code{.S}, respectively. Available values for
these expressions are

\describe{
\item{\code{.formant}}{The original formant value}
\item{\code{.formant_num}}{The number of the formant. (e.g. 1 for F1, 2 for F2 etc)}
}

Along with any data columns from your original data.
}

\subsection{Identifying tokens}{

DCT normalization requires identifying individual tokens, so there must be a column that
uniquely identifies (or, in combination with a \code{.by} grouping, uniquely
identifies) each individual token. This column should be passed to
\code{.token_id_col}.
}

}
}
\examples{
library(tidynorm)
library(dplyr)
ggplot2_inst <- require(ggplot2)

track_subset <- speaker_tracks |>
  filter(
    .by = c(speaker, id),
    if_all(
      F1:F3,
      .fns = \(x) mean(is.finite(x)) > 0.9
    ),
    row_number() \%\% 2 == 1
  )

track_dcts <- track_subset |>
  reframe_with_dct(
    F1:F3,
    .by = speaker,
    .token_id_col = id,
    .time_col = t,
    .order = 3
  )

track_norm <- track_dcts |>
  norm_dct_generic(
    F1:F3,
    .token_id_col = id,
    .by = speaker,
    .by_formant = TRUE,
    .L = median(.formant, na.rm = TRUE),
    .S = mad(.formant, na.rm = TRUE),
    .param_col = .param,
    .drop_orig = TRUE,
    .names = "{.formant}_mad"
  )

head(track_norm)

full_tracks <- track_norm |>
  summarise(
    .by = c(speaker, vowel, .param),
    across(
      F1_mad:F3_mad,
      mean
    )
  ) |>
  reframe_with_idct(
    F1_mad:F3_mad,
    .by = c(speaker, vowel),
    .param_col = .param
  )

head(full_tracks)

if (ggplot2_inst) {
  ggplot(
    full_tracks,
    aes(F2_mad, F1_mad, color = speaker)
  ) +
    geom_path(
      aes(group = interaction(speaker, vowel))
    ) +
    scale_y_reverse() +
    scale_x_reverse() +
    scale_color_brewer(palette = "Dark2") +
    coord_fixed()
}
}
