ScoreCalibration

Calibration of raw evaluation scores into the score a session reports.

Raw scores from the segment scorer are algorithm output: they cluster high and thin out at the bottom, which reads unfairly to a learner. Calibration is the perceptual curve that turns algorithm output into the score users see — and per ADR-023 ("the 0-100 / 0-1 score from a documented curve"), the curve is VoxaTrace's to own and document, while banding the calibrated score into stars/colors/verdicts stays the client's.

One currency (ADR-026)

The session applies the configured calibration exactly once, at the scoring seam. Everything called "score" — per-segment results, the session score, and the SessionConfig.scoreThreshold the auto-advance policy compares against — is in calibrated units. Measurements (pitch-accuracy ratio, cents, durations) stay raw: they are facts, not scores.

Presets

All presets share one sigmoid template, `0.5·(tanh(3.4·r − b₁) + tanh(3.7·r

  • b₂))`, differing only in the shifts b₁/b₂ — which guarantees the family never crosses: for every raw input, LENIENT ≥ BALANCED ≥ STRICT.

rawLENIENTBALANCEDSTRICT
0.30.460.270.14
0.50.780.620.41
0.70.930.860.74
1.00.990.980.96

BALANCED is bit-identical to the curve Riyaz has shipped for years (including its quirk that a perfect take reads ~0.98, kept so client score history stays comparable). IDENTITY is the default: no consumer's numbers change without opting in.

Custom curves are validated at construction (ADR-022): monotonic non-decreasing over 0..1 and finite everywhere; a broken curve fails at create, not via strange scores mid-session.

Types

Link copied to clipboard
object Companion

Properties

Link copied to clipboard

Functions

Link copied to clipboard
fun apply(rawScore: Float): Float

Calibrate a raw score. Sentinels (negative values, e.g. not-practiced) pass through untouched; valid scores are curved, then clamped to 0..1.

Link copied to clipboard
open override fun toString(): String