{
  "schemaVersion": 1,
  "slug": "cycling-cadence-calculator",
  "category": "sports",
  "kind": "implementation",
  "independentValidation": false,
  "implementationHash": "f2a1cee1343e1095bf97251f1a238fdb9250ce4d4324d0e58888a8f9a0c124bb",
  "provenance": "Generated from the calculation contract used by the published page. Publication is not external validation.",
  "sourceFiles": [
    "data/calculators/cycling-cadence-calculator.json",
    "src/engine.js"
  ],
  "runtimeSource": "/sources/engine.txt",
  "runtimeHash": "5c888d8898afbdee36267bb9977829e1e2ac568f6677c8ee87469c139864645c",
  "scope": "The compute function records implemented equations, constants, lookup tables and custom rules. Inputs record defaults and allowed values; outputs record precision and units. Defaults are examples, not recommendations. General background references are not evidence for this specific algorithm.",
  "publishedFormula": {
    "formula": "Cad = v × 1609.344 ÷ 60 ÷ (π × (D + 2t) ÷ 1000 × F ÷ R)",
    "vars": [
      [
        "v",
        "Speed (mph)"
      ],
      [
        "D",
        "Rim diameter (mm)"
      ],
      [
        "t",
        "Tire width (mm)"
      ],
      [
        "F",
        "Front chainring teeth"
      ],
      [
        "R",
        "Rear sprocket teeth"
      ]
    ],
    "note": "Rim presets: 700c/29″ = 622, 650b = 584, 26″ = 559, 20″ = 406; speed at target cadence = Cad × development × 60 ÷ 1609.344."
  },
  "externalEvidence": null,
  "contract": {
    "compute": "const R={'700c':622,'650b':584,'26':559,'29':622,'20':406},rim=R[wheelSize];if(!rim||!Number.isFinite(tireWidth)||tireWidth<=0||!Number.isInteger(frontTeeth)||!Number.isInteger(rearTeeth)||frontTeeth<=0||rearTeeth<=0||!Number.isFinite(speed)||speed<=0||!Number.isFinite(targetCadence)||targetCadence<=0)return{cadence:null,gearRatio:null,development:null,speedAtTarget:null,rearTeethForTarget:null,__error:'inputError'};const diameter=(rim+tireWidth*2)/1000,circumference=Math.PI*diameter,ratio=frontTeeth/rearTeeth,development=circumference*ratio,cadence=development>0?speed*1609.344/60/development:null,speedAtTarget=targetCadence*development/1609.344*60,rearTeethForTarget=frontTeeth/(speed*1609.344/60/targetCadence/circumference);return{cadence,gearRatio:ratio,development,speedAtTarget,rearTeethForTarget};",
    "inputs": [
      {
        "name": "speed",
        "type": "number",
        "default": 18,
        "min": 0.5,
        "max": 60,
        "step": 0.5,
        "slider": true
      },
      {
        "name": "frontTeeth",
        "type": "number",
        "default": 50,
        "min": 20,
        "max": 60,
        "step": 1,
        "slider": true
      },
      {
        "name": "rearTeeth",
        "type": "number",
        "default": 17,
        "min": 10,
        "max": 40,
        "step": 1,
        "slider": true
      },
      {
        "name": "wheelSize",
        "type": "select",
        "default": "700c",
        "options": [
          {
            "value": "700c"
          },
          {
            "value": "650b"
          },
          {
            "value": "26"
          },
          {
            "value": "29"
          },
          {
            "value": "20"
          }
        ]
      },
      {
        "name": "tireWidth",
        "type": "number",
        "default": 25,
        "min": 18,
        "max": 70,
        "step": 1,
        "slider": true
      },
      {
        "name": "targetCadence",
        "type": "number",
        "default": 90,
        "min": 50,
        "max": 130,
        "step": 1,
        "slider": true
      }
    ],
    "outputs": [
      {
        "name": "cadence",
        "precision": 1,
        "unit": "rpm"
      },
      {
        "name": "gearRatio",
        "precision": 2,
        "unit": ""
      },
      {
        "name": "development",
        "precision": 2,
        "unit": "m"
      },
      {
        "name": "speedAtTarget",
        "precision": 1,
        "unit": "mph"
      },
      {
        "name": "rearTeethForTarget",
        "precision": 1,
        "unit": ""
      }
    ],
    "interpret": null
  }
}
