frc-opr
v0.3.0
Published
Compute FRC power ratings (OPR, DPR, CCWM) from match data by least squares. Typed, zero dependencies, browser and Node.
Maintainers
Readme
frc-opr
Compute FRC power ratings (OPR, DPR, CCWM) from match data by least squares. Typed, zero runtime dependencies, runs in the browser and in Node.
Install
npm install frc-opr30-second example
import { powerRatings } from "frc-opr";
const { opr, dpr, ccwm } = powerRatings([
{ red: ["111", "222", "333"], blue: ["444", "555", "666"], redScore: 88, blueScore: 64 },
{ red: ["111", "444", "555"], blue: ["222", "333", "666"], redScore: 95, blueScore: 71 },
// ... the rest of the qualification matches
]);
opr.get("111"); // estimated points team 111 contributes
dpr.get("111"); // estimated points it allows the opponent
ccwm.get("111"); // contribution to winning margin (OPR minus DPR)Why this exists
OPR and its relatives are the standard derived statistics in FRC scouting, computed by
least squares over the alliance-membership matrix. Scouting tools are almost all web
apps, but the only reusable implementations are Java and Python scripts, so teams paste
ad hoc least-squares code into their frontends. frc-opr is the first TypeScript library
for it: a correct, tested solve with no dependencies, usable directly in a dashboard.
Comparison
| | frc-opr | Java / Python scripts | Statbotics API | |---|:---:|:---:|:---:| | Language | TypeScript | Java, Python | service | | Runs in the browser | yes | no | n/a (network) | | Works on your own match data | yes | yes | no, serves its own | | Zero dependencies | yes | varies | n/a | | OPR, DPR, CCWM | yes | varies | EPA and more |
Statbotics is excellent for precomputed ratings over official events; frc-opr computes
ratings locally from whatever matches you give it, including practice or custom data.
API
powerRatings(matches)returns{ opr, dpr, ccwm }, each aMapfrom team key to rating.defensivePowerRatings(matches)returns aMap<string, number>of DPR per team. Equivalent to thedprfield ofpowerRatings, but as a focused function when you only need DPR.winningMarginRatings(matches)returns aMap<string, number>of CCWM per team. Equivalent to theccwmfield ofpowerRatings, but as a focused function when you only need CCWM. Guaranteed to equal OPR minus DPR elementwise (the linearity of the system ensures this).powerRatingsRidge(matches, ridge)is the ridge-regularized (MMSE) variant: it stays solvable on early-event data that is not yet well determined and biases ratings toward zero, approachingpowerRatingsasridgeapproaches 0.fromTbaMatches(tbaMatches)converts The Blue Alliance match objects intoMatchvalues, skipping matches that have not been played.solve(matrix, b),luDecompose(matrix),luSolve(factorization, b): the dense linear solver, exported for reuse.
A Match is { red: string[], blue: string[], redScore: number, blueScore: number }.
Team keys are any non-empty strings.
DPR and CCWM in depth
DPR and CCWM solve the same normal-equations system as OPR, differing only in the right-hand side:
| Rating | Right-hand side per alliance appearance | |--------|----------------------------------------| | OPR | own alliance score | | DPR | opponent alliance score | | CCWM | own score minus opponent score (margin) |
Because the margin is the difference of the other two right-hand sides, CCWM = OPR - DPR
holds elementwise for every team. winningMarginRatings builds the margin right-hand side
directly and verifies this identity in the test suite to within 1e-9.
The math
Each alliance appearance gives one equation: the sum of its members' ratings equals the
alliance score (OPR) or the opponent score (DPR). That overdetermined system is solved
through its normal equations, whose matrix is the symmetric team co-appearance matrix.
OPR and DPR share that matrix, so it is factorized once. CCWM is OPR minus DPR, and the
CCWM values over an event sum to zero. If the data is rank-deficient (too few matches to
separate teams), powerRatings throws a clear error rather than returning unstable
numbers.
Roadmap
- Component ratings from labeled score breakdowns.
Examples
npm run exampleTesting
npm testTests cover exact recovery of known ratings from consistent synthetic events, the CCWM = OPR - DPR identity, the zero-sum CCWM property, solver unit tests, and the rank-deficient error path.
Contributing
Issues and pull requests are welcome. See CONTRIBUTING.md.
License
MIT. See LICENSE.
