www/includes/formulas.php

Wed, 02 Jan 2019 17:34:53 +0100

author
Michiel Broek <mbroek@mbse.eu>
date
Wed, 02 Jan 2019 17:34:53 +0100
changeset 164
0a5abea575a9
parent 147
e6e5d007eb54
child 231
9881453a49b3
permissions
-rw-r--r--

Added the last tab, fermentation to the product editer.

<?php

define('EURO', chr(128));

define('MMCa', '40.048');
define('MMMg', '24.305');
define('MMNa', '22.98976928');
define('MMCl', '35.453');
define('MMSO4', '96.0626');
define('MMCO3', '60.01684');
define('MMHCO3', '61.01684');
define('MMCaSO4', '172.171');
define('MMCaCl2', '147.015');
define('MMCaCO3', '100.087');
define('MMMgSO4', '246.475');
define('MMNaHCO3', '84.007');
define('MMNa2CO3', '105.996');
define('MMNaCl', '58.443');
define('MMCaOH2', '74.06268');


function ebc_to_srm($ebc)
{
	$srm = -1.32303E-12 * pow($ebc, 4) - 0.00000000291515 * pow($ebc, 3) + 0.00000818515 * pow($ebc, 2) + 0.372038 * $ebc + 0.596351;
	if (($ebc < 0) || ($srm < 0))
		syslog(LOG_NOTICE, "ebc_to_srm(".$ebc.") = ".$srm);
	return $srm;
}



function srm_to_ebc($srm)
{
	// Formule van Adrie Otten. brouwhulp.
	$ebc = round( 0.000000000176506 * pow($srm, 4) + 0.000000154529 * pow($srm, 3) - 0.000159428 * pow($srm, 2) + 2.68837 * $srm - 1.6004 );
	if (($ebc < 0) || ($srm < 0))
		syslog(LOG_NOTICE, "srm_to_ebc(".$srm.") = ".$ebc);
	return $ebc;
}



function ebc_to_color($ebc)
{
	return srm_to_color(ebc_to_srm($ebc));
}



function srm_to_color($srm)
{
	$i = abs($srm * 10);
	if ($i < 0) {
		$i = 0;
	}
	if ($i > 299) {
		$i = 299;
	}

	/* Table copied from Brouwhulp/BrewBuddy */
	$R = array( 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,	// 0
 		    250, 250, 250, 250, 250, 249, 248, 247, 246, 245, 244, 243, 242, 241, 240, 239, 238, 237, 236, 235,	// 2
		    234, 233, 232, 231, 230, 229, 228, 227, 226, 225, 224, 223, 222, 221, 220, 219, 218, 217, 216, 215,	// 4
		    214, 213, 212, 211, 210, 209, 208, 207, 206, 205, 204, 203, 202, 201, 200, 200, 199, 199, 198, 198,	// 6
		    197, 197, 196, 196, 195, 195, 194, 194, 193, 193, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,	// 8
		    192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,	// 10
		    192, 192, 192, 192, 192, 192, 192, 192, 191, 190, 189, 188, 187, 186, 185, 184, 183, 182, 181, 180,	// 12
		    179, 178, 177, 175, 174, 172, 171, 169, 168, 167, 195, 164, 162, 161, 159, 158, 157, 155, 154, 152,	// 14
		    151, 149, 148, 147, 145, 144, 142, 141, 139, 138, 137, 135, 134, 132, 131, 129, 128, 127, 125, 124,	// 16
		    122, 121, 119, 118, 117, 115, 114, 112, 111, 109, 108, 107, 105, 104, 102, 101,  99,  98,  97,  95,	// 18
		     94,  92,  91,  89,  88,  87,  85,  84,  82,  81,  79,  78,  77,  75,  74,  72,  71,  69,  68,  67,	// 20
		     65,  64,  62,  61,  59,  58,  57,  55,  54,  52,  51,  49,  48,  47,  45,  44,  43,  41,  39,  38,	// 22
		     37,  37,  36,  36,  35,  35,  34,  34,  33,  33,  32,  32,  31,  31,  30,  30,  29,  29,  28,  28,	// 24
		     27,  27,  26,  26,  25,  25,  24,  24,  23,  23,  22,  22,  21,  21,  20,  20,  19,  19,  18,  18,	// 26
		     17,  17,  16,  16,  15,  15,  14,  14,  13,  13,  12,  12,  11,  11,  10,  10,   9,   9,   8,   8 );

	$G = array( 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,
		    250, 250, 250, 250, 250, 250, 249, 248, 247, 246, 245, 244, 242, 240, 238, 236, 234, 232, 230, 228,
		    226, 224, 222, 220, 218, 216, 214, 212, 210, 208, 206, 204, 202, 200, 198, 196, 194, 192, 190, 188,
		    186, 184, 182, 180, 178, 176, 174, 172, 170, 168, 166, 164, 162, 160, 158, 156, 154, 152, 150, 148,
		    146, 144, 142, 141, 140, 139, 139, 138, 137, 136, 136, 135, 134, 133, 133, 132, 131, 130, 130, 129,
		    128, 127, 127, 126, 125, 124, 124, 123, 122, 121, 121, 120, 119, 118, 118, 117, 116, 115, 115, 114,
		    113, 112, 112, 111, 110, 109, 109, 108, 107, 106, 106, 105, 104, 103, 103, 102, 101, 100, 100,  99,
		     98,  97,  97,  96,  95,  94,  94,  93,  92,  91,  91,  90,  89,  88,  88,  87,  86,  85,  85,  84,
		     83,  82,  82,  81,  80,  79,  78,  77,  76,  75,  75,  74,  73,  72,  72,  71,  70,  69,  69,  68,
		     67,  66,  66,  65,  64,  63,  63,  62,  61,  60,  60,  59,  58,  57,  57,  56,  55,  54,  54,  53,
		     52,  51,  51,  50,  49,  48,  48,  47,  46,  45,  45,  44,  43,  42,  42,  41,  40,  39,  39,  38,
		     37,  36,  36,  35,  34,  33,  33,  32,  31,  30,  30,  29,  28,  27,  27,  26,  25,  24,  24,  23,
		     22,  22,  22,  21,  21,  21,  20,  20,  20,  19,  19,  19,  18,  18,  18,  17,  17,  17,  16,  16,
		     16,  15,  15,  15,  14,  14,  14,  13,  13,  13,  12,  12,  12,  11,  11,  11,  10,  10,  10,   9,
		      9,   9,   8,   8,   8,   7,   7,   7,   6,   6,   6,   5,   5,   5,   4,   4,   4,   3,   3,   3 );

	$B = array( 210, 204, 199, 193, 188, 182, 177, 171, 166, 160, 155, 149, 144, 138, 133, 127, 122, 116, 111, 105,
		    100,  94,  89,  83,  78,  72,  67,  61,  56,  50,  45,  45,  45,  46,  46,  46,  46,  47,  47,  47,
		     47,  48,  48,  48,  48,  49,  49,  49,  49,  50,  50,  50,  50,  51,  51,  51,  51,  52,  52,  52,
		     52,  53,  53,  53,  53,  54,  54,  54,  54,  55,  55,  55,  55,  56,  56,  56,  56,  56,  56,  56,
		     56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,
		     56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,
		     56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,  56,
		     56,  56,  56,  55,  55,  55,  55,  54,  54,  54,  54,  53,  53,  53,  53,  52,  52,  52,  52,  51,
		     51,  51,  51,  50,  50,  50,  50,  49,  49,  48,  47,  47,  46,  45,  45,  44,  43,  43,  42,  41,
		     41,  40,  39,  39,  38,  37,  37,  36,  35,  34,  33,  32,  31,  29,  28,  27,  26,  25,  24,  23,
		     21,  20,  19,  18,  17,  16,  15,  13,  12,  11,  10,   9,   8,   9,   9,  10,  10,  11,  11,  12,
		     12,  13,  13,  14,  14,  15,  15,  16,  16,  17,  17,  18,  18,  19,  19,  20,  20,  21,  21,  22,
		     21,  21,  21,  20,  20,  20,  19,  19,  19,  18,  18,  18,  17,  17,  17,  17,  16,  16,  15,  15,
		     15,  14,  14,  14,  13,  13,  13,  12,  12,  12,  11,  11,  11,  10,  10,  10,   9,   9,   9,   8,
		      8,   8,   7,   7,   7,   6,   6,   6,   5,   5,   5,   4,   4,   4,   3,   3,   3,   2,   2,   2 );

	return array($R[$i],$G[$i],$B[$i]);
}



function sg_to_plato($sg) {
	if ($sg > 0.5)
		return 259 - 259 / $sg;
	return 0;
}



function plato_to_sg($plato) {
	if ($plato < 259)
		return 259 / (259 - $plato);
	return 1.000;
}



/*
 * sugars is the total extract weight of sugars.
 */
function estimate_sg($sugars, $batch_size) {
	$plato = 100 * $sugars / $batch_size;
	$sg = plato_to_sg($plato);

	/* Average loops, HansH 5x. Brouwhulp 20x, about 10x is enough so keep 20. */
	for ($i = 0; $i < 20; $i++) {
		if ($sg > 0)
			$plato = 100 * $sugars / ($batch_size * $sg);
		$sg = plato_to_sg($plato);
	}
	return $sg;
}



function estimate_fg($percSugar, $percCara, $WGratio, $TotTme, $Temp, $attenuation, $og) {
	if ($percSugar > 40)
		$percSugar = 0;
	if ($percCara > 50)
		$percCara = 0;
	if (($WGratio > 0) && ($TotTme > 0)) {
		$BD = $WGratio;
		$BD = max(2, min(5.5, $BD));
		$Temp = max(60, min(72, $Temp));
	} else {
		$BD = 3.5;
		$Temp = 67;
		$TotTme = 75;
	}
	if ($attenuation < 30)
		$attenuation = 77;

	$AttBeer = 0.00825 * $attenuation + 0.00817 * $BD - 0.00684 * $Temp + 0.00026 * $TotTme - 0.00356 * $percCara + 0.00553 * $percSugar + 0.547;
	$fg = 1 + (1 - $AttBeer) * ($og - 1);
	return $fg;
}



function abvol($og, $fg) {
	if ((4.749804 - $fg) <> 0)
		return 486.8693 * ($og - $fg) / (4.749804 - $fg);
	return 0;
}


/*
 * Kleurwerking naar SRM
 */
function kw_to_srm($colormethod, $c) {

	if ($colormethod == "Morey")
		return 1.4922 * pow($c, 0.6859);
	if ($colormethod == "Mosher")
		return 0.3 * $c + 4.7;
	if ($colormethod == "Daniels")
		return 0.2 * $c + 8.4;
}



function kw_to_ebc($colormethod, $c) {
	return srm_to_ebc(kw_to_srm($colormethod, $c));
}



function calc_IBU($useat, $form, $sg, $volume, $mass, $boiltime, $alpha, $method)
{
	global $my_factor_mashhop;
	global $my_factor_fwh;
	global $my_factor_pellet;
	global $my_factor_plug;

	$fmoment  = 1.0;
	if (($useat == "Dry Hop") || ($useat == "Dry hop") || ($useat == "Whirlpool") || ($useat == "Aroma")) {
		$fmoment = 0.0;
	} else if ($useat == "Mash") {
		$fmoment += $my_factor_mashhop / 100;         // Brouwhulp
	} else if (($useat == "First Wort") || ($useat == "First wort")) {
		$fmoment += $my_factor_fwh / 100;         // Brouwhulp, Louis, Ozzie
	}

	$pfactor  = 1.0;
	if ($form == "Pellet") {
		$pfactor += $my_factor_pellet / 100;
	}
	if ($form == "Plug") {
		$pfactor += $my_factor_plug / 100;
	}

	$ibu = 0;
	if (($method == "Tinseth") || ($method == "Garetz")) {	// For Garetz, we need the $ibu
		$AddedAlphaAcids = (($alpha / 100) * $mass * 1000) / $volume;
		$Bigness_factor = 1.65 * pow( 0.000125, $sg - 1);
		$BoilTime_factor = ((1 - exp(-0.04 * $boiltime)) / 4.15);
		$utiisation = $Bigness_factor * $BoilTime_factor;
		$ibu = (round($utiisation * $AddedAlphaAcids * $fmoment * $pfactor * 10) / 10.0);
	}
	if ($method == "Daniels") {

		if ($form == "Leaf")
			$boilfactor = -(0.0041*$boiltime*$boiltime)+(0.6162*$boiltime)+1.5779;
		else
			$boilfactor = -(0.0051*$boiltime*$boiltime)+(0.7835*$boiltime)+1.9348;
		if ($sg < 1.050)
			$sgfactor = 0;
		else
			$sgfactor = (($sg * 1000) - 1050) / 200;
		$ibu = $fmoment * (($mass * $alpha * $boilfactor * 0.1) / ($volume * (1 + $sgfactor)));
	}
	if ($method == "Rager") {
		$boilfactor = $fmoment * 18.11 + 13.86 * tanh(($boiltime * 31.32) / 18.27);
		if ($sg < 1.050)
			$sgfactor = 0;
		else
			$sgfactor = (($sg * 1000) - 1050) / 200;
		$ibu = ($mass * $alpha * $boilfactor * 0.1) / ($volume * (1 + $sgfactor));
	}
	if ($method == "Garetz") {
		/* Something is wrong, late hops and dryhops give negative results. */
		$boilfactor = $fmoment * 6.03253 + 16.5289 * tanh(($boiltime - 19.17323) / 26.8013);
		$cfactor = $volume / (1.1 * $volume);	// ConcentratieFactor = (Volume na koelen) / (Volume bij Koken)
		$kookdichtheid = ($cfactor * (($sg * 1000) - 1000) / 1000) + 1;
		$sgfactor = ($kookdichtheid - 1.05) / 0.2 + 1;
		$hopratefactor = (($cfactor * $ibu) / 260) + 1;	// $ibu is Tinseth bitterness. Weird.
		$tempfactor = (32.8/550)*0.02+1;
		$ibu = ($boilfactor * $alpha * $mass * 0.1) / ($volume * $sgfactor * $hopratefactor * $tempfactor);
	}
	/* TODO: Noonan and Mosher */

	return $ibu;
}



/*

Brouwhulp data.pas



Procedure TFermentable.SetpHParameters(force : boolean);
var x, ebc : double;
begin
  if Between(FDIpH.Value, -0.01, 0.01) or Between(FAcidTo57.Value, -0.1, 0.1) or force then
  begin
    ebc:= SRMtoEBC(FColor.Value);
    case FGrainType of
    gtBase, gtKilned:
    begin
      FDIpH.Value:= -0.0132 * ebc + 5.7605;
      x:= 0.4278 * ebc - 1.8106;
      FAcidTo57.Value:= x;
    end;
    gtRoast:
    begin
      FDIpH.Value:= 0.00018 * ebc + 4.558;
      FAcidTo57.Value:= -0.0176 * ebc + 60.04;
    end;
    gtCrystal:
    begin
      FDIpH.Value:= -0.0019 * ebc + 5.2175;
      FAcidTo57.Value:= 0.132 * ebc + 14.277;
    end;
    gtSour:
    begin
      FDIpH.Value:= 3.44;
      FAcidTo57.Value:= 337;
    end;
    gtSpecial: //this could be anything. Assume for now it is a non-acidulated base or kilned malt
    begin
      FDIpH.Value:= -0.0132 * ebc + 5.7605;
      FAcidTo57.Value:= 0.4278 * ebc - 1.8106;
    end;
    end;
  end;
  //known parameters should be filled in here
  if FSupplier.Value = 'Weyermann' then
  begin
    if FName.Value = 'Vienna mout' then
    begin
      FDIpH.Value:= 5.65;
      FAcidTo57.Value:= 1.6;
    end;
    if FName.Value = 'Münchner I' then
    begin
      FDIpH.Value:= 5.44;
      FAcidTo57.Value:= 8.4;
    end;
    if FName.Value = 'Münchner II' then
    begin
      FDIpH.Value:= 5.54;
      FAcidTo57.Value:= 5.6;
    end;
    if FName.Value = 'Caramunich I' then
    begin
      FDIpH.Value:= 5.1;
      FAcidTo57.Value:= 22.4;
    end;
    if FName.Value = 'Caramunich II' then
    begin
      FDIpH.Value:= 4.71;
      FAcidTo57.Value:= 49;
    end;
    if FName.Value = 'Caramunich III' then
    begin
      FDIpH.Value:= 4.92;
      FAcidTo57.Value:= 31.2;
    end;
    if FName.Value = 'Cara-aroma' then
    begin
      FDIpH.Value:= 4.48;
      FAcidTo57.Value:= 74.4;
    end;
    if FName.Value = 'Carafa I' then
    begin
      FDIpH.Value:= 4.71;
      FAcidTo57.Value:= 42;
    end;
    if FName.Value = 'Carafa III' then
    begin
      FDIpH.Value:= 4.81;
      FAcidTo57.Value:= 35.4;
    end;
    if FName.Value = 'Carafa II' then
    begin
      FDIpH.Value:= 4.76;
      FAcidTo57.Value:= 38.7;
    end;
    if FName.Value = 'Carafa Special I' then
    begin
      FDIpH.Value:= 4.73;
      FAcidTo57.Value:= 46.4;
    end;
    if FName.Value = 'Carafa Special II' then
    begin
      FDIpH.Value:= 4.78;
      FAcidTo57.Value:= 42.9;
    end;
    if FName.Value = 'Carafa Special III' then
    begin
      FDIpH.Value:= 4.83;
      FAcidTo57.Value:= 38.9;
    end;
    if IsInString(FName.Value, 'Zuurmout') then
    begin
      FDIpH.Value:= 3.44;
      FAcidTo57.Value:= 358.2;
    end;
  end;
end;


function TFermentable.GetExtract: double;
begin
  Result := 0;
  if FRecipe <> nil then
  begin
    Result := FAmount.Value * FYield.Value / 100 * (1 - FMoisture.Value / 100);
    if FAdded = atMash then
      Result := Result * FRecipe.Efficiency / 100;
  end;
end;


function TFermentable.GetKolbachIndex: double;
begin
  if FProtein.Value > 0 then
    Result := FDissolvedProtein.Value / FProtein.Value
  else
    Result := 0;
end;


function TWater.GetResidualAlkalinity: double;
begin
  //Result in mg/l as CaCO3
  Result:= FTotalAlkalinity.Value - (FCalcium.Value / 1.4 + FMagnesium.Value / 1.7);
end;


function TWater.GetHardness: double;
begin
  Result := 0.14 * FCalcium.Value - 0.23 * FMagnesium.Value;
end;

function TWater.GetEstPhMash: double;
{var
  pHdemi, S: double;}
begin
  Result:= MashpH;
{  Result := 0;
  if FRecipe <> nil then
  begin
    pHDemi := FRecipe.pHdemi;
    S := 0.013 * FRecipe.MashThickness + 0.013;
    Result := pHDemi + ResidualAlkalinity / 50 * S;
  end;}
end;





Procedure TRecipe.CalcCalories;
var sug, alc, org, fig : double;
begin
  if FOGFermenter.Value > 1.001 then org:= FOGFermenter.Value
  else if FOG.Value > 1.001 then org:= FOG.Value
  else org:= 0;
  if FFG.Value > 0.999 then fig:= FFG.Value
  else if FEstFG.Value > 1.000 then fig:= FEstFG.Value
  else if FEstFG2.Value > 1.000 then fig:= FEstFG2.Value
  else fig:= 0;
  if (org > 0) and (fig > 0) then
  begin
    alc:= 1881.22 * fig * (org - fig) / (1.775 - org);
    sug:= 3550 * fig * (0.1808 * org + 0.8192 * fig - 1.0004);
    FCalories.Value:= (alc + sug) / (12 * 0.0295735296);
  end
  else FCalories.Value:= 0;
end;




*/

?>

mercurial