R/benchmark_targets.R

Defines functions get_nalnl2_v2_target

# Extrapolated target insertion gains for a 65 dB SPL input 
# from Johnson & Dillon (2011) "A comparison of NAL-NL2 and DSL m[i/o] v5.0a for adults"
# These match the exact A-1 to A-7 audiograms.

jd2011_targets <- list(
  "a1" = list(
    # Fine-frequency grid from Johnson & Dillon (2011) Table/Figure data
    freq = c(125, 160, 200, 250, 315, 400, 500, 630, 800, 1000, 1250, 1600, 2000, 2500, 3150, 4000, 5000, 6300, 8000),
    threshold = c(15, 20, 30, 40, 50, 60),   # at standard audiometric freqs
    # NAL-NL2 insertion gains at each input level
    nalnl2_50 = c(0.3, 0.3, 0.3, 0.3, 0.7, 1.3, 2.0, 4.7,  8.2, 12.4, 14.2, 16.6, 19.5, 21.0, 23.0, 25.6, 25.7, 25.8, 25.5),
    nalnl2_65 = c(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.2,  3.4,  7.3,  8.5, 10.2, 12.1, 13.5, 15.2, 18.0, 18.5, 18.9, 19.1),
    nalnl2_80 = c(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,  0.0,  0.2,  0.8,  1.7,  2.7,  3.5,  4.6,  7.0,  7.7,  8.6,  9.3),
    # Legacy 6-freq fields kept for backward compatibility (interpolated from fine grid at 65 dB)
    nalnl2 = c(0.0, 0.0, 7.3, 12.1, 18.0, 19.1),
    dsl = c(18, 25, 26, 24, 20, 15),
    cameq2 = c(20, 19, 25, 27, 28, 38),
    cr_nalnl2 = c(2.6, 3.4, 2.6, 2.35, 2.1, 1.9)
  ),
  "a2" = list(
    freq = c(125, 160, 200, 250, 315, 400, 500, 630, 800, 1000, 1250, 1600, 2000, 2500, 3150, 4000, 5000, 6300, 8000),
    threshold = c(60, 50, 40, 30, 20, 15),
    nalnl2_50 = c(15.8, 15.8, 15.8, 15.8, 16.2, 16.7, 17.3, 17.7, 18.2, 18.7, 17.6, 16.0, 14.2, 11.8,  8.8,  8.6,  8.1,  7.4,  6.6),
    nalnl2_65 = c(10.1, 10.1, 10.1, 10.1,  9.9,  9.6,  9.3, 10.1, 11.1, 12.2, 11.3,  9.9,  8.3,  6.5,  4.0,  3.9,  4.0,  4.0,  4.0),
    nalnl2_80 = c( 0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  1.4,  3.2,  2.5,  1.5,  0.3,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0),
    nalnl2 = c(10.1, 9.3, 12.2, 8.3, 3.9, 4.0),
    dsl = c(24, 19, 15, 8, 4, 3),
    cameq2 = c(28, 28, 28, 20, 0, 0),
    cr_nalnl2 = c(2.5, 2.0, 1.5, 1.0, 1.0, 1.0)
  ),
  "a3" = list(
    freq = c(125, 160, 200, 250, 315, 400, 500, 630, 800, 1000, 1250, 1600, 2000, 2500, 3150, 4000, 5000, 6300, 8000),
    threshold = c(10, 20, 40, 50, 55, 60),
    nalnl2_50 = c(0.0,  0.0,  0.0,  0.0,  0.5,  1.5,  2.7,  6.2, 10.6, 15.9, 18.0, 21.0, 24.4, 25.3, 26.5, 28.2, 28.2, 28.1, 27.8),
    nalnl2_65 = c(0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  1.2,  5.2,  9.9, 11.6, 14.1, 16.8, 17.7, 18.8, 20.7, 21.0, 21.4, 21.6),
    nalnl2_80 = c(0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  1.9,  3.1,  4.7,  6.5,  7.0,  7.7,  9.3, 10.0, 10.8, 11.5),
    nalnl2 = c(0.0, 0.0, 9.9, 16.8, 20.7, 21.6),
    dsl = c(8, 20, 27, 26, 19, 8),
    cameq2 = c(12, 12, 24, 28, 27, 40),
    cr_nalnl2 = c(1.2, 1.8, 2.4, 2.4, 1.8, 1.2)
  ),
  "a4" = list(
    freq = c(125, 160, 200, 250, 315, 400, 500, 630, 800, 1000, 1250, 1600, 2000, 2500, 3150, 4000, 5000, 6300, 8000),
    threshold = c(0, 0, 10, 40, 70, 80),
    nalnl2_50 = c(0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.6,  3.1,  7.1, 12.8, 19.2, 21.9, 25.4, 27.8, 27.6, 27.3, 26.6),
    nalnl2_65 = c(0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.9,  3.8,  7.8, 12.5, 15.2, 18.8, 21.8, 22.0, 22.1, 21.8),
    nalnl2_80 = c(0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.8,  3.0,  5.3,  8.3, 11.3, 11.8, 12.3, 12.6),
    nalnl2 = c(0.0, 0.0, 0.9, 12.5, 21.8, 21.8),
    dsl = c(0, 0, 3, 20, 38, 35),
    cameq2 = c(10, 10, 15, 25, 30, 60),
    cr_nalnl2 = c(1.0, 1.0, 1.65, 2.0, 2.1, 1.9)
  ),
  "a5" = list(
    freq = c(125, 160, 200, 250, 315, 400, 500, 630, 800, 1000, 1250, 1600, 2000, 2500, 3150, 4000, 5000, 6300, 8000),
    threshold = c(10, 10, 20, 60, 80, 100),
    nalnl2_50 = c(0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  1.9,  6.2, 11.3, 15.1, 20.6, 26.8, 28.4, 30.5, 32.1, 31.9, 31.5, 30.9),
    nalnl2_65 = c(0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  2.8,  6.6, 10.1, 15.0, 20.7, 22.6, 25.0, 27.1, 27.1, 27.0, 26.6),
    nalnl2_80 = c(0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.2,  2.9,  6.7, 11.0, 12.7, 14.9, 17.2, 17.4, 17.7, 17.7),
    nalnl2 = c(0.0, 0.0, 6.6, 20.7, 27.1, 26.6),
    dsl = c(0, 0, 15, 30, 25, 25),
    cameq2 = c(10, 10, 25, 45, 60, 65),
    cr_nalnl2 = c(1.0, 1.0, 2.0, 2.5, 2.1, 1.9)
  ),
  "a6" = list(
    freq = c(125, 160, 200, 250, 315, 400, 500, 630, 800, 1000, 1250, 1600, 2000, 2500, 3150, 4000, 5000, 6300, 8000),
    threshold = c(50, 55, 60, 65, 75, 80),
    loss = c(30, 30, 30, 30, 30, 30),
    nalnl2_50 = c(28.0, 28.0, 28.0, 28.0, 28.4, 28.9, 29.5, 31.6, 34.4, 37.7, 38.8, 40.5, 42.3, 43.6, 45.4, 48.2, 48.3, 48.4, 48.2),
    nalnl2_65 = c(22.5, 22.5, 22.5, 22.5, 22.9, 23.5, 24.2, 26.4, 29.4, 32.9, 33.6, 34.5, 35.6, 36.9, 38.4, 41.4, 41.8, 42.3, 42.6),
    nalnl2_80 = c(20.7, 20.7, 20.7, 20.7, 20.7, 20.7, 20.7, 22.1, 24.0, 26.3, 26.5, 26.9, 27.3, 28.1, 29.1, 31.6, 32.3, 33.2, 33.9),
    nalnl2 = c(22.5, 24.2, 32.9, 35.6, 41.4, 42.6),
    dsl = c(32, 35, 43, 35, 35, 38),
    cameq2 = c(48, 48, 52, 43, 48, 52),
    cr_nalnl2 = c(2.0, 2.2, 2.5, 2.5, 2.1, 1.9)
  ),
  "a7" = list(
    # Pure conductive loss (ABG = 50 dB across all frequencies)
    # NAL-NL2 gains are nearly identical across input levels (linear amplification, CR ~ 1.0)
    freq = c(125, 160, 200, 250, 315, 400, 500, 630, 800, 1000, 1250, 1600, 2000, 2500, 3150, 4000, 5000, 6300, 8000),
    threshold = c(50, 50, 50, 50, 50, 50),
    loss = c(50, 50, 50, 50, 50, 50),
    nalnl2_50 = c(34.7, 34.7, 34.7, 34.7, 34.7, 34.7, 34.6, 34.6, 34.7, 34.7, 34.7, 34.7, 34.8, 34.8, 34.9, 35.1, 35.1, 35.1, 35.1),
    nalnl2_65 = c(34.7, 34.7, 34.7, 34.7, 34.7, 34.7, 34.6, 34.6, 34.7, 34.7, 34.7, 34.7, 34.8, 34.8, 34.9, 35.0, 35.0, 35.1, 35.1),
    nalnl2_80 = c(34.7, 34.7, 34.7, 34.7, 34.7, 34.7, 34.6, 34.6, 34.7, 34.7, 34.7, 34.7, 34.8, 34.8, 34.9, 35.0, 35.0, 35.1, 35.1),
    nalnl2 = c(34.7, 34.6, 34.7, 34.8, 35.0, 35.1),
    dsl = c(30, 30, 37, 34, 32, 31),
    cameq2 = c(40, 40, 45, 43, 40, 40),
    cr_nalnl2 = c(1.0, 1.0, 1.0, 1.0, 1.0, 1.0)
  )

)

# Helper function to get an interpolated gain vector for any given frequency array
get_nalnl2_v2_target <- function(preset, formula, target_freqs, level = 65) {
  if (!(preset %in% names(jd2011_targets))) return(NULL)

  data <- jd2011_targets[[preset]]
  if (formula == "NAL-NL2") {
    # Use fine-frequency multi-level data if available (preferred)
    if (!is.null(data$nalnl2_65) && !is.null(data$nalnl2_50) && !is.null(data$nalnl2_80)) {
      if (level == 65) {
        y <- data$nalnl2_65
      } else if (level == 50) {
        y <- data$nalnl2_50
      } else if (level == 80) {
        y <- data$nalnl2_80
      } else {
        # Interpolate between levels using available data
        if (level < 65) {
          frac <- (level - 50) / 15
          y <- data$nalnl2_50 + frac * (data$nalnl2_65 - data$nalnl2_50)
        } else {
          frac <- (level - 65) / 15
          y <- data$nalnl2_65 + frac * (data$nalnl2_80 - data$nalnl2_65)
        }
      }
      return(approx(x = log10(data$freq), y = y, xout = log10(target_freqs), rule = 2)$y)
    }
    # Legacy 6-freq fallback
    y  <- data$nalnl2
    cr <- data$cr_nalnl2
  } else if (formula == "DSL") {
    y  <- data$dsl
    cr <- pmax(1.0, data$cr_nalnl2 * 0.85)
  } else if (formula == "CAMEQ2-HF") {
    y  <- data$cameq2
    cr <- pmax(1.0, data$cr_nalnl2 * 0.90)
  } else {
    return(NULL)
  }

  # Apply WDRC gain shift if level is not 65 dB SPL (legacy path only)
  if (level != 65) {
    y <- y + (level - 65) * (1 / cr - 1)
  }

  # Interpolate to the target frequencies
  approx(x = log10(data$freq), y = y, xout = log10(target_freqs), rule = 2)$y
}

Try the SII package in your browser

Any scripts or data that you put into this service are public.

SII documentation built on Sept. 12, 2026, 5:08 p.m.