// Conversion from specific gravity to/from Brix and other scales. // This uses the equation developed by J. Hackbarth (2011), which is based on // the AOAC Brix tables (Horwitz and Latimer, 2005), to convert from Brix to // specific gravity. // // The Brix scale is virtually identical to the Balling and Plato scales. // // See: // http://web2.airmail.net/sgross/fermcalc/fermcalc_conversions.html // // TODO: Correct for hydrometer temperature. See: // http://web2.airmail.net/sgross/fermcalc/fermcalc_alcohol.html class Brix { class var coeffs = [1, +0.3875135555, +0.09702881653, +0.3883357480, -1.782845295, +5.591472292, -11.00667976, +13.62230734, -10.33082001, +4.387787019, -0.7995558730] // Convert a Brix value, expressed as a dimensionless number, to a // specific gravity (which is a dimensionless number comparing the density // of the liquid to that of water.) class BrixToSG[brix is dimensionless] := { sg = 1 bp = brix/100 for k=1 to 10 sg = sg + coeffs@k bp^k return sg } // Convert a specific gravity, expressed as a dimensionless number, to a // Brix value (returned as a dimensionless number.) // This inverts the BrixToSG calculation using the secant method. // (Note that this could now just call secant.frink's method // inverseSecant.) class SGToBrix[sg is dimensionless] := { // Estimation function taken from // http://en.wikipedia.org/wiki/Brix#Tables brix1 = 261.3 (1 - 1/sg) brix2 = 261.3 (1 - 1/(sg+0.00001)) sg1 = BrixToSG[brix1] sg2 = BrixToSG[brix2] while (true) { invSlope = (brix2-brix1)/(sg2 - sg1) bnew = brix1 + (sg - sg1) invSlope sgnew = BrixToSG[bnew] if abs[sgnew - sg] < 1e-8 return bnew sg2 = sg1 sg1 = sgnew brix2 = brix1 brix1 = bnew } } }