///|
pub(all) struct QualityMetrics {
samples : Int32
minimum : Double
maximum : Double
mean : Double
deviation : Double
rms : Double
negative_fraction : Double
first_difference_mad : Double
curvature_rms : Double
uniform_axis : Bool
}
///|
/// Descriptive QA metrics, not a detector of chemical identity or noise truth.
/// First differences and curvature are in sample-index coordinates.
pub fn quality(input : Spectrum) -> QualityMetrics raise SpectralError {
let y = input.values
let n = y.length()
let mut minimum = y[0]
let mut maximum = y[0]
let mut negatives = 0
let differences = Array::make(n - 1, 0.0)
let curvature = Array::make(n - 2, 0.0)
for i in 0.. maximum {
maximum = y[i]
}
if y[i] < 0.0 {
negatives = negatives + 1
}
if i >= 1 {
differences[i - 1] = y[i] - y[i - 1]
}
if i >= 2 {
curvature[i - 2] = y[i] - 2.0 * y[i - 1] + y[i - 2]
}
}
{
samples: n,
minimum,
maximum,
mean: mean(y),
deviation: sample_deviation(y),
rms: root_mean_square(y),
negative_fraction: negatives.to_double() / n.to_double(),
first_difference_mad: median_absolute_deviation(differences),
curvature_rms: root_mean_square(curvature),
uniform_axis: is_uniform_axis(input),
}
}
///|
/// Pearson correlation on exactly aligned axes; constant inputs are refused.
pub fn spectral_correlation(
left : Spectrum,
right : Spectrum,
) -> Double raise SpectralError {
require_same_axis(left, right, 0.0)
let a = snv(left).values
let b = snv(right).values
let mut product = 0.0
for i in 0.. 1.0 {
1.0
} else if value < -1.0 {
-1.0
} else {
value
}
}
///|
/// Spectral angle in radians; meaningful for nonzero aligned vectors.
pub fn spectral_angle(
left : Spectrum,
right : Spectrum,
) -> Double raise SpectralError {
require_same_axis(left, right, 0.0)
let a = unit_vector(left).values
let b = unit_vector(right).values
let mut cosine = 0.0
for i in 0.. 1.0 {
1.0
} else if cosine < -1.0 {
-1.0
} else {
cosine
}
@math.acos(bounded)
}