Skip to content

Repository files navigation

frc-opr

frc-opr logo

CI License: MIT

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-opr

30-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

I built this after needing the same rating math in FRC scouting dashboards and small Node scripts. OPR and its relatives are computed by least squares over the alliance-membership matrix, but most reusable implementations are Java or Python, so teams end up pasting one-off solvers into their frontends. frc-opr keeps that solve small, tested, and 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 a Map from team key to rating.
  • defensivePowerRatings(matches) returns a Map<string, number> of DPR per team. Equivalent to the dpr field of powerRatings, but as a focused function when you only need DPR.
  • winningMarginRatings(matches) returns a Map<string, number> of CCWM per team. Equivalent to the ccwm field of powerRatings, 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, approaching powerRatings as ridge approaches 0.
  • fromTbaMatches(tbaMatches) converts The Blue Alliance match objects into Match values, 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 example

Testing

npm test

Tests 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.

About

Compute FRC power ratings (OPR, DPR, CCWM) from match data by least squares. Typed, zero dependencies, browser and Node.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages