www/includes/formulas.php

changeset 164
0a5abea575a9
parent 147
e6e5d007eb54
child 231
9881453a49b3
equal deleted inserted replaced
163:4a4cc3497a57 164:0a5abea575a9
268 268
269 /* 269 /*
270 270
271 Brouwhulp data.pas 271 Brouwhulp data.pas
272 272
273 Function THop.FlavourContribution : double; //in % * concentration in g/l
274 var bt, vol : double;
275 begin
276 bt:= FTime.Value;
277 vol:= 0;
278 if FRecipe <> NIL then vol:= FRecipe.BatchSize.Value;
279 if FUse = huFirstWort then Result:= 0.15 * FAmount.Value * 1000 //assume 15% flavourcontribution for fwh
280 else if bt > 50 then Result:= 0.10 * FAmount.Value * 1000 //assume 10% flavourcontribution as a minimum
281 else
282 begin
283 Result:= 15.25 / (6 * sqrt(2 * PI)) * Exp(-0.5*Power((bt-21)/6, 2))
284 * FAmount.Value * 1000;
285 if result < 0.10 * FAmount.Value * 1000 then
286 Result:= 0.10 * FAmount.Value * 1000 //assume 10% flavourcontribution as a minimum
287 end;
288 if vol > 0 then Result:= Result / vol;
289 end;
290
291 Function THop.AromaContribution : double; //in % * concentration in g/l
292 var bt, vol : double;
293 begin
294 bt:= FTime.Value;
295 vol:= 0;
296 if FRecipe <> NIL then vol:= FRecipe.BatchSize.Value;
297 if bt > 20 then Result:= 0
298 else if bt > 7.5 then
299 Result:= 10.03 / (4 * sqrt(2 * PI)) * Exp(-0.5*Power((bt-7.5)/4, 2))
300 * FAmount.Value * 1000
301 else if FUse = huBoil then Result:= FAmount.Value * 1000
302 else if FUse = huAroma then Result:= 1.2 * FAmount.Value * 1000
303 else if FUse = huWhirlpool then Result:= 1.2 * FAmount.Value * 1000
304 else if FUse = huDryHop then Result:= 1.33 * FAmount.Value * 1000;
305 if vol > 0 then Result:= Result / vol;
306 end;
307 273
308 274
309 Procedure TFermentable.SetpHParameters(force : boolean); 275 Procedure TFermentable.SetpHParameters(force : boolean);
310 var x, ebc : double; 276 var x, ebc : double;
311 begin 277 begin
437 else 403 else
438 Result := 0; 404 Result := 0;
439 end; 405 end;
440 406
441 407
442 Procedure TWater.AddMinerals(Ca, Mg, Na, HCO3, Cl, SO4 : double);
443 begin
444 FCalcium.Add(Ca);
445 FMagnesium.Add(Mg);
446 FSodium.Add(Na);
447 FBicarbonate.Add(HCO3);
448 FChloride.Add(Cl);
449 FSulfate.Add(SO4);
450 end;
451
452 function TWater.GetResidualAlkalinity: double; 408 function TWater.GetResidualAlkalinity: double;
453 begin 409 begin
454 //Result in mg/l as CaCO3 410 //Result in mg/l as CaCO3
455 Result:= FTotalAlkalinity.Value - (FCalcium.Value / 1.4 + FMagnesium.Value / 1.7); 411 Result:= FTotalAlkalinity.Value - (FCalcium.Value / 1.4 + FMagnesium.Value / 1.7);
456 end; 412 end;
457 413
458 const
459 Ka1 = 0.0000004445;
460 Ka2 = 0.0000000000468;
461
462 Function PartCO3(pH : double) : double;
463 var H : double;
464 begin
465 H:= Power(10, -pH);
466 Result:= 100 * Ka1 * Ka2 / (H*H + H * Ka1 + Ka1 * Ka2);
467 end;
468
469 Function PartHCO3(pH : double) : double;
470 var H : double;
471 begin
472 H:= Power(10, -pH);
473 Result:= 100 * Ka1 * H / (H*H + H * Ka1 + Ka1 * Ka2);
474 end;
475
476 Function PartH2CO3(pH : double) : double;
477 var H : double;
478 begin
479 H:= Power(10, -pH);
480 Result:= 100 * H * H / (H*H + H * Ka1 + Ka1 * Ka2);
481 end;
482
483 Function Charge(pH : double) : double;
484 begin
485 Result:= (-2 * PartCO3(pH) - PartHCO3(pH));
486 end;
487
488 //Z alkalinity is the amount of acid (in mEq/l) needed to bring water to the target pH (Z pH)
489 Function TWater.ZAlkalinity(pHZ : double) : double; //in mEq/l
490 var CT, DeltaCNaught, DeltaCZ, C43, Cw, Cz : double;
491 begin
492 C43:= Charge(4.3);
493 Cw:= Charge(FpH.Value);
494 Cz:= Charge(pHz);
495 DeltaCNaught:= -C43+Cw;
496 CT:= GetAlkalinity / 50 / DeltaCNaught;
497 DeltaCZ:= -Cz+Cw;
498 Result:= CT * DeltaCZ;
499 end;
500
501 //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)
502 Function TWater.ZRA(pHZ : double) : double; //in mEq/l
503 var Calc, Magn, Z : double;
504 begin
505 Calc:= FCalcium.Value / (MMCa / 2);
506 Magn:= FMagnesium.Value / (MMMg / 2);
507 Z:= ZAlkalinity(pHZ);
508 Result:= Z - (Calc / 3.5 + Magn / 7);
509 end;
510
511 Function TWater.ProtonDeficit(pHZ : double) : double;
512 var i : integer;
513 F : TFermentable;
514 x : double;
515 begin
516 Result:= ZRA(pHZ) * FAmount.Value;
517 //proton deficit for the added malts
518 for i:= 0 to FRecipe.NumFermentables - 1 do
519 begin
520 F:= FRecipe.Fermentable[i];
521 if (F.AddedType = atMash) and (F.GrainType <> gtNone) then
522 begin
523 x:= F.AcidRequired(pHZ) * F.Amount.Value;
524 Result:= Result + x;
525 end;
526 end;
527 end;
528
529 Function TWater.MashpH : double;
530 var n : integer;
531 pd : double;
532 pH, deltapH, deltapd : double;
533 begin
534 Result:= 0;
535 n:= 0;
536 pH:= 5.4;
537 deltapH:= 0.001;
538 deltapd:= 0.1;
539 pd:= ProtonDeficit(pH);
540 while ((pd < -deltapd) or (pd > deltapd)) and (n < 1000) do
541 begin
542 inc(n);
543 if pd < -deltapd then ph:= ph - deltapH
544 else if pd > deltapd then pH:= pH + deltapH;
545 pd:= ProtonDeficit(pH);
546 end;
547 Result:= pH;
548 end;
549
550 Function TWater.MashpH2(PrDef : double) : double;
551 var n : integer;
552 pd : double;
553 pH, deltapH, deltapd : double;
554 begin
555 Result:= 0;
556 n:= 0;
557 pH:= 5.4;
558 deltapH:= 0.001;
559 deltapd:= 0.1;
560 pd:= ProtonDeficit(pH);
561 while ((pd < PrDef-deltapd) or (pd > PrDef + deltapd)) and (n < 1000) do
562 begin
563 inc(n);
564 if pd < PrDef-deltapd then ph:= ph - deltapH
565 else if pd > PrDef+deltapd then pH:= pH + deltapH;
566 pd:= ProtonDeficit(pH);
567 end;
568 Result:= pH;
569 end;
570
571 function TWater.GetAlkalinity: double;
572 begin
573 Result := FBicarbonate.Value / 1.22; //mEq/l
574 end;
575 414
576 function TWater.GetHardness: double; 415 function TWater.GetHardness: double;
577 begin 416 begin
578 Result := 0.14 * FCalcium.Value - 0.23 * FMagnesium.Value; 417 Result := 0.14 * FCalcium.Value - 0.23 * FMagnesium.Value;
579 end; 418 end;
588 begin 427 begin
589 pHDemi := FRecipe.pHdemi; 428 pHDemi := FRecipe.pHdemi;
590 S := 0.013 * FRecipe.MashThickness + 0.013; 429 S := 0.013 * FRecipe.MashThickness + 0.013;
591 Result := pHDemi + ResidualAlkalinity / 50 * S; 430 Result := pHDemi + ResidualAlkalinity / 50 * S;
592 end;} 431 end;}
593 end;
594
595
596 function TBeerStyle.GetBUGUMin: double;
597 var
598 B, G: double;
599 begin
600 Result:= 0;
601 if ((FOGMax.Value + FOGMin.Value) > 0) and ((FIBUMax.Value + FIBUMin.Value) > 0) then
602 begin
603 G := (FOGMax.Value - FOGMin.Value) / ((FOGMax.Value + FOGMin.Value) / 2);
604 B := (FIBUMax.Value - FIBUMin.Value) / ((FIBUMax.Value + FIBUMin.Value) / 2);
605 if G > B then
606 Result := ((FIBUMin.Value + FIBUMax.Value) / 2) / (1000 * (FOGMax.Value - 1))
607 else
608 Result := FIBUMin.Value / (1000 * (((FOGMax.Value + FOGMin.Value) / 2) - 1));
609 end;
610 end;
611
612 function TBeerStyle.GetBUGUMax: double;
613 var
614 B, G: double;
615 begin
616 Result:= 0;
617 if ((FOGMax.Value + FOGMin.Value) > 0) and ((FIBUMax.Value + FIBUMin.Value) > 0)
618 and (FOGMin.Value > 1) then
619 begin
620 G := (FOGMax.Value - FOGMin.Value) / ((FOGMax.Value + FOGMin.Value) / 2);
621 B := (FIBUMax.Value - FIBUMin.Value) / ((FIBUMax.Value + FIBUMin.Value) / 2);
622 if G > B then
623 Result := ((FIBUMin.Value + FIBUMax.Value) / 2) / (1000 * (FOGMin.Value - 1))
624 else
625 Result := FIBUMax.Value / (1000 * (((FOGMax.Value + FOGMin.Value) / 2) - 1));
626 end;
627 end;
628
629
630 // Get concentration of ions in diluted brewwater (1) and target water (2) in mmol/l
631 Ca1 := W.Calcium.Value / MMCa;
632 Ca2 := W2.Calcium.Value / MMCa;
633 Mg1 := W.Magnesium.Value / MMMg;
634 Mg2 := W2.Magnesium.Value / MMMg;
635 Na1 := W.Sodium.Value / MMNa;
636 Na2 := W2.Sodium.Value / MMNa;
637
638 CO31 := W.Bicarbonate.Value / MMHCO3;
639 CO32 := W2.Bicarbonate.Value / MMHCO3;
640 SO41 := W.Sulfate.Value / MMSO4;
641 SO42 := W2.Sulfate.Value / MMSO4;
642 Cl1 := W.Sulfate.Value / MMSO4;
643 Cl2 := W2.Sulfate.Value / MMSO4;
644
645
646 procedure TRecipe.CalcWaterBalance;
647 var
648 i: integer;
649 F: TFermentable;
650 begin
651 FAbsorbedByGrain := 0;
652 for i := Low(FFermentables) to High(FFermentables) do
653 begin
654 F := TFermentable(FFermentables[i]);
655 if (F.FermentableType = ftGrain) or (F.FermentableType = ftAdjunct) then
656 FAbsorbedByGrain := FAbsorbedByGrain + F.Amount.Value;
657 end;
658 FAbsorbedByGrain := FAbsorbedByGrain * Settings.GrainAbsorption.Value;
659
660 if FEquipment.CalcBoilVolume.Value then
661 {FBoilSize.Value := FBatchSize.Value / (1 - (FEquipment.EvapRate.Value / 100) *
662 (FBoilTime.Value / 60));}
663 FBoilSize.Value:= FBatchSize.Value + FEquipment.BoilSize.Value
664 * FEquipment.EvapRate.Value / 100 *
665 (FBoilTime.Value / 60);
666 end; 432 end;
667 433
668 434
669 435
670 436

mercurial