Last active
December 7, 2023 14:58
-
-
Save thomasvst/64379578a83e09a170f9607bf2d07c94 to your computer and use it in GitHub Desktop.
Collection of utility funtions around spoke length calculation in Javascript. Written by Thomas @ LH WHEELS (https://www.lhwheels.be/)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Compute the spoke length for one side of the wheel, based on the standard spoke length formula. | |
* | |
* Sample : spokeLength(593, 110, 2.5, 57.9, 26.8, 32, 3); | |
* | |
* @param erd the Effective Rim Diameter (ERD) | |
* @param spokeHoleDiameter the hub spoke hole dimater, in mm (usually 2.6) | |
* @param hubFlangeDiameter the diameter of the hub flange (from hole to hole) in mm | |
* @param hubFlangeToCenter the distante between the hub flange and the wheel center, taking the rim offset into account, in mm | |
* @param numberOfSpokes the total number of spoke used to buid the wheel (24, 28, 32) | |
* @param crossPattern the cross pattern (0, 1, 2, 3) | |
* | |
* @return the computed spoke length, rounded to 1 decimal place | |
* | |
* @author thomas@lhwheels.be | |
* @see https://www.wheelpro.co.uk/support/spoke-length-calculators/ | |
* @depreacted use spokeLengthV2 | |
*/ | |
function spokeLength(erd, spokeHoleDiameter, hubFlangeDiameter, hubFlangeToCenter, numberOfSpokes, crossPattern) { | |
var R = erd / 2; // Rim radius (half the ERD) | |
var H = hubFlangeDiameter / 2; // Hub flange radius | |
var F = hubFlangeToCenter; // Hub flange offset | |
var X = crossPattern; // Cross pattern | |
var h = numberOfSpokes; // Number of spokes in the wheel | |
var Ø = spokeHoleDiameter; // Diameter of the spoke hole in the hub | |
// var spokeLength = Math.sqrt((R * R) + (H * H) + (F * F) - 2 * R * H * Math.cos((4.0 * Math.PI * X) / h)) - (d / 2); | |
var spokeLength = Math.sqrt((R ** 2) + (H ** 2) + (F ** 2) - 2 * R * H * Math.cos((4.0 * Math.PI * X) / h)) - (Ø / 2); | |
return Math.round(spokeLength * 10) / 10; | |
} | |
/** | |
* Compute the spoke length for one side of a the wheel, based on the standard spoke length formula. | |
* | |
* Sample for straight pull spokes : spokeLengthV2('SP', 593, 2.5, 57.9, 26.8, 32, 3, 1.1); | |
* Sample for straight j-bend spokes : spokeLengthV2('JB', 593, 2.5, 57.9, 26.8, 32, 3, null); | |
* | |
* @param spokeType the spoke type : 'SP' for straight pull / 'JB' for J-Bend | |
* @param erd the Effective Rim Diameter in mm (ERD) | |
* @param spokeHoleDiameter the hub spoke hole dimater in mm (usually 2.6) | |
* @param hubFlangeDiameter the diameter of the hub flange (from hole to hole) in mm | |
* @param hubFlangeToCenter the distante between the hub flange and the wheel center, taking the rim offset into account, in mm | |
* @param numberOfSpokes the total number of spoke used to build the wheel (20, 24, 28, 32, 36 ...) | |
* @param crossPattern the cross pattern (0, 1, 2, 3) | |
* @param spokeHoleOffset the spoke hole offset (only apply when spoke type = 'SP' ) | |
* | |
* @return the computed spoke length, rounded to 1 decimal place | |
* | |
* @author thomas@lhwheels.be | |
* @see https://www.wheelpro.co.uk/support/spoke-length-calculators/ | |
* @see https://www.wheelpro.co.uk/wheelbuilding/book.php | |
* @depreacted use spokeLengthV3 | |
*/ | |
function spokeLengthV2(spokeType, erd, spokeHoleDiameter, hubFlangeDiameter, hubFlangeToCenter, numberOfSpokes, crossPattern, spokeHoleOffset) { | |
var R = erd / 2; // Rim radius (half the ERD) | |
var H = hubFlangeDiameter / 2; // Hub flange radius to spoke holes | |
var F = hubFlangeToCenter; // Hub flange offset | |
var X = crossPattern; // Cross pattern | |
if (spokeType == 'SP') { | |
X += 0.5; | |
} | |
var h = numberOfSpokes; // Number of spokes in the wheel | |
var Ø = spokeHoleDiameter; // Diameter of the spoke hole in the hub | |
spokeHoleOffset = crossPattern == 0 ? 0 : spokeHoleOffset; // always 0 for radial wheels | |
var spokeLength = Math.sqrt((R ** 2) + (H ** 2) + (F ** 2) - 2 * R * H * Math.cos((4.0 * Math.PI * X) / h)); | |
if (spokeType == 'JB') { | |
spokeLength -= (Ø / 2); | |
} else if (spokeType == 'SP') { | |
spokeLength += spokeHoleOffset; | |
} | |
return Math.round(spokeLength * 10) / 10; | |
} | |
function test_spokeLengthV2() { | |
console.log(spokeLengthV2('JB', 593, 2.5, 57.9, 26.8, 32, 3, null), "Spoke length should be 286.7"); | |
console.log(spokeLengthV2('SP', 593, 2.5, 57.9, 26.8, 32, 3, 1.1), "Spoke length should be 294.6"); | |
console.log(spokeLengthV2('JB', 603, 2.6, 42, 34.5, 24, 2, null), "Spoke length should be 292.3"); | |
} | |
/** | |
* Compute the elongation of a spoke. | |
* Based on the following formula : elongation in mm = (Spoketension in N / (pi * r^2)) / (GPa in N-mm2 / spoke length in mm) | |
* | |
* @param spokeTensionInKg the spoke tension in kg. Use 100kg as a midpoint tension if you don't kown what to use. | |
* @param spokeDiameter the spoke diameter in mm | |
* | |
* @see https://www.mtbr.com/threads/spoke-elongation-formula.1182122/ | |
*/ | |
function spokeElongation(spokeTensionInKg, spokeDiameter, spokeLength) { | |
let gpa = 205000; // based on the Young's modulus of 205000 N / mm2 (typical value for high strength stainless steel) | |
let spokeTensionInN = spokeTensionInKg * 9.81; | |
let spokeRadius = spokeDiameter / 2 | |
return (spokeTensionInN / (Math.PI * spokeRadius * spokeRadius)) / (gpa / spokeLength); | |
} | |
function test_spokeElongation() { | |
console.log(spokeElongation(79, 2, 290), "Elongation should be 0.3489"); | |
console.log(spokeElongation(100, 1.5, 292.3018), "Elongation should be 0.7915"); | |
} | |
/** | |
* Compute the spoke length for one side of a the wheel, based on the standard spoke length formula and taking spoke elongation into account. | |
* | |
* Sample for straight pull spokes : spokeLengthV3('SP', 593, 2.5, 57.9, 26.8, 32, 3, 1.1, 1.5); | |
* Sample for straight j-bend spokes : spokeLengthV3('JB', 593, 2.5, 57.9, 26.8, 32, 3, null, 1.5); | |
* | |
* @param spokeType the spoke type : 'SP' for straight pull / 'JB' for J-Bend | |
* @param erd the Effective Rim Diameter in mm (ERD) | |
* @param spokeHoleDiameter the hub spoke hole dimater in mm (usually 2.6) | |
* @param hubFlangeDiameter the diameter of the hub flange (from hole to hole) in mm | |
* @param hubFlangeToCenter the distante between the hub flange and the wheel center, taking the rim offset into account, in mm | |
* @param numberOfSpokes the total number of spoke used to build the wheel (20, 24, 28, 32, 36 ...) | |
* @param crossPattern the cross pattern (0 (radial), 1, 2, 3) | |
* @param spokeHoleOffset the spoke hole offset (only apply when spoke type = 'SP' ) | |
* @param spokeDia the spoke diameter in mm (1.5 for Sapim CX-Ray, 1.65 for Sapim D-Light, 1.8 for Sapim Race, etc...) | |
* @spokeTensionRatio the spoke tension ratio in percent (100 for 100%) | |
* | |
* @return the computed spoke length, rounded to 1 decimal place | |
* | |
* @author thomas@lhwheels.be | |
* @see https://www.wheelpro.co.uk/support/spoke-length-calculators/ | |
* @see https://www.wheelpro.co.uk/wheelbuilding/book.php | |
*/ | |
function spokeLengthV3(spokeType, erd, spokeHoleDiameter, hubFlangeDiameter, hubFlangeToCenter, numberOfSpokes, crossPattern, spokeHoleOffset, spokeDia, spokeTensionRatio) { | |
var R = erd / 2; // Rim radius (half the ERD) | |
var H = hubFlangeDiameter / 2; // Hub flange radius to spoke holes | |
var F = hubFlangeToCenter; // Hub flange offset | |
var X = crossPattern; // Cross pattern | |
if (spokeType == 'SP') { | |
X += 0.5; | |
} | |
var h = numberOfSpokes; // Number of spokes in the wheel | |
var Ø = spokeHoleDiameter; // Diameter of the spoke hole in the hub | |
spokeHoleOffset = crossPattern == 0 ? 0 : spokeHoleOffset; // always 0 for radial wheels | |
var spokeLength = Math.sqrt((R ** 2) + (H ** 2) + (F ** 2) - 2 * R * H * Math.cos((4.0 * Math.PI * X) / h)); | |
if (spokeType == 'JB') { | |
spokeLength -= (Ø / 2); | |
} else if (spokeType == 'SP') { | |
spokeLength += spokeHoleOffset; | |
} | |
let spokeTension = 120 * spokeTensionRatio / 100; | |
let elongation = spokeElongation(spokeTension, spokeDia, spokeLength); | |
spokeLength = spokeLength - elongation; | |
return Math.round(spokeLength * 10) / 10; | |
} | |
function test_spokeLengthV3() { | |
console.log(spokeLengthV3('JB', 593, 2.5, 57.9, 26.8, 32, 3, null, 1.5, 100), "Spoke length should be 285.9"); | |
} | |
/** | |
* Round a spoke length to a multiple of 2 value. The value is rounded to a lower value, between 1 et 3 mm. | |
* This kind of rounding is ideal when using Sapim double square (DS) nipple. | |
* ERD must be measured with DS nipples and the spoke must be engaged to 1mm before the end of the nipple. | |
* | |
* @param value the spoke length to round | |
* @return the rounded spoke length | |
* | |
* @author thomas@lhwheels.be | |
*/ | |
function roundSpokeLength(value) { | |
var rounded = Math.floor(value); | |
if (rounded % 2 == 1) { | |
rounded = rounded - 1; | |
} | |
if (value - rounded <= 1) { | |
rounded = rounded - 2; | |
} | |
return rounded; | |
} | |
function test_roundSpokeLength() { | |
console.log(roundSpokeLength(291.9), "Rounded spoke length should be 290"); | |
console.log(roundSpokeLength(292), "Rounded spoke length should be 290"); | |
console.log(roundSpokeLength(292.2), "Rounded spoke length should be 290"); | |
console.log(roundSpokeLength(293), "Rounded spoke length should be 290"); | |
console.log(roundSpokeLength(293.1), "Rounded spoke length should be 292"); | |
} | |
/** | |
* Compute the spoke tension ratio between the 2 side based on the flanges offsets (this is not a precise method). | |
* The flange offset is the distance from the hub centre line to the centre of the flange. | |
* The spoke tension ration will alway be 100 (%) on the side havi the shortest flange offset. | |
* | |
* @param thisFlangeOffset the offset of this flange (the one we are computing the spoke tension ratio) | |
* @param otherFlangeOffset the offset of the other flange | |
* @return an the spoke ration in % (integer value). Ex : 100 for 100%, 60 for 60%. | |
* | |
* @author thomas@lhwheels.be | |
*/ | |
function computeSpokeTensionRatio(thisFlangeOffset, otherFlangeOffset) { | |
if (thisFlangeOffset < otherFlangeOffset) { | |
return 100; | |
} else { | |
let ratio = Math.min(thisFlangeOffset, otherFlangeOffset) / Math.max(thisFlangeOffset, otherFlangeOffset); | |
return Math.round(ratio * 100); | |
} | |
} | |
function test_computeSpokeTensionRatio() { | |
console.log(computeSpokeTensionRatio(31, 37), "Spoke tension ration should be 100%"); | |
console.log(computeSpokeTensionRatio(37, 31), "Spoke tension ration should be 84%"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment