scaling of a N/Z type nomogram

Mathematics about graphical computing
kloekwil
Posts: 10
Joined: Mon Dec 29, 2014 8:00 pm

scaling of a N/Z type nomogram

I got interested in nomograms because of its simplicity to do calculations while not having a pc etc at hand. It appears to be useful for my beer brewing hobby.

In short:
When brewing beer one starts with a sugary solution with a certain Original Gravity (OG). Yeast ferments the sugars leading to a decrease in gravity and at the end the gravity is FG (Final Gravity). The degree of fermentation (ADF) at the end of fermentation is calculated from the OG and FG by:

Gravity is normally measured using a hydrometer yielding specific gravities. However nowadays it is more common to measure the starting and final gravities using a Brix meter.
Goal: Therefor I want to derive a nomogram to construct the ADF from the staring Brix (B0) and final Brix (B1).

All the equations are there and I converted it to a determinant. It yields a Z-type of nomogram. The problem however is the small scale for the B0 and B1 line compared to the ADF scale which makes it impossible to do a reading.
Question: How do I apply a scaling to get the B0 and B1 lines on a similar scale compared to the ADF line?

The longer version with equations:

OG=259/(259-B0)
FG=a+b*B0+c*B0^2+d*B0^3 + e*B1+f*B1^2+g*B1^3 ..(a…g are constants)
ADF=(OG-FG)/(OG-1) ..(OG>1 and FG>=1 and OG>FG) ADF varies from 0 to 1 but ADF is typically 0,5 to 0,9

B0 and B1 typically vary between 0 and say 20 where B0>=B1

I used the following functions to construct the determinant:
FG(B0,B1)=g(v)+f(w)
g(v)= a+b*B0+c*B0^2+d*B0^3
f(w)= e*B1+f*B1^2+g*B1^3
f(v)=OG= 259/(259-B1)

f(u)=(f(v)-(g(v)+f(w))/(f(v)-1)

Determinant:
x ------------------------- y ----------------------
________________________________________________
f(u) -----------------------1 --------------------- 1 = ADF
(f(v)-g(v))/f(v) --------- (f(v)-1)/f(v) --------- 1 = Function of B0
f(w) ---------------------- 0---------------------- 1 =Function of B1

Below the constructed chart of B0, B1 and ADF demonstrating the problem: one wants to draw a line through B1 and B0 reading the final ADG. However the difference in scale make it impossible to use (yet ) The chart is plotted for realistic values of B0, B1 and ADF

In a later stage I also would like to add also the OG and FG lines since often these are used in combination with B0 and B1 and of course incorporate this in PyNomo-software.

I just installed the PyNomo-software and it works. When having a lead to an answer to my question I will see if it easy to learn the python language and make a nice nomogram.

But first things first.... scaling

Thanks in advance for having a look at my challenge.
William Last edited by kloekwil on Sun Jan 04, 2015 3:14 pm, edited 1 time in total.
jasonwalker
Posts: 27
Joined: Sun Sep 11, 2011 3:54 pm

Re: scaling of a N/Z type nomogram

Hi William,

Welcome aboard. There's a short answer and a long answer - I'm off to catch a boat, so I'll give the short one. I'll post the longer one in a few days if no-one beats me to it.

There are transforming constants you can apply to your determinant, but I'd have to look them up. Abbott or Levens (standard texts) would have them (off the top of my head). That would be the long answer.

Short one. Use the transform_ini function in pynomo - it will automatically stretch the nomogram to the shape of the block. Specifically:
In the ADF and B1 params, include (as well as max and min) u_min_trafo and u_max_trafo, set to the same values as the max and min. When specifying the block params have a height and width, and then include the line

'transform_ini':True,

The rest works like magic. I haven't manually transformed a nomogram in ages!

There's more info in the type 9 documentation. http://pynomo.org/wiki/index.php?title=Type_9

Anyway, apologies if that's a bit brief, my boat awaits.

Jason
kloekwil
Posts: 10
Joined: Mon Dec 29, 2014 8:00 pm

Re: scaling of a N/Z type nomogram

Hi Jason,

Thanks for you reply. I hope your post has not prevented you to catch the boat Although nomograms are new to me and math classes seem history I would first like to know what I am doing, so I prefer the long way (but I enjoy doing it). There will always be time for the short answer.

The names of Abbott and Levens lead me to an article on the Dead Reckonings site on transformations.

thanks so far,
William
kloekwil
Posts: 10
Joined: Mon Dec 29, 2014 8:00 pm

Re: scaling of a N/Z type nomogram

... and the article about transformations on the Dead Reckoning site lead me to the following nomogram. I used the projection point technique. The data were generated in excel. It gave the best results for xp=0,17, yp=0,17 and zp did not have a large effect on the nomogram.

The B0-line could have some better accuracy in the region B0=12-20 since normally readings are made with an accuracy of 0,1
The B1-line could have some better accuracy in the region B1=5-11 since normally readings are made with an accuracy of 0,1
Accuracy of the ADF-line is perfect.

So far I am happy. Tomorrow I will try to make some further steps. kloekwil
Posts: 10
Joined: Mon Dec 29, 2014 8:00 pm

Re: scaling of a N/Z type nomogram

Indeed, it is very easy to have a nomogram automatically scaled with PyNomo, specially when one uses the polygon option.

Initially I perfomed the projection scaling by adding this to determinant and that yielded the same result as posted before.

Then I used the polygon-option in Pynome starting with the most simple determinant and it yielded even a better picture. Great software!

Two questions remain:

When using the polygon-option the command line showed the following output: -0.0 25.0 18.0 -1.59869325324e-15 17.999863027 10.9003467454 2.45995921436 12.4673339603. What does it mean?

A Python question: how can functions be defined that can be used in the parameter block. I tried to define functions and use combination of defined functions in the parameter block. This resulted in errors.
See below for the code for the B0-params. It defines functions f(u) and g(u) and I wanted to use it in B0-params via 'f':(fu-gu)/fu but that was not accepted. Therefor i just wrote out the equation in full.

As a next step I will try to add the OG-scale which runs parallel to the B0-scale.
Furthermore I also want to add the FG-scale which will require more effort

Any way thanks for the feedback.

Code: Select all

def fu(u):
return 259/(259-u/corr)

def gu(u):
return a+b*u+c*u**2+d*u**3

def fv(v):
return ee*v+ff*v*2+gg*v**3

B0_params={
'u_min':10,
'u_max':22,
'u_min_trafo':0.5,
'u_max_trafo':22,
#'f':(fu-gu)/fu,
#'g':(fu-1)/fu,
'f':lambda u:((259/(259-u/corr)-(a+b*u+c*u**2+d*u**3))/(259/(259-u/corr))),
'g':lambda u:((259/(259-u/corr)-1)/(259/(259-u/corr))),
'h':lambda u:1.0,
'title':'B0',
'tick_side':'right',
'tick_levels':3,
'tick_text_levels':2 kloekwil
Posts: 10
Joined: Mon Dec 29, 2014 8:00 pm

Re: scaling of a N/Z type nomogram

kloekwil wrote:As a next step I will try to add the OG-scale which runs parallel to the B0-scale.

I run into a problem for which I cannot find a solution in the examples. I want to align the B0-line from the type-9 nomogram dervied above with an alternative OG-line which is a simple function of B0 (OG=(259/(259-B0/corr)) .
I am able to do this for the type-8 nomograms when I take the BO-function and the inverse function (see code below) but how to perform this in combination with the type-9 nomogram since there are 3 functions to align with. Do I need to come up with 3 align functions for f, g and h?

A hint to point me in the right direction is appreciated Code: Select all

"""
B0-OG-plot.py

"""
from pynomo.nomographer import *

corr=1.03

def OG(B0):
return 259/(259-B0/corr)

def inv_OG(OG):
return corr*(259-259/OG)

B0_para={
'tag':'Start',
'u_min':5,
'u_max':25,
'function':lambda B0:OG(B0),
'title':r'B0',
'tick_levels':3,
'tick_text_levels':1,
'tick_side':'left',
'title_x_shift':-0.5
}

OG_para={
'tag':'Start',
'u_min':1.020,
'u_max':1.100,
'function':lambda OG:OG,
'align_func':lambda OG:inv_OG(OG),
'title':r'OG',
'tick_levels':3,
'tick_text_levels':1,
'tick_side':'right',
'title_x_shift':0.5,
'text_format':r"\$%.3f\$"
}

B0_block={
'block_type':'type_8',
'f_params':B0_para
}
OG_block={
'block_type':'type_8',
'f_params':OG_para
}

main_params={
'filename':'B0-OG plot.pdf',
'paper_height':20.0,
'paper_width':2.0,
'block_params':[B0_block,OG_block],
'transformations':[('scale paper',)]
}
Nomographer(main_params)

kloekwil wrote:Furthermore I also want to add the FG-scale which will require more effort

This FG-scale cannot run parallel with the B1 scale since it also depends on the value of BO (or OG). What would be the best approach to incorporate FG?

At the end ithe nomogram should allow to determine the ADF by one of the following (depending on the measurement that is made at the start and at the end):
BO and B1 (that one I have)
OG and B1
OG and FG
B0 and FG

It was fun to work on this during the xmass-break . I am really surprised by the abilities if PyNomo. If I get a real grip on how this works I would like to incorporate more brewing related calculations.

thanks, William
jasonwalker
Posts: 27
Joined: Sun Sep 11, 2011 3:54 pm

Re: scaling of a N/Z type nomogram

Hello again!

Gosh, you've been busy. And that's turning into a really nice nomogram. I'd suggest tidying up the scale lengths: the bottom section of the B1 scale doesn't appear to be serving much function - I'd either chop it off or extend B0. But you're the expert. When it's done, I'd suggest trying to get it published in a brewing periodical or journal. I think a lot of people would consider it useful!

You seem to have answered many of your own questions yourself - for example I see that you sorted out the defining function issue.

The OG/B0 scale issue is straightforward. Just align it with B0_params, the rest of the nomogram will take care of itself. The B1 scale is more difficult - but not insurmountable. Without getting stuck into the algebra, I'd suggest the following approach.

Design a nomogram which has B0, FG and AGF - hopefully you can design it in such a way that the B0 and ADF functions coincide exactly with your existing nomogram, and the B1 scale lies somewhere in between. Then align the outer scales to overlie the two nomograms. This is what I normally do.

A more complex - but more elegant - solution is to use a grid for the middle scale, a function of B1 on the vertical scale and of k*(B0) on the horizontal, where k is 0 or 1. Where k=0, this would be the existing B1 scale, and where k=1 is the FG scale. Not sure whether this is doable, as I haven't looked at the algebra. Whenever I've done this sort of thing I've just overlain two nomograms.

If you manage it, it means that the nomogram will not only be able to calculate ADF from B0 and B1, but would also give you OG and FG - which may be of interest to someone!

As to your question on the command line output, I have absolutely no idea. Nice work. And don't worry, I caught the boat.

Jason
kloekwil
Posts: 10
Joined: Mon Dec 29, 2014 8:00 pm

Re: scaling of a N/Z type nomogram

jasonwalker wrote:The OG/B0 scale issue is straightforward. Just align it with B0_params, the rest of the nomogram will take care of itself. The B1 scale is more difficult - but not insurmountable. Without getting stuck into the algebra, I'd suggest the following approach.

Thanks for your reaction Jason!

The OG/B0 scale is so straightforward that I don't get them aligned Whatever I do the OG line appears very tiny in the bottom left or bottom right corner of the current nomogram.

What did I do:
I added an OG_params block with a function giving the OG function corresponding to the B0_values
I added to this block the align_function that is the inverse of the OG_function
I added a tag 'start' to the B0_params and to the OG_params
I created a block_params for type * for the OG_params.

I think something goes wrong with either the u_min and u_max values or the function in OG_params. I tried al possible combinations but the OG-scale is at a bottom cornes not even touching the B0-line

See below for the code. What goes wrong?

To finalise with something positive: I also created a type-9 nomogram for the OG-FG-ADF situation which looks similar to the B0-B1-ADF nomogram i.e. OG and BO are both vertical line at the left hand-side and ADF is in both nomograms a vertical line at the right-hand side.

Code: Select all

"""
Fermentation_incl_OG.py

The original gravity OG is the a simple function of B0:
OG = 259/(259-B0/corr))  where corr is a correction constant ranging from 1,02 to 1,04 (assume 1,03)
The final gravity (FG) depends on both the sugar content and the alcohol content and therefore depends on both B0 and B1.
FG = a+b*B0+c*B0^2+d*B0^3  +  e*B1+f*B1^2+g*B1^3
a=1,0031; b=-2,318474e-3; c=-7,775e-6; d=3,4e-8; e=5,74e-3; f=3,344e-5; g=8,6e-8

Goal is to have a nomogram for reading ADF as function of B0 and B1.
Later OG, FG and even alcohol content could be added

Typical values:
ADF = 0,5 - 1,1
B0 = 10 - 22
B1 = 2 - 12
OG=1,030 - 1,200
FG=0,990 - 1,025

Definitions:
f(u)=259/(259-B0/corr)
g(u)=a+b*B0+c*B0^2+d*B0^3
f(v)=e*B1+f*B1^2+g*B1^3

Leads to the following determinant

---------------------------------------------
| (f(u)-g(u))/f(u)| (f(u)-1)/f(u) |      1  |         B0 terms
---------------------------------------------
|         f(v)    |          0    |      1  |  =0      B1-terms
---------------------------------------------
|         f(w)    |          1    |      1  |         ADF
---------------------------------------------

Copyright (C) 2007-2012  Leif Roschier

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
"""
from pynomo.nomographer import *

corr=1.03
a=1.0031
b=-2.318474e-3
c=-7.775e-6
d=-3.4e-8
e=5.74e-3
f=3.344e-5
g=8.6e-8

def fu(u):
return 259/(259-u/corr)     #function for OG , u=B0

def gu(u):
return a+b*u+c*u**2+d*u**3

def fv(v):
return e*v+f*v*2+g*v**3      #v=B1

def fw(w):

def OG(u):
return 259/(259-u/corr)      #calculates OG-value from B0

def inv_OG(OG):
return corr*(259-259/OG)   #calculates B0-value from OG

B0_params={
'tag':'start',
'u_min':9,
'u_max':22,
'u_min_trafo':0.5,
'u_max_trafo':22,
'f': lambda u:(fu(u)-gu(u))/fu(u),
'g': lambda u:(fu(u)-1)/fu(u),
'h': lambda u:1.0,
'title':'B0',
'tick_side':'right',
'tick_levels':3,
'tick_text_levels':2
}
B1_params={
'u_min':3,
'u_max':12,
#'u_min_trafo':0.5,
#'u_max_trafo':1,
#f':fv,
'f':lambda v:fv(v),
'g':lambda v:0,
'h':lambda v:1.0,
'title':'B1',
'tick_side':'left',
'tick_levels':4,
'tick_text_levels':2
}
'u_min':0.5,
'u_max':1.0,
'u_min_trafo':0.5,
'u_max_trafo':22,
'f':lambda w:fw(w),
'g':lambda w:1.0,
'h':lambda w:1.0,
'tick_side':'left',
'tick_levels':4,
'tick_text_levels':2,
}

block_params={
'block_type':'type_9',
'f1_params':B0_params,
'f2_params':B1_params,
'transform_ini':True,
'isopleth_values':[[19.1,9.3,'x']]
}

OG_params={
'tag':'start',
'u_min':OG(9),
'u_max':OG(22),
'function':lambda u:u,
'align_func':lambda u:inv_OG(u),
'tick_side':'right',
'tick_levels':3,
'tick_text_levels':2
}

block2_params={
'block_type':'type_8',
'f_params':OG_params,
}

main_params={
'filename':'fermentation incl SG.pdf',
'paper_height':25.0,
'paper_width':18.0,
'block_params':[block_params, block2_params],
'transformations':[('rotate', 0.001),('scale paper',),('polygon',)],
'isopleth_params':[
{'color':'red',
'linewidth':'thick',
'linestyle':'dashed',
'circle_size':0.06,
'transparency':0.0,
},
],
}
Nomographer(main_params)
jasonwalker
Posts: 27
Joined: Sun Sep 11, 2011 3:54 pm

Re: scaling of a N/Z type nomogram

Not sure. I've tried lining the new scale up with no conversion factor - so essentially you should get the same scale on either side - but even that doesn't completely line up. Perhaps some of the other members may have a clue (you may have noticed, it's a slow moving forum!)
I think the numbers are Isopleth calculations, by the way.

The transform ini and u_min_trafo values, by the way, refer to the out edges of the 'rectangle' holding the nomogram. So for B0 min is 0 and max is 22, but for ADF min should be 1 and max 0.5 - the scale is upside down. if you then add

Code: Select all

'height':25.0,
'width':18.0,

to the block params for the type 9, it will transform the whole thing very nicely. I'd use that and ditch the polygon transform.

Hmmm. Anyone else got any ideas?
kloekwil
Posts: 10
Joined: Mon Dec 29, 2014 8:00 pm

Re: scaling of a N/Z type nomogram

I think the problem lies in making a block of the B0_params which is part of the type-9 nomogram and the OG_params which is part of the type-8 nomogram. They are coupled by the tag "start" and the function and align function. In the OG_params i doubt about the 'function" since it looks so different from the functions below.

When I make a single nomogram of B0 and OG the scale perfectly align..

B0_params (transformed)

Code: Select all

'f': lambda u:(fu(u)-gu(u))/fu(u),
'g': lambda u:(fu(u)-1)/fu(u),
'h': lambda u:1.0,

OG_params

Code: Select all

'function':lambda u:u,   #u = OG calculated fom B0)
'align_func':lambda u:inv_OG(u),

jasonwalker wrote:Perhaps some of the other members may have a clue (you may have noticed, it's a slow moving forum!)

I hope so because I am stuck right now.

thanks,William
jasonwalker
Posts: 27
Joined: Sun Sep 11, 2011 3:54 pm

Re: scaling of a N/Z type nomogram

I'll admit, I haven't yet delved into your algebra - hopefully I might get a chance over the weekend...

J
Glen
Posts: 67
Joined: Fri Jan 25, 2008 4:11 am
Location: Australia

Re: scaling of a N/Z type nomogram

Sorry to have missed all the excitement.

I'll try to have a look to see what I can do with B1.

An ADF/OG/FG one can be done with 3 parallel scales, which means you could do it with a "slide rule" device.

(You may not be able to get all 5 variables on a single scale.)
kloekwil
Posts: 10
Joined: Mon Dec 29, 2014 8:00 pm

Re: scaling of a N/Z type nomogram

Glen wrote:Sorry to have missed all the excitement.

I'll try to have a look to see what I can do with B1.

An ADF/OG/FG one can be done with 3 parallel scales, which means you could do it with a "slide rule" device.

(You may not be able to get all 5 variables on a single scale.)

Welcome back Glen I can imagine that a five-parameter nomogram will be hard. From a practical point of view two single nomograms ( B0-B1/FG-ADF) and (B0/OG-B1-ADF) would already be great.

When trying to align the og-line with the B0 line the og line ends up somewhere below the B1-line...
Glen
Posts: 67
Joined: Fri Jan 25, 2008 4:11 am
Location: Australia

Re: scaling of a N/Z type nomogram

[quote="kloekwil"]
When trying to align the og-line with the B0 line the og line ends up somewhere below the B1-line...[/quote]

Hmm, it's easy enough to do by hand:

[img]http://i.imgur.com/DQvK14L.jpg [/img]

so I'm certain Pynomo can do it

... Hey, how do you get the images to show up in this?
Last edited by Glen on Wed Feb 04, 2015 5:27 am, edited 2 times in total.
kloekwil
Posts: 10
Joined: Mon Dec 29, 2014 8:00 pm

Re: scaling of a N/Z type nomogram

Glen wrote:
kloekwil wrote:... Hey, how do you get the images to show up in this?

Just by adding: " [_img]http://i.imgur.com/DQvK14L.jpg [_/img] (remove underscores) that yields Glen wrote:
kloekwil wrote:When trying to align the og-line with the B0 line the og line ends up somewhere below the B1-line...

Hmm, it's easy enough to do by hand:
so I'm certain Pynomo can do it

... Hey, how do you get the images to show up in this?

So you made this image by hand?

I tried to this this with Pynomo but have need been succesfull so far.

I was able to make the simple B0-OG plot which looks like your plot:

Code: Select all

"""
B0-OG-plot.py

"""
from pynomo.nomographer import *

corr=1.03

def OG(B0):
return 259/(259-B0/corr)

def inv_OG(OG):
return corr*(259-259/OG)

B0_para={
'tag':'Start',
'u_min':5,
'u_max':25,
'function':lambda B0:OG(B0),
'title':r'B0',
'tick_levels':3,
'tick_text_levels':1,
'tick_side':'left',
'title_x_shift':-0.5
}

OG_para={
'tag':'Start',
'u_min':1.020,
'u_max':1.100,
'function':lambda OG:OG,
'align_func':lambda OG:inv_OG(OG),
'title':r'OG',
'tick_levels':3,
'tick_text_levels':1,
'tick_side':'right',
'title_x_shift':0.5,
'text_format':r"\$%.3f\$"
}

B0_block={
'block_type':'type_8',
'f_params':B0_para
}
OG_block={
'block_type':'type_8',
'f_params':OG_para
}

main_params={
'filename':'B0-OG plot.pdf',
'paper_height':20.0,
'paper_width':2.0,
'block_params':[B0_block,OG_block],
'transformations':[('scale paper',)]
}
Nomographer(main_params)

Which gives the following plot: But when trying to align the function from the type-8 and the type-9 B0-functions I get something like this: 