1 ;;; brew-calc.el --- calc functions for brewing ber
3 ;; Copyright (C) 2009 Erik Hetzner
5 ;; Author: Erik Hetzner <ehetzner@gmail.com>
7 ;; This file is NOT part of GNU Emacs.
9 ;; This program is free software: you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation, either version 3 of the License, or
12 ;; (at your option) any later version.
14 ;; This program is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
21 ;; calc functions for brewing
25 (org-food-alist-append 'math-additional-units
26 '((degPlato nil
"Degrees Plato")))
28 (setq math-units-table nil
)
31 "Get the norm of a value with units."
32 (math-simplify (math-remove-units v
)))
34 (defmath brew2C
(temp)
35 "Ensure that a temperature is in degC."
36 (let ((old-units (math-units-in-expr-p temp t
)))
38 (cond ((not old-units
)
39 (error "Not a temperature."))
40 ((eq (nth 0 old-units
) 'degC
)
42 ((eq (nth 0 old-units
) 'degF
)
43 (math-convert-temperature temp
'(var degF var-degF
) '(var degC var-degC
)))))))
45 (defmath brew2MG_L
(expr)
46 "Ensure that a mass / vol is in mg / L."
52 (defmath brew2min
(expr)
53 "Ensure that a time is in minutes."
54 (math-convert-units expr
'(var min var-min
)))
56 ;; From Wikipedia, Plato_scale
57 (defmath brewSG2P
(sg)
58 "Convert from Specific gravity to Plato, correcting SG vector
60 (let ((sg1 (brewSGCorr sg
)))
67 '(var degPlato var-degPlato
))))
69 ;; From Wikipedia, Plato_scale
71 "Convert Plato (degPlato) to specific gravity (unitless)."
72 (let ((pn (brewNorm p
)))
73 (math-simplify (/ (- 668
81 "Ensure that a value is in degrees Plato (degPlato)."
82 (if (eq (car (math-units-in-expr-p n t
)) 'degPlato
)
87 "Ensure that a value is in corrected, unitless, specific
89 (if (eq (car (math-units-in-expr-p n t
)) 'degPlato
)
93 ;;(defmath brewFpn (x)
94 ;; (let ((Pn (brewNorm (brew2P x))))
96 ;; (+ (* :"0.0024688" Pn)
97 ;; (* :"0.00001561" (^ Pn 2))))))
99 ;;(defmath brewAW (P n)
100 ;; (let ((P1 (brewNorm (brew2P P)))
101 ;; (n1 (brewNorm (brew2P n))))
105 (defmath brewAW2AV
(aw ae
)
106 "Convert Alcohol by weight to alcohol by volume."
107 (* aw
(/ (brew2SG ae
) :"0.79661")))
109 (defmath brewAV
(oe ae
)
110 "Calculate alc by vol. given original extract and apparent
113 (brewAWFix oe ae
) ae
))
115 ;; From George Fix, http://hbd.org/hbd/archive/880.html#880-9, due to
117 (defmath brewRE
(oe ae
)
118 "Calculate real extraction, given original extract and apparent
120 (let ((oe1 (brewNorm (brew2P oe
)))
121 (ae1 (brewNorm (brew2P ae
))))
123 (* (+ (* :"0.1808" oe1
)
125 '(var degPlato var-degPlato
)))))
127 (defmath brewAWFix
(oe ae
)
128 "Calculate alc. by weight, given original extract and apparent
130 (let* ((oe1 (brewNorm (brew2P oe
)))
131 (ae1 (brewNorm (brew2P ae
)))
132 (re (brewNorm (brewRE oe ae
))))
135 (* :"0.010665" oe1
)))))
137 (defmath brewCalories
(oe ae
)
138 "Calculate cal/L, given original extract and apparent final
140 (let* ((fg (brew2SG ae
))
141 (a (brewAWFix oe ae
))
142 (re (brewNorm (brewRE oe ae
))))
143 (* (* (* (+ (* :"6.9" a
)
144 (* :"4.0" (- re
:".1")))
147 (/ '(var Kcal var-Kcal
)
150 (defmath brewRA
(oe ae
)
151 "Calculate approximation to real attenuation."
152 (let ((re (brewNorm (brewRE oe ae
)))
153 (oe1 (brewNorm (brew2P oe
))))
156 (defmath brewAA
(oe ae
)
157 "Calculate approximate attenuation."
158 (let ((ae1 (brewNorm (brew2P ae
)))
159 (oe1 (brewNorm (brew2P oe
))))
163 ;; Per http://www.csgnetwork.com/h2odenscalc.html and
164 ;; http://www.earthwardconsulting.com/density.xls
165 (defmath brewRhoCalc
(temp)
166 "Calculate factor by which water at a given temp differs from
167 water at ref. temp (~4 degC)"
168 (let ((tempn (brewNorm (brew2C temp
))))
170 (- 1 (* (/ (+ tempn
:"288.9414")
172 (+ tempn
:"68.12963")))
173 (^
(- tempn
:"3.9863") 2))))))
175 ;; Follows from above, assuming that beer has the same relationship to
176 ;; temperature as water does.
177 (defmath brewSGCorr
(sg)
178 "Ensures that specific gravity is in a corrected, unitless
179 number, rather than a vector containing measured gravity, temp of
180 sampled liquid, and calibration temp, e.g. [1.010, 74 degF, 20
182 (if (not (vectorp sg
))
184 (let ((ir (nth 1 sg
))
187 (/ (* (brewRhoCalc ct
) ir
)
190 (defmath brewTinsethBigness
(ex)
191 "Calculate the Tinseth 'bigness' AA utilization factor."
192 (let ((sg (brew2SG ex
)))
197 (defmath brewTinsethBoilTime
(time)
198 "Calculate the Tinseth 'boil time' AA utilization factor."
199 (let ((min (brewNorm (brew2min time
))))
200 (/ (- 1 (^ e
(* min
:"-0.04")))
203 (defmath brewTinsethAAUtil
(ex m
)
204 "Calculate the Tinseth AA utilization factor."
205 (* (brewTinsethBigness ex
)
206 (brewTinsethBoilTime m
)))
208 (defmath brewTinsethIBU
(time hop-mass aa boil-size ex
)
209 "Calculate the IBUs given a time, mass of hops, aa of hops,
210 size of boil, and extract (SG or Plato)."
211 (* (brewTinsethAAUtil ex time
)
213 (/ (* aa hop-mass
) boil-size
))))