107 |
107 |
108 return array($R[$i],$G[$i],$B[$i]); |
108 return array($R[$i],$G[$i],$B[$i]); |
109 } |
109 } |
110 |
110 |
111 |
111 |
|
112 |
|
113 function sg_to_plato($sg) { |
|
114 if ($sg > 0.5) |
|
115 return 259 - 259 / $sg; |
|
116 return 0; |
|
117 } |
|
118 |
|
119 |
|
120 |
|
121 function plato_to_sg($plato) { |
|
122 if ($plato < 259) |
|
123 return 259 / (259 - $plato); |
|
124 return 1.000; |
|
125 } |
|
126 |
|
127 |
|
128 |
|
129 /* |
|
130 |
|
131 Brouwhulp data.pas |
|
132 |
|
133 Function THop.FlavourContribution : double; //in % * concentration in g/l |
|
134 var bt, vol : double; |
|
135 begin |
|
136 bt:= FTime.Value; |
|
137 vol:= 0; |
|
138 if FRecipe <> NIL then vol:= FRecipe.BatchSize.Value; |
|
139 if FUse = huFirstWort then Result:= 0.15 * FAmount.Value * 1000 //assume 15% flavourcontribution for fwh |
|
140 else if bt > 50 then Result:= 0.10 * FAmount.Value * 1000 //assume 10% flavourcontribution as a minimum |
|
141 else |
|
142 begin |
|
143 Result:= 15.25 / (6 * sqrt(2 * PI)) * Exp(-0.5*Power((bt-21)/6, 2)) |
|
144 * FAmount.Value * 1000; |
|
145 if result < 0.10 * FAmount.Value * 1000 then |
|
146 Result:= 0.10 * FAmount.Value * 1000 //assume 10% flavourcontribution as a minimum |
|
147 end; |
|
148 if vol > 0 then Result:= Result / vol; |
|
149 end; |
|
150 |
|
151 Function THop.AromaContribution : double; //in % * concentration in g/l |
|
152 var bt, vol : double; |
|
153 begin |
|
154 bt:= FTime.Value; |
|
155 vol:= 0; |
|
156 if FRecipe <> NIL then vol:= FRecipe.BatchSize.Value; |
|
157 if bt > 20 then Result:= 0 |
|
158 else if bt > 7.5 then |
|
159 Result:= 10.03 / (4 * sqrt(2 * PI)) * Exp(-0.5*Power((bt-7.5)/4, 2)) |
|
160 * FAmount.Value * 1000 |
|
161 else if FUse = huBoil then Result:= FAmount.Value * 1000 |
|
162 else if FUse = huAroma then Result:= 1.2 * FAmount.Value * 1000 |
|
163 else if FUse = huWhirlpool then Result:= 1.2 * FAmount.Value * 1000 |
|
164 else if FUse = huDryHop then Result:= 1.33 * FAmount.Value * 1000; |
|
165 if vol > 0 then Result:= Result / vol; |
|
166 end; |
|
167 |
|
168 |
|
169 Procedure TFermentable.SetpHParameters(force : boolean); |
|
170 var x, ebc : double; |
|
171 begin |
|
172 if Between(FDIpH.Value, -0.01, 0.01) or Between(FAcidTo57.Value, -0.1, 0.1) or force then |
|
173 begin |
|
174 ebc:= SRMtoEBC(FColor.Value); |
|
175 case FGrainType of |
|
176 gtBase, gtKilned: |
|
177 begin |
|
178 FDIpH.Value:= -0.0132 * ebc + 5.7605; |
|
179 x:= 0.4278 * ebc - 1.8106; |
|
180 FAcidTo57.Value:= x; |
|
181 end; |
|
182 gtRoast: |
|
183 begin |
|
184 FDIpH.Value:= 0.00018 * ebc + 4.558; |
|
185 FAcidTo57.Value:= -0.0176 * ebc + 60.04; |
|
186 end; |
|
187 gtCrystal: |
|
188 begin |
|
189 FDIpH.Value:= -0.0019 * ebc + 5.2175; |
|
190 FAcidTo57.Value:= 0.132 * ebc + 14.277; |
|
191 end; |
|
192 gtSour: |
|
193 begin |
|
194 FDIpH.Value:= 3.44; |
|
195 FAcidTo57.Value:= 337; |
|
196 end; |
|
197 gtSpecial: //this could be anything. Assume for now it is a non-acidulated base or kilned malt |
|
198 begin |
|
199 FDIpH.Value:= -0.0132 * ebc + 5.7605; |
|
200 FAcidTo57.Value:= 0.4278 * ebc - 1.8106; |
|
201 end; |
|
202 end; |
|
203 end; |
|
204 //known parameters should be filled in here |
|
205 if FSupplier.Value = 'Weyermann' then |
|
206 begin |
|
207 if FName.Value = 'Vienna mout' then |
|
208 begin |
|
209 FDIpH.Value:= 5.65; |
|
210 FAcidTo57.Value:= 1.6; |
|
211 end; |
|
212 if FName.Value = 'Münchner I' then |
|
213 begin |
|
214 FDIpH.Value:= 5.44; |
|
215 FAcidTo57.Value:= 8.4; |
|
216 end; |
|
217 if FName.Value = 'Münchner II' then |
|
218 begin |
|
219 FDIpH.Value:= 5.54; |
|
220 FAcidTo57.Value:= 5.6; |
|
221 end; |
|
222 if FName.Value = 'Caramunich I' then |
|
223 begin |
|
224 FDIpH.Value:= 5.1; |
|
225 FAcidTo57.Value:= 22.4; |
|
226 end; |
|
227 if FName.Value = 'Caramunich II' then |
|
228 begin |
|
229 FDIpH.Value:= 4.71; |
|
230 FAcidTo57.Value:= 49; |
|
231 end; |
|
232 if FName.Value = 'Caramunich III' then |
|
233 begin |
|
234 FDIpH.Value:= 4.92; |
|
235 FAcidTo57.Value:= 31.2; |
|
236 end; |
|
237 if FName.Value = 'Cara-aroma' then |
|
238 begin |
|
239 FDIpH.Value:= 4.48; |
|
240 FAcidTo57.Value:= 74.4; |
|
241 end; |
|
242 if FName.Value = 'Carafa I' then |
|
243 begin |
|
244 FDIpH.Value:= 4.71; |
|
245 FAcidTo57.Value:= 42; |
|
246 end; |
|
247 if FName.Value = 'Carafa III' then |
|
248 begin |
|
249 FDIpH.Value:= 4.81; |
|
250 FAcidTo57.Value:= 35.4; |
|
251 end; |
|
252 if FName.Value = 'Carafa II' then |
|
253 begin |
|
254 FDIpH.Value:= 4.76; |
|
255 FAcidTo57.Value:= 38.7; |
|
256 end; |
|
257 if FName.Value = 'Carafa Special I' then |
|
258 begin |
|
259 FDIpH.Value:= 4.73; |
|
260 FAcidTo57.Value:= 46.4; |
|
261 end; |
|
262 if FName.Value = 'Carafa Special II' then |
|
263 begin |
|
264 FDIpH.Value:= 4.78; |
|
265 FAcidTo57.Value:= 42.9; |
|
266 end; |
|
267 if FName.Value = 'Carafa Special III' then |
|
268 begin |
|
269 FDIpH.Value:= 4.83; |
|
270 FAcidTo57.Value:= 38.9; |
|
271 end; |
|
272 if IsInString(FName.Value, 'Zuurmout') then |
|
273 begin |
|
274 FDIpH.Value:= 3.44; |
|
275 FAcidTo57.Value:= 358.2; |
|
276 end; |
|
277 end; |
|
278 end; |
|
279 |
|
280 |
|
281 function TFermentable.GetExtract: double; |
|
282 begin |
|
283 Result := 0; |
|
284 if FRecipe <> nil then |
|
285 begin |
|
286 Result := FAmount.Value * FYield.Value / 100 * (1 - FMoisture.Value / 100); |
|
287 if FAdded = atMash then |
|
288 Result := Result * FRecipe.Efficiency / 100; |
|
289 end; |
|
290 end; |
|
291 |
|
292 |
|
293 function TFermentable.GetKolbachIndex: double; |
|
294 begin |
|
295 if FProtein.Value > 0 then |
|
296 Result := FDissolvedProtein.Value / FProtein.Value |
|
297 else |
|
298 Result := 0; |
|
299 end; |
|
300 |
|
301 |
|
302 Procedure TWater.AddMinerals(Ca, Mg, Na, HCO3, Cl, SO4 : double); |
|
303 begin |
|
304 FCalcium.Add(Ca); |
|
305 FMagnesium.Add(Mg); |
|
306 FSodium.Add(Na); |
|
307 FBicarbonate.Add(HCO3); |
|
308 FChloride.Add(Cl); |
|
309 FSulfate.Add(SO4); |
|
310 end; |
|
311 |
|
312 function TWater.GetResidualAlkalinity: double; |
|
313 begin |
|
314 //Result in mg/l as CaCO3 |
|
315 Result:= FTotalAlkalinity.Value - (FCalcium.Value / 1.4 + FMagnesium.Value / 1.7); |
|
316 end; |
|
317 |
|
318 const |
|
319 Ka1 = 0.0000004445; |
|
320 Ka2 = 0.0000000000468; |
|
321 |
|
322 Function PartCO3(pH : double) : double; |
|
323 var H : double; |
|
324 begin |
|
325 H:= Power(10, -pH); |
|
326 Result:= 100 * Ka1 * Ka2 / (H*H + H * Ka1 + Ka1 * Ka2); |
|
327 end; |
|
328 |
|
329 Function PartHCO3(pH : double) : double; |
|
330 var H : double; |
|
331 begin |
|
332 H:= Power(10, -pH); |
|
333 Result:= 100 * Ka1 * H / (H*H + H * Ka1 + Ka1 * Ka2); |
|
334 end; |
|
335 |
|
336 Function PartH2CO3(pH : double) : double; |
|
337 var H : double; |
|
338 begin |
|
339 H:= Power(10, -pH); |
|
340 Result:= 100 * H * H / (H*H + H * Ka1 + Ka1 * Ka2); |
|
341 end; |
|
342 |
|
343 Function Charge(pH : double) : double; |
|
344 begin |
|
345 Result:= (-2 * PartCO3(pH) - PartHCO3(pH)); |
|
346 end; |
|
347 |
|
348 //Z alkalinity is the amount of acid (in mEq/l) needed to bring water to the target pH (Z pH) |
|
349 Function TWater.ZAlkalinity(pHZ : double) : double; //in mEq/l |
|
350 var CT, DeltaCNaught, DeltaCZ, C43, Cw, Cz : double; |
|
351 begin |
|
352 C43:= Charge(4.3); |
|
353 Cw:= Charge(FpH.Value); |
|
354 Cz:= Charge(pHz); |
|
355 DeltaCNaught:= -C43+Cw; |
|
356 CT:= GetAlkalinity / 50 / DeltaCNaught; |
|
357 DeltaCZ:= -Cz+Cw; |
|
358 Result:= CT * DeltaCZ; |
|
359 end; |
|
360 |
|
361 //Z Residual alkalinity is the amount of acid (in mEq/l) needed to bring the water in the mash to the target pH (Z pH) |
|
362 Function TWater.ZRA(pHZ : double) : double; //in mEq/l |
|
363 var Calc, Magn, Z : double; |
|
364 begin |
|
365 Calc:= FCalcium.Value / (MMCa / 2); |
|
366 Magn:= FMagnesium.Value / (MMMg / 2); |
|
367 Z:= ZAlkalinity(pHZ); |
|
368 Result:= Z - (Calc / 3.5 + Magn / 7); |
|
369 end; |
|
370 |
|
371 Function TWater.ProtonDeficit(pHZ : double) : double; |
|
372 var i : integer; |
|
373 F : TFermentable; |
|
374 x : double; |
|
375 begin |
|
376 Result:= ZRA(pHZ) * FAmount.Value; |
|
377 //proton deficit for the added malts |
|
378 for i:= 0 to FRecipe.NumFermentables - 1 do |
|
379 begin |
|
380 F:= FRecipe.Fermentable[i]; |
|
381 if (F.AddedType = atMash) and (F.GrainType <> gtNone) then |
|
382 begin |
|
383 x:= F.AcidRequired(pHZ) * F.Amount.Value; |
|
384 Result:= Result + x; |
|
385 end; |
|
386 end; |
|
387 end; |
|
388 |
|
389 Function TWater.MashpH : double; |
|
390 var n : integer; |
|
391 pd : double; |
|
392 pH, deltapH, deltapd : double; |
|
393 begin |
|
394 Result:= 0; |
|
395 n:= 0; |
|
396 pH:= 5.4; |
|
397 deltapH:= 0.001; |
|
398 deltapd:= 0.1; |
|
399 pd:= ProtonDeficit(pH); |
|
400 while ((pd < -deltapd) or (pd > deltapd)) and (n < 1000) do |
|
401 begin |
|
402 inc(n); |
|
403 if pd < -deltapd then ph:= ph - deltapH |
|
404 else if pd > deltapd then pH:= pH + deltapH; |
|
405 pd:= ProtonDeficit(pH); |
|
406 end; |
|
407 Result:= pH; |
|
408 end; |
|
409 |
|
410 Function TWater.MashpH2(PrDef : double) : double; |
|
411 var n : integer; |
|
412 pd : double; |
|
413 pH, deltapH, deltapd : double; |
|
414 begin |
|
415 Result:= 0; |
|
416 n:= 0; |
|
417 pH:= 5.4; |
|
418 deltapH:= 0.001; |
|
419 deltapd:= 0.1; |
|
420 pd:= ProtonDeficit(pH); |
|
421 while ((pd < PrDef-deltapd) or (pd > PrDef + deltapd)) and (n < 1000) do |
|
422 begin |
|
423 inc(n); |
|
424 if pd < PrDef-deltapd then ph:= ph - deltapH |
|
425 else if pd > PrDef+deltapd then pH:= pH + deltapH; |
|
426 pd:= ProtonDeficit(pH); |
|
427 end; |
|
428 Result:= pH; |
|
429 end; |
|
430 |
|
431 function TWater.GetAlkalinity: double; |
|
432 begin |
|
433 Result := FBicarbonate.Value / 1.22; //mEq/l |
|
434 end; |
|
435 |
|
436 function TWater.GetHardness: double; |
|
437 begin |
|
438 Result := 0.14 * FCalcium.Value - 0.23 * FMagnesium.Value; |
|
439 end; |
|
440 |
|
441 function TWater.GetEstPhMash: double; |
|
442 {var |
|
443 pHdemi, S: double;} |
|
444 begin |
|
445 Result:= MashpH; |
|
446 { Result := 0; |
|
447 if FRecipe <> nil then |
|
448 begin |
|
449 pHDemi := FRecipe.pHdemi; |
|
450 S := 0.013 * FRecipe.MashThickness + 0.013; |
|
451 Result := pHDemi + ResidualAlkalinity / 50 * S; |
|
452 end;} |
|
453 end; |
|
454 |
|
455 |
|
456 function TBeerStyle.GetBUGUMin: double; |
|
457 var |
|
458 B, G: double; |
|
459 begin |
|
460 Result:= 0; |
|
461 if ((FOGMax.Value + FOGMin.Value) > 0) and ((FIBUMax.Value + FIBUMin.Value) > 0) then |
|
462 begin |
|
463 G := (FOGMax.Value - FOGMin.Value) / ((FOGMax.Value + FOGMin.Value) / 2); |
|
464 B := (FIBUMax.Value - FIBUMin.Value) / ((FIBUMax.Value + FIBUMin.Value) / 2); |
|
465 if G > B then |
|
466 Result := ((FIBUMin.Value + FIBUMax.Value) / 2) / (1000 * (FOGMax.Value - 1)) |
|
467 else |
|
468 Result := FIBUMin.Value / (1000 * (((FOGMax.Value + FOGMin.Value) / 2) - 1)); |
|
469 end; |
|
470 end; |
|
471 |
|
472 function TBeerStyle.GetBUGUMax: double; |
|
473 var |
|
474 B, G: double; |
|
475 begin |
|
476 Result:= 0; |
|
477 if ((FOGMax.Value + FOGMin.Value) > 0) and ((FIBUMax.Value + FIBUMin.Value) > 0) |
|
478 and (FOGMin.Value > 1) then |
|
479 begin |
|
480 G := (FOGMax.Value - FOGMin.Value) / ((FOGMax.Value + FOGMin.Value) / 2); |
|
481 B := (FIBUMax.Value - FIBUMin.Value) / ((FIBUMax.Value + FIBUMin.Value) / 2); |
|
482 if G > B then |
|
483 Result := ((FIBUMin.Value + FIBUMax.Value) / 2) / (1000 * (FOGMin.Value - 1)) |
|
484 else |
|
485 Result := FIBUMax.Value / (1000 * (((FOGMax.Value + FOGMin.Value) / 2) - 1)); |
|
486 end; |
|
487 end; |
|
488 |
|
489 |
|
490 CalcOG; |
|
491 CalcBitterness; |
|
492 |
|
493 // Get concentration of ions in diluted brewwater (1) and target water (2) in mmol/l |
|
494 Ca1 := W.Calcium.Value / MMCa; |
|
495 Ca2 := W2.Calcium.Value / MMCa; |
|
496 Mg1 := W.Magnesium.Value / MMMg; |
|
497 Mg2 := W2.Magnesium.Value / MMMg; |
|
498 Na1 := W.Sodium.Value / MMNa; |
|
499 Na2 := W2.Sodium.Value / MMNa; |
|
500 |
|
501 CO31 := W.Bicarbonate.Value / MMHCO3; |
|
502 CO32 := W2.Bicarbonate.Value / MMHCO3; |
|
503 SO41 := W.Sulfate.Value / MMSO4; |
|
504 SO42 := W2.Sulfate.Value / MMSO4; |
|
505 Cl1 := W.Sulfate.Value / MMSO4; |
|
506 Cl2 := W2.Sulfate.Value / MMSO4; |
|
507 |
|
508 |
|
509 procedure MixWater(W1, W2, Wr: TWater); |
|
510 |
|
511 function Mix(V1, V2, C1, C2: double): double; |
|
512 begin |
|
513 if (V1 + V2) > 0 then |
|
514 Result := (V1 * C1 + V2 * C2) / (V1 + V2) |
|
515 else |
|
516 Result := 0; |
|
517 end; |
|
518 |
|
519 var |
|
520 vol1, vol2: double; |
|
521 phnew: double; |
|
522 begin |
|
523 vol1 := W1.Amount.Value; |
|
524 vol2 := W2.Amount.Value; |
|
525 if (vol1 + vol2) > 0 then |
|
526 begin |
|
527 Wr.Amount.Value := vol1 + vol2; |
|
528 Wr.Calcium.Value := Mix(vol1, vol2, W1.Calcium.Value, W2.Calcium.Value); |
|
529 Wr.Magnesium.Value := Mix(vol1, vol2, W1.Magnesium.Value, W2.Magnesium.Value); |
|
530 Wr.Sodium.Value := Mix(vol1, vol2, W1.Sodium.Value, W2.Sodium.Value); |
|
531 Wr.Bicarbonate.Value := Mix(vol1, vol2, W1.Bicarbonate.Value, W2.Bicarbonate.Value); |
|
532 Wr.Sulfate.Value := Mix(vol1, vol2, W1.Sulfate.Value, W2.Sulfate.Value); |
|
533 Wr.Chloride.Value := Mix(vol1, vol2, W1.Chloride.Value, W2.Chloride.Value); |
|
534 pHnew := -log10((power(10, -W1.pHWater.Value) * vol1 + |
|
535 power(10, -W2.pHWater.Value) * vol2) / (vol1 + vol2)); |
|
536 Wr.pHwater.Value := pHnew; |
|
537 end; |
|
538 end; |
|
539 |
|
540 |
|
541 |
|
542 function TRecipe.CalcColorWort : double; |
|
543 var |
|
544 i: integer; |
|
545 F: TFermentable; |
|
546 c, v: double; |
|
547 begin |
|
548 c := 0; |
|
549 v := FBatchSize.Value; |
|
550 if (v > 0) and (High(FFermentables) >= 0) then |
|
551 begin |
|
552 for i := Low(FFermentables) to High(FFermentables) do |
|
553 begin |
|
554 F := TFermentable(FFermentables[i]); |
|
555 c := c + F.Amount.Value * F.Color.Value / v; |
|
556 end; |
|
557 c := c * 8.34436; |
|
558 case FColorMethod of |
|
559 cmMorey: c := 1.49 * Power(c, 0.69); |
|
560 cmMosher: c := 0.3 * c + 4.7; |
|
561 cmDaniels: c := 0.2 * c + 8.4; |
|
562 end; |
|
563 end; |
|
564 Result:= c; |
|
565 end; |
|
566 |
|
567 |
|
568 procedure TRecipe.CalcWaterBalance; |
|
569 var |
|
570 i: integer; |
|
571 F: TFermentable; |
|
572 begin |
|
573 FAbsorbedByGrain := 0; |
|
574 for i := Low(FFermentables) to High(FFermentables) do |
|
575 begin |
|
576 F := TFermentable(FFermentables[i]); |
|
577 if (F.FermentableType = ftGrain) or (F.FermentableType = ftAdjunct) then |
|
578 FAbsorbedByGrain := FAbsorbedByGrain + F.Amount.Value; |
|
579 end; |
|
580 FAbsorbedByGrain := FAbsorbedByGrain * Settings.GrainAbsorption.Value; |
|
581 |
|
582 if FEquipment.CalcBoilVolume.Value then |
|
583 {FBoilSize.Value := FBatchSize.Value / (1 - (FEquipment.EvapRate.Value / 100) * |
|
584 (FBoilTime.Value / 60));} |
|
585 FBoilSize.Value:= FBatchSize.Value + FEquipment.BoilSize.Value |
|
586 * FEquipment.EvapRate.Value / 100 * |
|
587 (FBoilTime.Value / 60); |
|
588 end; |
|
589 |
|
590 |
|
591 |
|
592 procedure TRecipe.CalcOG; |
|
593 var |
|
594 i, j, k: integer; |
|
595 v, v2, sg, d, tot, tot2, vol, vol1, vol2, sugF, sug, sug2, p, x: double; |
|
596 mass1, mass2 : double; |
|
597 F: TFermentable; |
|
598 begin |
|
599 for j := 1 to 1 do |
|
600 begin |
|
601 sug:= 0; |
|
602 sugf:= 0; |
|
603 sug2:= 0; |
|
604 tot := 0; |
|
605 tot2:= 0; |
|
606 vol:= 0; |
|
607 FEfficiency.Value := GetEfficiency; |
|
608 for i := 0 to NumFermentables - 1 do |
|
609 begin |
|
610 F := TFermentable(Fermentable[i]); |
|
611 if (F.AddedType = atMash) or (F.AddedType = atBoil) then |
|
612 begin |
|
613 d := F.Amount.Value * (F.Yield.Value / 100) * (1 - F.Moisture.Value / 100); |
|
614 if (F.AddedType = atMash) then |
|
615 d := FEfficiency.Value / 100 * d; |
|
616 sugf := sugf + d; |
|
617 tot := tot + F.Amount.Value; |
|
618 end |
|
619 else |
|
620 begin |
|
621 x:= (F.Yield.Value / 100) * (1 - F.Moisture.Value / 100); |
|
622 sug2:= sug2 + F.Amount.Value * x; |
|
623 tot2:= tot2 + F.Amount.Value; |
|
624 tot := tot + F.Amount.Value; |
|
625 vol:= vol + F.Amount.Value / (x * SugarDensity + (1 - x) * 1); |
|
626 end; |
|
627 end; |
|
628 if tot > 0 then |
|
629 for i := 0 to NumFermentables - 1 do |
|
630 begin |
|
631 F := Fermentable[i]; |
|
632 F.Percentage.Value := 100 * F.Amount.Value / tot; |
|
633 end; |
|
634 |
|
635 if (FEquipment <> NIL) and (FBatchSize.Value > 0) then |
|
636 begin |
|
637 vol1:= FBatchSize.Value - FEquipment.TrubChillerLoss.Value; |
|
638 vol2:= vol1 + FEquipment.TopUpWater.Value + vol; |
|
639 sug:= sugf * vol1 / FBatchSize.Value; //kg |
|
640 sug:= sug + sug2; //kg |
|
641 if vol2 > 0 then |
|
642 sug:= sug / vol2; //kg/l |
|
643 p:= 100 * sug; |
|
644 sg:= PlatoToSG(p); |
|
645 for k:= 1 to 30 do |
|
646 begin |
|
647 if sg > 0 then |
|
648 p := 100 * sug / sg; //deg. Plato |
|
649 sg := PlatoToSG(p); |
|
650 end; |
|
651 FEstOG.Value:= sg; |
|
652 end |
|
653 else if FBatchSize.Value <> 0 then |
|
654 begin |
|
655 p := 100 * sugf / FBatchSize.Value; //deg. Plato |
|
656 sg := PlatoToSG(p); |
|
657 for k:= 1 to 20 do |
|
658 begin |
|
659 if sg > 0 then |
|
660 p := 100 * sugf / (FBatchSize.Value * sg); //deg. Plato |
|
661 sg := PlatoToSG(p); |
|
662 end; |
|
663 FEstOG.Value := sg; |
|
664 end |
|
665 else |
|
666 FEstOG.Value := 1.0; |
|
667 end; |
|
668 |
|
669 CalcWaterBalance; |
|
670 end; |
|
671 |
|
672 |
|
673 |
|
674 procedure TRecipe.EstimateFG; |
|
675 var |
|
676 i: integer; |
|
677 percS, percCara, BD, Att, AttBeer, sg: double; |
|
678 Temp, TotTme: double; |
|
679 Y: TYeast; |
|
680 // Eq: TEquipment; |
|
681 begin |
|
682 percS := GetPercSugar; |
|
683 //if PercS > 40 then PercS:= 0; |
|
684 percCara := GetPercCrystalMalt; |
|
685 if percCara > 50 then PercCara:= 0; |
|
686 if (Mash <> nil) and (Mash.MashStep[0] <> nil) then |
|
687 begin |
|
688 BD := Mash.MashStep[0].WaterToGrainRatio; |
|
689 BD:= Max(2, Min(5.5, BD)); |
|
690 Temp := Mash.AverageTemperature; |
|
691 Temp:= Max(60, Min(72, Temp)); |
|
692 TotTme := Mash.TotalMashTime; |
|
693 TotTme:= Max(20, Min(90, TotTme)); |
|
694 end |
|
695 else |
|
696 begin |
|
697 BD := 3.5; |
|
698 Temp := 67; |
|
699 TotTme := 75; |
|
700 end; |
|
701 Y := Yeast[0]; |
|
702 if Y <> nil then |
|
703 begin |
|
704 Att := Y.Attenuation.Value; |
|
705 if Att < 30 then Att:= 77; |
|
706 end |
|
707 else |
|
708 Att := 77; |
|
709 AttBeer := 0.00825 * Att + 0.00817 * BD - 0.00684 * Temp + 0.00026 * |
|
710 TotTme - 0.00356 * PercCara + 0.00553 * PercS + 0.547; |
|
711 |
|
712 { Eq := nil; |
|
713 if FEquipment <> nil then |
|
714 Eq := TEquipment(Equipments.FindByName(FEquipment.Name.Value)); |
|
715 if Eq <> nil then |
|
716 AttBeer2 := Eq.EstimateFG(Att, BD, Temp, TotTme, PercCara, PercS);} |
|
717 |
|
718 FEstFG.Value := 1 + (1 - AttBeer) * (FEstOG.Value - 1); |
|
719 CalcOGFermenter; |
|
720 if FOGFermenter.Value > 1.001 then |
|
721 begin |
|
722 sg:= FOGFermenter.Value; |
|
723 FEstFG2.Value := 1 + (1 - AttBeer) * (sg - 1); |
|
724 FEstABV.Value := ABVol(FEstOG.Value, FEstFG.Value); |
|
725 end |
|
726 else if FOG.Value > 1.001 then |
|
727 begin |
|
728 sg:= FOG.Value; |
|
729 FEstFG2.Value := 1 + (1 - AttBeer) * (sg - 1); |
|
730 FEstABV.Value := ABVol(FEstOG.Value, FEstFG.Value); |
|
731 end |
|
732 else |
|
733 begin |
|
734 FEstFG2.Value := 1 + (1 - AttBeer) * (FEstOG.Value - 1); |
|
735 FEstABV.Value := ABVol(FEstOG.Value, FEstFG.Value); |
|
736 end; |
|
737 end; |
|
738 |
|
739 Procedure TRecipe.CalcCalories; |
|
740 var sug, alc, org, fig : double; |
|
741 begin |
|
742 if FOGFermenter.Value > 1.001 then org:= FOGFermenter.Value |
|
743 else if FOG.Value > 1.001 then org:= FOG.Value |
|
744 else org:= 0; |
|
745 if FFG.Value > 0.999 then fig:= FFG.Value |
|
746 else if FEstFG.Value > 1.000 then fig:= FEstFG.Value |
|
747 else if FEstFG2.Value > 1.000 then fig:= FEstFG2.Value |
|
748 else fig:= 0; |
|
749 if (org > 0) and (fig > 0) then |
|
750 begin |
|
751 alc:= 1881.22 * fig * (org - fig) / (1.775 - org); |
|
752 sug:= 3550 * fig * (0.1808 * org + 0.8192 * fig - 1.0004); |
|
753 FCalories.Value:= (alc + sug) / (12 * 0.0295735296); |
|
754 end |
|
755 else FCalories.Value:= 0; |
|
756 end; |
|
757 |
|
758 |
|
759 |
|
760 |
|
761 */ |
|
762 |
112 ?> |
763 ?> |