Site Background Concentrations

Background Concentration Formula Guidance

This document explains how TypeScript-based formulas can be used to calculate background concentration values dynamically. It covers the purpose of background concentration formulas, the calculation workflow, available utility methods, common use cases, fallback strategies, validation checks, and implementation guidance for reliable background calculations.

The Background Concentration Formula feature allows you to create custom TypeScript functions that dynamically calculate the background concentration for a chemical analyte. Instead of storing a fixed background value, you can define logic that computes the appropriate concentration from nominated reference locations, historical results, selected percentiles, non-detect handling rules, and qualifier exclusions.

Pre-Requisites

Formulas are written in TypeScript (a form of JavaScript).  You should become familiar with TypeScript prior to attempting to create your own formulas.   ESdat Support offers a fee-based service to create formulas for organizations that don't have this capability.

How It Works

  • You write a calculate() function that receives a CalculationContext containing the current sample and background concentration being evaluated.
  • Your function uses utility methods to retrieve historical results for a selected location, calculate percentiles, and apply non-detect or qualifier handling rules.
  • Your function returns a BackgroundCalculationResult with the calculated concentration, unit, and description.

Why Use Background Concentration Formulas?

ScenarioWithout FormulaWith Formula
Percentile-based baselineCalculate percentiles manually from exported historical resultsFormula calculates the selected percentile from qualifying historical results
Average background concentrationManually average recent results and update the background valueFormula retrieves recent qualifying results and calculates the average automatically
Site-specific thresholdMaintain separate static background values for each location or reference areaFormula compares the current sample against data from the nominated reference location
Non-detect and qualifier handlingApply exclusions or substitutions manually outside the systemFormula applies configured non-detect and qualifier rules consistently during calculation

Key Concepts

Data Retrieval

Background concentration formulas retrieve historical chemistry data through utility methods on the Utils class. The main retrieval methods support recent-result lookups, percentiles, selected reference locations, total-or-filtered basis, matrix type, non-detect handling, and qualifier exclusions.

  • getNPreviousResultsForLocation() — retrieves qualifying historical result values for a selected location and chemical code.
  • getNPreviousPercentileResultsForLocation() — calculates a percentile from qualifying historical results using the same lookup criteria.

Result Structure

Each background concentration formula returns a result object that communicates both the calculated value and how it was derived.

  • Concentration — the calculated background concentration, or null if a value cannot be calculated.
  • Unit — the unit of measurement returned with the calculated concentration.
  • Description — a human-readable explanation of the calculation, assumptions, exclusions, and fallback handling.
  • Options — controls whether non-detects are excluded or substituted and which qualifiers are excluded.

Best Practices

  • Specify the reference location explicitly rather than assuming the current sample location should be used.
  • Handle missing or insufficient historical data gracefully by returning null with a clear description.
  • Document how non-detects and qualifiers are handled, especially when substituting non-detect values or excluding rejected results.
  • Use the unit, matrix type, and total-or-filtered basis expected by the background concentration record.
  • Keep formulas simple, readable, and easy to review by using descriptive constants and clear result descriptions.
  • Validate formulas against edge cases such as no historical data, few qualifying results, all non-detects, or changed site conditions.

Users define the calculation logic by editing the calculate() function. The system runs this function automatically whenever a background concentration is evaluated.

Utility Function Reference

Utils.getNPreviousResultsForLocation(params)

Retrieves the specified number of most recent qualifying historical result values for a location and chemical code.

Utils.getNPreviousResultsForLocation({  SampleDateTime: Date,  LocationCode: string,  Well?: string | null,  ChemCode: ChemCode,  Unit: string,  TotalOrFiltered?: 'T' | 'F',  MatrixType?: string | null,  NumberOfResults: number,  Options?: Options }): number[]

Utils.getNPreviousPercentileResultsForLocation(params)

Calculates a percentile from the qualifying historical results returned by the same lookup criteria used by getNPreviousResultsForLocation.

Utils.getNPreviousPercentileResultsForLocation({  SampleDateTime: Date,  LocationCode: string,  Well?: string | null,  ChemCode: ChemCode,  Unit: string,  TotalOrFiltered?: 'T' | 'F',  MatrixType?: string | null,  NumberOfResults: number,  Percentile: number,  Method?: PercentileMethod,  Options?: Options }): number | null

Available percentile methods:

'R1' | 'EmpiricalInvCDF' | 'SAS3' | 'R2' | 'EmpiricalInvCDFAverage' | 'SAS5' | 'R3' | 'Nearest' | 'SAS2' | 'R4' | 'California' | 'SAS1' | 'R5' | 'Hazen' | 'Hydrology' | 'R6' | 'Weibull' | 'Nist' | 'SPSS' | 'SAS4' | 'R7' | 'Excel' | 'Mode' | 'S' | 'R8' | 'Median' | 'Default' | 'R9' | 'Normal'

Options Object

Controls how non-detect results and qualifier codes are handled before historical values are returned or used in percentile calculations.

Options: {  ExcludeNonDetects?: boolean,  ExcludeQualifiers?: string[],  NonDetectMultiplier?: number }

Formula Development Guidance

1. Select the Reference Location

Important: The sample's own Location_Code and Well are available in the context, but do not assume they should be used unless you specifically want to compare against that same location's history.

  • A nominated reference/background well
  • A composite of multiple background locations
  • A regulatory standard or fixed value

The user should explicitly specify which location code to use.

2. Handle Non-Detects Appropriately

  • Exclude them entirely using ExcludeNonDetects: true.
  • Use a substitution multiplier such as NonDetectMultiplier: 0.5 for DL/2.
  • ExcludeNonDetects takes precedence over NonDetectMultiplier.
MethodMultiplier
Replace with 0Not directly supported
Replace with DL/2NonDetectMultiplier: 0.5
Replace with DL/√2Not directly supported

3. Filter by Qualifiers

  • 'R' — Rejected
  • 'J' — Estimated value
  • 'UJ' — Estimated non-detect

Multiple qualifiers on a single result are semicolon-delimited, such as "J;R".

4. Choose an Appropriate Sample Count

  • Too few samples may not be statistically meaningful.
  • Too many samples may include data from different site conditions.
  • Typical range: 10–20 samples.
  • Consider seasonality.
  • Ensure sufficient older data exists.

5. Unit Conversion Awareness

  • Always specify the correct Unit.
  • Always use the unit expected by the background concentration record.
  • Common units: mg/L, µg/L, mg/kg, µg/kg.

6. Keep Formulas Simple

  • Simple percentile calculations.
  • One utility call when possible.
  • Descriptive variable names.

7. Check for Null Results Before Returning a Calculated Concentration

if (concentration != null) {  return {    Concentration: concentration,    Unit: UNIT,    Description: '...'  } } return {  Concentration: null,  Unit: UNIT,  Description: 'No historical data available' }

8. Common Patterns and Recipes

Fixed Value Background

return {  Concentration: 0.5,  Unit: 'mg/L',  Description: 'Fixed background concentration' }

Simple Average of Last N Results

Use getNPreviousResultsForLocation and calculate the average manually.

Percentile With Exclusions

Utils.getNPreviousPercentileResultsForLocation({  Options: {    ExcludeNonDetects: true,    ExcludeQualifiers: ['R', 'J']  } })

9. Validation Checklist

  • Handle cases where no historical data exists.
  • Consider very few results.
  • Verify filtered and total results.
  • Verify different matrix types.

Best Practices Checklist

Use this checklist after selecting the utility method and calculation approach.

1. Use Descriptive Constants at the Top

const UNIT = 'mg/L' const SAMPLES = 15 const PERCENTILE = 95 const REFERENCE_LOCATION = 'BG-01'

2. Exclude Rejected Data

Options: {  ExcludeQualifiers: ['R'] }

3. Document Non-Detect Handling

Options: {  NonDetectMultiplier: 0.5,  ExcludeQualifiers: ['R'] }

4. Validate Before Using Returned Values

const concentration = Utils.getNPreviousPercentileResultsForLocation({}) if (concentration == null) {  return {    Concentration: null,    Unit: UNIT,    Description: 'Insufficient historical data for calculation'  } }

5. Use Meaningful Descriptions

Description: `95th percentile of last ${SAMPLES} results at ${REFERENCE_LOCATION}` Description: `80th percentile at ${REFERENCE_LOCATION} (non-detects replaced with DL/2)`

6. Choose the Right Percentile Method

ScenarioRecommended Method
General environmental dataR8
Regulatory compliance (Excel-compatible)Excel
Hydrological/water quality dataHazen or Hydrology

7. Consider Sample-Size Requirements

  • Minimum of 10 samples.
  • 15-20+ samples preferred.
  • Fewer than 5 samples may require an alternative approach.

8. Match Units to Historical Data

Always use the unit that matches your historical results.

9. Keep Formulas Simple

  • One utility call when possible.
  • Simple arithmetic.
  • Clear linear logic.

10. Be Explicit About Limitations

Document limitations and handle known constraints gracefully.

11. Consider Matrix and Basis

Use Matrix_Type and Total_or_Filtered to ensure comparable results.

12. Test Edge Cases

  • No historical data exists.
  • All historical results are non-detects.
  • Location has changed over time.
  • Chemical is not commonly detected.

Write formulas that handle these gracefully rather than crashing or returning misleading values.