Preprocessing

Spectrum subtraction, smoothing, normalization, and related utilities.

Spectrum Subtraction

OpticalSpectroscopy.subtract_spectrumFunction
subtract_spectrum(sample, reference; scale=1.0, interpolate=false)

Subtract a reference spectrum from a sample spectrum.

Accepts AbstractSpectroscopyData types (uses xdata/ydata interface) or any objects with .x and .y fields.

Returns (x=..., y=...) NamedTuple.

source
subtract_spectrum(s::Spectrum, ref::Spectrum; scale=1.0, interpolate=false) -> Spectrum

Subtract ref from s. Returns a new Spectrum carrying s's shallow-copied metadata.

source

Smoothing

OpticalSpectroscopy.smooth_dataFunction
smooth_data(y; window=3)

Apply moving average smoothing to data.

source
smooth_data(s::Spectrum; window=3) -> Spectrum

Moving-average smoothing of a Spectrum. Returns a new Spectrum with shallow-copied metadata.

source
OpticalSpectroscopy.savitzky_golay_smoothFunction
savitzky_golay_smooth(y; window=11, order=3)

Apply Savitzky-Golay smoothing filter to data.

Uses polynomial fitting within a sliding window to smooth data while preserving peak shape and width better than moving-average smoothing (Savitzky & Golay, 1964).

Arguments

  • y::AbstractVector{<:Real}: Input data vector.

Keywords

  • window::Int=11: Window size (must be odd and ≥ order + 2).
  • order::Int=3: Polynomial order for the local fit.

Returns

  • Vector{Float64}: Smoothed data vector (same length as input).

Examples

y_noisy = sin.(0:0.1:2π) .+ 0.1 * randn(63)
y_smooth = savitzky_golay_smooth(y_noisy; window=11, order=3)
source
savitzky_golay_smooth(s::Spectrum; window=11, order=3) -> Spectrum

Savitzky-Golay smoothing of a Spectrum. Returns a new Spectrum with shallow-copied metadata.

source

Derivatives

OpticalSpectroscopy.derivativeFunction
derivative(y; order=1, window=11, poly_order=3)
derivative(x, y; order=1, window=11, poly_order=3)

Compute the derivative of a signal using Savitzky-Golay differentiation.

When x is provided, the derivative is correctly scaled by the x-spacing (using the median point spacing as the rate parameter).

Arguments

  • x::AbstractVector{<:Real}: (optional) Independent variable (e.g., wavenumber, wavelength).
  • y::AbstractVector{<:Real}: Signal to differentiate.

Keywords

  • order::Int=1: Derivative order (1 = first derivative, 2 = second, etc.).
  • window::Int=11: Savitzky-Golay window size (must be odd, ≥ poly_order + 2).
  • poly_order::Int=3: Polynomial order for the SG filter (must be ≥ order).

Returns

  • Vector{Float64}: Derivative of the input signal.

Examples

x = 400.0:0.5:800.0
y = @. 100 * exp(-(x - 520)^2 / (2 * 20^2))
dy = derivative(x, y; order=1)          # First derivative (correctly scaled)
d2y = derivative(x, y; order=2)         # Second derivative
source
derivative(s::Spectrum; order=1, window=11, poly_order=3) -> Spectrum

Savitzky-Golay derivative of a Spectrum, scaled by the x-spacing. Returns a new Spectrum with shallow-copied metadata, retagged with the :derivative signal token (the original y-quantity no longer applies).

source

Normalization and Band Analysis

OpticalSpectroscopy.band_areaFunction
band_area(x, y, x_min, x_max)
band_area(spec, x_min, x_max)

Compute the integrated area under a spectrum within a given range using trapezoidal integration.

The spec form accepts any 1D AbstractSpectroscopyData (uses xdata/ydata).

Arguments

  • x::AbstractVector{<:Real}: x-axis values (e.g., wavenumber, wavelength).
  • y::AbstractVector{<:Real}: y-axis values (e.g., intensity).
  • x_min::Real: Lower bound of integration range.
  • x_max::Real: Upper bound of integration range.

Returns

  • Float64: Integrated area.

Examples

x = 400.0:0.5:800.0
y = @. 100 * exp(-(x - 520)^2 / (2 * 10^2))
area = band_area(x, y, 480.0, 560.0)
source
OpticalSpectroscopy.normalize_areaFunction
normalize_area(x, y)

Normalize a spectrum so its total integrated area equals 1.

Arguments

  • x::AbstractVector{<:Real}: x-axis values.
  • y::AbstractVector{<:Real}: y-axis values.

Returns

  • Vector{Float64}: Area-normalized y-values.

Examples

x = 1.0:0.1:10.0
y = ones(length(x))
y_norm = normalize_area(x, y)  # Total area ≈ 1.0
source
normalize_area(s::Spectrum) -> Spectrum

Normalize a Spectrum to unit integrated area. Returns a new Spectrum with shallow-copied metadata, retagged with the :normalized_intensity signal token (the original y-unit no longer applies).

source
OpticalSpectroscopy.normalize_to_peakFunction
normalize_to_peak(x, y, position; tolerance=5.0)

Normalize a spectrum by dividing by the intensity at a specified peak position.

Finds the data point nearest to position within tolerance and divides the entire spectrum by that point's intensity.

Arguments

  • x::AbstractVector{<:Real}: x-axis values.
  • y::AbstractVector{<:Real}: y-axis values.
  • position::Real: Target x-position for normalization (e.g., 520 cm-1 for Si).

Keywords

  • tolerance::Real=5.0: Maximum allowed distance from position to nearest data point.

Returns

  • Vector{Float64}: Peak-normalized y-values.

Examples

x = 400.0:1.0:800.0
y = @. 50 * exp(-(x - 520)^2 / (2 * 10^2))
y_norm = normalize_to_peak(x, y, 520.0)  # y at x≈520 becomes 1.0
source
normalize_to_peak(s::Spectrum, position; tolerance=5.0) -> Spectrum

Normalize a Spectrum to the intensity at position. Returns a new Spectrum with shallow-copied metadata, retagged with the :normalized_intensity signal token (the original y-unit no longer applies).

source
OpticalSpectroscopy.estimate_snrFunction
estimate_snr(y)
estimate_snr(spec)

Estimate the signal-to-noise ratio using the DER-SNR method.

The spec form accepts any 1D AbstractSpectroscopyData (signal comes from ydata).

Uses the second-order finite difference of adjacent pixels to estimate noise (Stoehr et al., 2008, "DER_SNR: A Simple & General Spectroscopic Signal-to-Noise Measurement Algorithm").

Arguments

  • y::AbstractVector{<:Real}: Spectral intensity values.

Returns

  • NamedTuple{(:snr, :signal, :noise)}: Estimated SNR, signal level, and noise level.

Examples

y_clean = 100 * ones(100)
y_noisy = y_clean .+ 2 * randn(100)
result = estimate_snr(y_noisy)
result.snr  # ≈ 50
source