Bulhmann decompression calculator (ZH16B)

Contributions to this software library are always welcome. Please ensure that you post program listings rather than .raw files. They give a reasonable idea of what your program does without having to load them into a DM42 and you can also include comments in your code. Check out the following link for a decoder/encoder: https://technical.swissmicros.com/decoders/dm42/

You can then copy/paste the listing and post it in "code" tags.
Post Reply
Boub65
Posts: 148
Joined: Tue Sep 12, 2017 4:34 pm
Location: Rabat, Morocco

Bulhmann decompression calculator (ZH16B)

Post by Boub65 »

=========================================
DISCLAIMER :
"zh16b" is a DM42 deco program is given for educational
purpose only (RPN deco calculations)
IT SHOULD NOT BE USED TO PLAN YOUR DIVES...
... although it gives same results (around 99%) as MULTIDECO ANDROID commercial planner!
=========================================

Version changes :
- 02/08/2021 : corrected some bugs and documented code
- 26/07/2021 : added surface interval and second dive computing
- 25/07/2021 : Corrected some bugs and documentation errors, split original program in 3 parts, documented code, added mix change during deco stops, added Trimix mixes using Erik Baker's gradient factors
- 21/07/2021 : First release with only Nitrox mixes, no deco mixe changes

Introduction :
This is the first version of a RPN deco planner using the Buhlmann algorithm, the ZH16B algorithm to be precise.
(https://en.m.wikipedia.org/wiki/B%C3%BC ... _algorithm)
The Buhlmann ZH16B algorithm uses a base of 16 M-Values (A and B) for Nitrogen and Helium decompression TABLES.
The program also uses Erik Baker's gradient factors when computing ceiling using Trimix (https://wrobell.dcmod.org/decotengu/model.html)

KNOWN LIMITATIONS : (beware that some are voluntary limitations)
- this version is using Air/Nitrox mixes only (Helium mixes not included but on it's way in some next releases)
(not true anymore in last release)
- this version of the program is limited to only one off-gasing mix (deco mix) (not true anymore in last release)
- the program is METRIC only (but is it really a limitation 🤔)
- the program is limited to 99 meters and 999 minutes
- deco is calculated at sea level in fresh water (but internal data can be changed to accommodate altitude diving in fresh water)
- descent speed is 20m/min, ascent speed is 10m/min, between stops speed is 10m/min (but internals can be changed to accommodate any speed)
- there is NO CHECK on valid/invalid gaz usage in this version. Narcosis and High/Low Oxygen levels are still managed by the computer available between your ears!

DIVE MODEL :
A dive is modeled by a succession of flat segments (legs?), an ascent to the first deco stop, and deco stops until surface is reached.
You can add as many flat segments (legs?) as you need to modelize your dive, each segment with it's own diving mix.
Once you decide to "call the dive", the program calculates the ascent to the first deco stop, first deco stop and each successive stops until surface is reached.
Deco can also be done with different deco mixes, you can change dexo mix at the end of any stop.
When at surface, you can add a surface interval, then a second dive.

WARNING :
1) As usual during the dive (with travel/bottom mixes)...
- Descent time in INCLUDED in segment time and is retrieved form time spent at depth
- Ascent time is EXCLUDED in segment time and time spent at depth is unchanged
- you change mix once arrived at the flat portion of the segment/leg
2) As usual during deco stops (with deco mixes)...
- Ascent time to the following stop is included in following deco stop time
- deco mix is changed at the bottom and ascent to first stop is done with deco mix

HINTS :
A) Bottom/Travel or Deco Mix change :
You can always force a mix change, at any point of the dive, inserting a "0 minute" segment/leg during the dive when prompted with "(?)"
Example :
Y = oo.hh new mix (oo = 02% and hh = HE%)
X = dd.000 where dd is current depth with 0 minutes
Then hit R/S to compute the dive

B) Message prompt in ALHPA
When ALPHA prompt a message including a :
- "(?)" => then the program asks you for a new segment data or to "call the dive"
- "(R/S)" => then the program asks you to hit R/S to get more travel/deco info

C) Each segment/leg is keyed in as this :
1) the mix used for the segment in Y as oo.hh, oo being the O2 percentage in the mix, hh being the He percentage in the mix (21.00 for air, 32.00 for a 32% Nitrox, 50.00 for a 50% deco gas, 18.30 for a 18/30 Trimix for example)
2) the next diving segment in X as dd.mmm , dd being the depth reached in meters and mmm being the duration in minutes of the dive segment (duration INCLUDING descent time and EXCLUDING ascent time)
3) then you hit "R/S" to add the segment to calculations

D) 2 results are show when adding a segment :
1) First result is ascent/descent management to targeted depth shown with a "DIVE ⬇️ (R/S)" or a "DIVE ⬆️ (R/S)" message in ALPHA
- total diving time in Z, often called RUN time (in minutes)
- current mix used by program in Y (as oo.hh)
- dd.mmm in X, depth as nn and mmm as real time spent in ascent/descent ONLY
Hit "R/S" to continue (as shown in ALHPA message)
2) Second result is time spent at depth shown with a "DIVE ➡️ (?)" message in ALPHA
- total diving time in Z (in minutes)
- current mix used by program in Y (as oo.hh)
- dd.mm in X, depth as dd and real time spent at depth in mmm (time spent in ascent or descent from previous depth is removed from segment time)

E) You can add as many segments as you need to simulate your dive.

F) "calling the dive" or computing the deco stops
When you "call the dive", you have to key :
- the first mix used during deco in Y as oo.he (see explanation up somewhere)
- 0 in X because you are asking to reach the surface (0 meters)
- then hit R/S to calculate first deco stop
1) You get first an ascent to the first deco stop, then as many information as there is stops in the deco (every 3 meters)
1.1) First the result is ascent to the first stop with a "ASCENT (R/S)" message in ALPHA
- total dive time still in Z (in minutes)
- Mix used during deco in Y (as oo.hh)
- dd.mmm in X, dd as depth of first deco stop and mmm as duration of the first stop INCLUDING ascent time from last segment
Hit R/S to continue and get all the deco stops informations
1.2) Following results are all the deco stops
- total dive time still in Z (in minutes)
- Mix used during deco in Y (as oo.hh)
- dd.mmm in X, dd as depth of deco stop and mmm as duration of the first stop INCLUDING ascent time from last stop
1.3) after each stop you have two choices
1.3.1) You either hit R/S to continue the deco with the same mix,
1.3.2) Or you enter a new deco mix
- the new mix used during deco in Y as oo.he (see explanation up somewhere)
- 00.000 in X because you are still asking to reach the surface
- then hit R/S to calculate next deco stop with new deco mix

G) Reaching surface, surface interval and second dive
When you reach 0m you get a "SURFACE (?)" message in ALPHA and X is showing 00.000 and Y is showing 21.00 (we suppose you are breathing Air at surface)
You can add a surface segment/leg with 00.mmm where 0 is for surface and mmm the surface interval, you get a "SURFACE ➡️ (?)" asking either for another surface interval segment or a second dive

EXAMPLE OF A DIVE :
You want to plan the following dive :
- Segment 1 : 30 minutes at 30m with air
- Segment 2 : 30 minutes at 20m with 32% Nitrox
- Then you call the dive USING a 50% Nitrox mix for deco
- At 6m stop, you SWITCH to 100% Oxygen deco mix

Launch "zh16b" program
you get a "SURFACE (?)" message in ALHPA
21.00 (air as travel/bottom mix)
ENTER
30.030 (30m, 30 minutes)
R/S
you get a "DIVE ⬇️ (R/S)" message in ALPHA with
Z = 1.5 min (RUN time)
Y = 21.00 (air used)
X = 30.002 (2 minutes descent time from surface to 30m)
HIT R/S
you get a ""DIVE ➡️ (?)" message in ALPHA with
Z = 30 min (RUN time)
Y = 21.00 (air used)
X = 30.029 (29 minutes spent at 30m depth)
You key in
32.00 (new travel/bottom mix)
ENTER
20.030 (20m, 30 minutes)
R/S
You get a "DIVE ⬆️ (R/S)" message in ALPHA
Z = 31 min (RUN time)
Y = 21.00 (air used up to next flat segment)
X = 20.001 (1 minutes ascent time from 30m to 20m)
HIT R/S
you get a "DIVE ➡️ (?)" message in ALPHA with
Z = 61 minute (RUN time)
Y = 32.00 (32% Nitrox used)
X = 20.030 (30 minutes spent at 20m)
You key in
50.00 (we switch to a 50% Nitrox mix for deco)
ENTER
0 (request deco stops computing)
R/S
you get a "ASCENT (R/S)" message in ALPHA
Z = 62.1 (RUN time)
50.00 (50% Nitrox used)
9.001 (first stop is 9m and one minute ascent between 20m and 9m)
HIT R/S
you get a "STOP (R/S)" message in ALPHA
Z = 63 (RUN time)
50.00 (50% Nitrox used)
9.001 (first stop is 9m and one minute stop at 9m, including the ascent time)
You key in
100.00 (we switch to a 100% Oxygen mix for deco)
ENTER
0 (request following deco stops computing)
R/S
you get a "STOP (R/S)" message in ALPHA
Z = 64 (RUN time)
100.00 (100% Oxygen used)
6.001 (next stop is 6m and one minute stop at 6m, including the ascent time)
HIT R/S
you get a "STOP (R/S)" message in ALPHA
Z = 69 (RUN time)
100.00 (100% Oxygen used)
3.005 (next stop is 3m and 5 minutes stop at 3m, including the ascent time)
HIT R/S
you get a "SURFACE" message in ALPHA
Z = 69 (RUN time)
100.00 (100% Oxygen used)
0.000 (you reached surface)

===================================
I will keep in this post short with only the informations to run the ZH16B program on DM42
=> all the program internal informations in a following post to allow anyone to tune their deco scheme
=> all test dives and comparison with the ANDOID commercial MULTIDECO program in a following post
===================================

I have splitted the (very long program) into 3 parts :
zhinit.raw
(1.56 KiB) Downloaded 4 times
zhtools.raw
(810 Bytes) Downloaded 2 times
zh16b.raw
(1.65 KiB) Downloaded 2 times
===============================================

Code: Select all

00 { 1686-Byte Prgm }
01▸LBL "ZH16B"
02 XEQ "ZHINIT"
03 "SURFACE (?)"
04▸LBL "LOOP"
05 XEQ "ZHSHOW"
06 STOP
07 X<>Y
08 STO "O2.HE"
09 R↓
@  PROF2 is stored in the format dd.mmm
@  dd = depth and mmm = minutes of the leg
10 STO "PROF2"
11 RCL "O2.HE"
@  did we enter a mix = 0?
12 X=0?
13 GTO 00
@  mix!=0, we extract the mix composition
@  HE2% is just the fractional part of the mix
14 FP
15 STO "%HE2"
@  now we compute the N22% part
@  N2 = (100 - O2)/100 - HE2%
@  we start at N22% = 100%
16 100
@  we retreive O2 part and compute the %
17 RCL "O2.HE"
18 IP
19 -
20 100
21 ÷
@  we retreive now HE2%
22 RCL "%HE2"
23 -
24 STO "%N22"
@  main and no mix change
25▸LBL 00
@  PROF2 is still in the format dd.mmm
@  dd = depth and mmm = minutes of the leg
26 RCL "PROF2"
@  did we request a stop calculcation
@  if yes, we go to stop calculations
27 X=0?
28 GTO "STOPS"
@  not a stop, we add a new leg
@  we extract first the depth and time of the leg
@  PROF2 = dd.mmm
@  T2 = mmm
29 FP
30 1ᴇ3
31 ×
32 STO "T2"
@  PROF2 = dd
33 RCL "PROF2"
34 IP
35 STO "PROF2"
@  now we calculate the depth gradient 
@  new depth - current depth
36 RCL "PROF"
37 -
@  are we ascending (new depth - current depth>0?)
38 X<0?
39 GTO "UP"
@  are we descending (new deth - current detph>0?)
40 X>0?
41 GTO "DOWN"
@  we are staying at same depth! no need to calculate 
@  ascent od descent part of the leg
@  nor ascent or descent values (R=TR=0)
42 0
43 STO "R"
44 STO "TR"
@  no need to calculate PP because of heavy calculations,
@  just copy B => C
45 XEQ "ZHPPB2C"
@  new mix is now current mix
46 RCL "%N22"
47 STO "%N2"
48 RCL "%HE2"
49 STO "%HE"
@  we have now to calculate the horizontal part of leg
50 GTO "HORIZ"
@  case we are ascending
@  we need to calculate tr and R with Vdwn
51▸LBL "UP"
52 "DIVE ↑ (R/S)"
@  we calculate the ascending leg with current mix
@  rule is to use the current mix when ascending
@  (certainly due to risk of high O2 if we use new 
@  mix of the leg)
@  we use V = Vup
53 RCL "VUP"
54 STO "V"
55 GTO 01
@  case we are descending
@  we need to calculate tr and R with Vdwn
56▸LBL "DOWN"
57 "DIVE ↓ (R/S)"
58 RCL "VDWN"
@  is it the first leg?
59 RCL "PROF"
60 X≠0?
61 GTO 04
@  if it is the first leg, the current mix used during
@  decent is the leg mix!
62 RCL "%N22"
63 STO "%N2"
64 RCL "%HE2"
65 STO "%HE"
@  we reset DTR because it is first leg
@  important if we track surface intervals
66 0
67 STO "DTR"
@  now we are sure to have the good mix in %N2 and %HE
68▸LBL 04
@  we calculate the descending with current mix
@  rule is to use the current mix when descending
@  we use k = Vdwn
69 RCL "VDWN"
70 STO "V"
@  all the calculation are now independent of Vup 
@  and Vdwn stored in V
71▸LBL 01
@  tr = (Proff - Profi)/V
@  proff is leg depth
@  profi is current depth
72 RCL "PROF2"
73 RCL "PROF"
74 -
75 RCL "V"
76 ÷
77 STO "TR"
@  R = mtob*N2*V
78 RCL "%N2"
79 RCL "MTOB"
80 ×
81 RCL "V"
82 ×
83 STO "R"
@  Pio2 = (Prof*mtob + Patm - Pwvp)
@  Pio = Pio2 * N2
84 RCL "PATM"
85 RCL "PWVP"
86 -
87 RCL "PROF"
88 RCL "MTOB"
89 ×
90 +
91 STO "PIO2"
92 RCL "%N2"
93 ×
94 STO "PIO"
@  we calculate then PP during ascent/descend
@  PP (Pio, tr, R, Periode, B => C)
95 RCL "TN2"
96 XEQ "ZHPPV"
@  R = mtob*He*V
97 RCL "%HE"
98 RCL "MTOB"
99 ×
100 RCL "V"
101 ×
102 STO "R"
@  Pio = Pio2 * He
103 RCL "PIO2"
104 RCL "%HE"
105 ×
106 STO "PIO"
@  we calculate then PP during ascent/descend
@  PP (Pio, tr, R, Periode, B => C)
107 RCL "THE"
108 XEQ "ZHPPV"
@  dtr = dtr + tr
109 RCL "TR"
110 STO+ "DTR"
111 XEQ "ZHSHOWV"
112 STOP
@  after calculating ascent/descent with current mix,
@  the leg is now calculated with leg mix 
113 RCL "%N22"
114 STO "%N2"
115 RCL "%HE2"
116 STO "%HE"
@  calculate the flat portion of the leg
117▸LBL "HORIZ"
118 "DIVE → (?)"
@  did we dive or is it just a surface interval?
119 RCL "PROF2"
120 X=0?
@  here we know that we are dealing with a surface
@  interval
121 "SURFACE → (?)"
@  is it a "virtual leg" with no time at depth.
@  this is used to change mixes for example
122 RCL "T2"
123 X=0?
124 GTO 02
@  were we ascending ? if we are time during ascent
@  is not retreived from time at depth
@  total leg time is kept unchanged
125 RCL "PROF2"
126 RCL "PROF"
127 -
128 X<0?
129 GTO 03
@  were are descending, so time during descent is
@  included in total leg time
130 RCL "TR"
131 STO- "T2"
@  do we find ourselves with a negative time at depth, 
@  so we need to correct with 0 and skip heavy PP
@  calculations
132 RCL "T2"
133 X>0?
134 GTO 03
135 0
136 STO "T2"
@  we skip heavy PP computing because time in flat 
@  part of the leg is =0
137 GTO 02
@  now we calculate the flat portion of the leg
138▸LBL 03
@  new depth = leg depth
139 RCL "PROF2"
140 STO "PROF"
@  Pio2 = (Prof*mtob + Patm - Pwvp)
@  Pio = Pio2 * N2
141 RCL "PROF"
142 RCL "MTOB"
143 ×
144 RCL "PATM"
145 +
146 RCL "PWVP"
147 -
148 STO "PIO2"
149 RCL "%N2"
150 ×
151 STO "PIO"
@  we calculate PP (Pio, t, Periode, C => B)
152 RCL "TN2"
153 XEQ "ZHPP"
@  Pio = Pio2 * He
154 RCL "PIO2"
155 RCL "%HE"
156 ×
157 STO "PIO"
@  we calculate PP (Pio, t, Periode, C => B)
158 RCL "THE"
159 XEQ "ZHPP"
@  dtr = dtr + t2
160 RCL "T2"
161 STO+ "DTR"
162 GTO "LOOP"
@  in case flat portion of leg is = 0
@  we just copy C => B due to heavy calculation in PP
163▸LBL 02
@  new depth = leg depth (should already be the case!)
164 RCL "PROF2"
165 STO "PROF"
166 XEQ "ZHPPC2B"
@  dtr = dtr + t2 (should be +0!)
167 RCL "T2"
168 STO+ "DTR"
169 GTO "LOOP"
@  ==========================
@  part of the program that computes the end of the dive
@  ==========================
170▸LBL "STOPS"
@  we suppose ceiling is surface
171 0
172 STO "PALIER2"
@  we start with gf = gfmin
173 RCL "GFMIN"
174 STO "GF"
@  calculate the ceiling in Palier2 going from bottom
@  ceiling is calculated for both N2 and He
175 XEQ "ZHCEIL"
176 RCL "PALIER2"
@  new target depth is now the calculated ceiling
177 STO "PROF2"
@  tr = (proff - profi) / Vup
@  proff is first stop
@  profi is bottom depth
178 RCL "PROF2"
179 RCL "PROF"
180 -
181 RCL "VUP"
182 ÷
183 STO "TR"
@  R = Vup*mtob*N2
@  we are still ascending with Vup speed
@  mix used is new deco mix rather than current bottom @ mix so we use %N22 and %HE2
184 RCL "VUP"
185 RCL "%N22"
186 ×
187 RCL "MTOB"
188 ×
189 STO "R"
@  Pio = (prof*mtob + Patm - Pwvp)
@  Pio = Pio2 * N2
@  Prof is bottom
190 RCL "PATM"
191 RCL "PWVP"
192 -
193 RCL "PROF"
194 RCL "MTOB"
195 ×
196 +
197 STO "PIO2"
198 RCL "%N22"
199 ×
200 STO "PIO"
@  we calculate then PP during ascent/descend
@  PP (Pio, tr, R, Periode, B => C)
201 RCL "TN2"
202 XEQ "ZHPPV"
@  R = Vup*mtob*He
@  we are still ascending with Vup speed
203 RCL "VUP"
204 RCL "%HE2"
205 ×
206 RCL "MTOB"
207 ×
208 STO "R"
@  Pio = Pio2*HE
@  Prof is bottom
209 RCL "PIO2"
210 RCL "%HE2"
211 ×
212 STO "PIO"
@  we calculate then PP during ascent/descend
@  PP (Pio, tr, R, Periode, B => C)
213 RCL "THE"
214 XEQ "ZHPPV"
@  dtr = dtr + tr
215 RCL "TR"
216 STO+ "DTR"
@  we need to switch now current mix with new mix 
@  or the display will be wrong showing bottom mix
@  now that we have ascended, we switch to new deco mix
@  for flat leg
217 RCL "%N22"
218 STO "%N2"
219 RCL "%HE2"
220 STO "%HE"
221 "ASCENT (R/S)"
222 XEQ "ZHSHOWV"
223 STOP
@  new depth is first stop depth for flat leg
224 RCL "PROF2"
225 STO "PROF"
@  did we reach surface?
226 X=0?
@  if we reached surface during first ascent
227 GTO 31
@  we didn't reach surface we need to calculate stop time
@  first stop time is was is left from ascent rounded to
@  nearest minute
228 RCL "TR"
229 RCL "TR"
230 IP
231 -
232 STO "TR"
@  we compute now gfsteps using 
@  steps = int(palier/3)
@  gfsteps = (gfmax- gfmin)/steps or 0
233 RCL "PROF"
234 3
235 ÷
236 IP
@  if steps = 0 we do not divide by steps
@  we should NOT have palier = 0!
237 X=0?
238 GTO 22
239 RCL "GFMAX"
240 RCL "GFMIN"
241 -
242 X<>Y
243 ÷
244▸LBL 22
245 STO "GFSTEP"
@  loop on stops until stop <= 0 (surface is reached)
246▸LBL 30
247 RCL "PROF"
@  did we reach surface, then we exit
248 X≤0?
249 GTO 31
@  we didn't reach surface, we compute time spent at stop
@  Pio2 = (palier*mtob + Patm - Pwvp)
250 RCL "PATM"
251 RCL "PWVP"
252 -
253 RCL "PROF"
254 RCL "MTOB"
255 ×
256 +
257 STO "PIO2"
@  t2 -= tr 
@  we remove from first minute of deco time spent 
@  ascending to the stop
258 RCL "TR"
259 +/-
260 STO "T2"
@  Palier2 = palier for the +1minute loop 
261 RCL "PROF"
262 STO "PALIER2"
@  gf += gfstep
263 RCL "GFSTEP"
264 STO+ "GF"
@  loop did we change deco stop adding +1minute
@  in computing
265▸LBL 40
266 RCL "PROF"
267 RCL "PALIER2"
@  did we change stop depth?
@  we get out of the "LBL 40" loop
268 X≠Y?
269 GTO 41
@  we add +1minute to stop time
270 1
271 STO+ "T2"
@  Pio = Pio2 * N2
272 RCL "PIO2"
273 RCL "%N2"
274 ×
275 STO "PIO"
@  we compute PP with one more minute at stop
@  we compute PP (Pio, t, Periode, C => B)
276 RCL "TN2"
277 XEQ "ZHPP"
@  Pio = Pio2 * He
278 RCL "PIO2"
279 RCL "%HE"
280 ×
281 STO "PIO"
@  we compute PP with one more minute at stop
@  we compute PP (Pio, t, Periode, C => B)
282 RCL "THE"
283 XEQ "ZHPP"
284 0
285 STO "PALIER2"
286 XEQ "ZHCEIL"
287 RCL "PALIER2"
288 RCL "PROF"
289 3
290 -
@  did the new ceiling > current depth +3m ?
@  in that case new ceiling is current - 3m
291 X<Y?
292 X<>Y
293 STO "PALIER2"
@  we loop for one more minute?
294 GTO 40
@  we reached enought time to go to next stop
295▸LBL 41
@  DTR = DTR + t2
296 RCL "T2"
297 STO+ "DTR"
298 RCL "TR"
299 STO+ "T2"
300 "STOP (R/S)"
301 XEQ "ZHSHOWP"
302 STOP
@  are we requesting a new deco mix beetween stops?
@ new deco mix requested with X=0
303 X≠0?
304 GTO 42
@  new mix requested
305 R↓
306 STO "O2.HE"
@  the HE% part is just the frational part
307 FP
308 STO "%HE2"
@  now we compute the N22% part
@  N2 = (100 - O2)/100 - HE2%
@  we start at N22% = 100%
309 100
@  we retreive O2 part and compute the %
310 RCL "O2.HE"
311 IP
312 -
313 100
314 ÷
@  we retreive now HE2%
315 RCL "%HE2"
316 -
317 STO "%N22"
@  we continue to next stop
318▸LBL 42
@  tr = (palier2 - current) / Vpalier
319 RCL "PALIER2"
320 RCL "PROF"
321 -
322 RCL "VPALIER"
323 ÷
324 STO "TR"
@  mix is still the last on ascent one before swithing
@  R = Vpalier*mtob*N2
325 RCL "VPALIER"
326 RCL "MTOB"
327 ×
328 RCL "%N2"
329 ×
330 STO "R"
@  Pio is still ok from last calculation
@  depth for Pio is last stop
331 RCL "PIO2"
332 RCL "%N2"
333 ×
334 STO "PIO"
@  we calculate then PP during ascent/descend
@  PP (Pio, tr, R, Periode, B => C)
335 RCL "TN2"
336 XEQ "ZHPPV"
@  R = Vpalier*mtob*He
337 RCL "VPALIER"
338 RCL "MTOB"
339 ×
340 RCL "%HE"
341 ×
342 STO "R"
@  Pio is still ok from last calculation
343 RCL "PIO2"
344 RCL "%HE"
345 ×
346 STO "PIO"
@  we calculate then PP during ascent/descend
@  PP (Pio, tr, R, Periode, B => C)
347 RCL "THE"
348 XEQ "ZHPPV"
@  now new mix will be used
349 RCL "%N22"
350 STO "%N2"
351 RCL "%HE2"
352 STO "%HE"
@  new depth is current stop
353 RCL "PALIER2"
354 STO "PROF"
@  did we surface => end
355 X=0?
356 GTO 31
@  we didn't surface we add ascent to stop in run time
357 RCL "TR"
358 STO+ "DTR"
@  loop
359 GTO 30
@  end of the dive, we reched surface
360▸LBL 31
@  we reached surface, depth = 0, time leg = 0
361 "SURFACE ↑ (R/S)"
362 0
363 STO "PROF2"
364 STO "PROF"
365 STO "T2"
366 XEQ "ZHSHOW"
367 STOP
@  before looping to surface
@  we put the DTR = 0
@  and reset mix to surface air mix
368 0
369 STO "DTR"
370 STO "TR"
371 STO "%HE2"
372 STO "%HE"
373 RCL "N2SURF"
374 STO "%NE"
375 STO "%NE2"
376 "SURFACE (?)"
377 GTO "LOOP"
378 END
===============================================

Code: Select all

00 { 807-Byte Prgm }
01▸LBL "ZHTOOLS"
02▸LBL "ZHPP"
03 STO "I"
04▸LBL 50
05 RCL "I"
06 RCL 00
07 4
08 ×
09 +
10 STO "J"
11 2
12 LN
13 RCL IND "I"
14 ÷
15 RCL "T2"
16 ×
17 +/-
18 E^X
19 1
20 -
21 RCL IND "J"
22 RCL "PIO"
23 -
24 ×
25 RCL IND "J"
26 +
27 RCL "I"
28 RCL 00
29 3
30 ×
31 +
32 X<>Y
33 STO IND ST Y
34 ISG "I"
35 GTO 50
36 RTN
37▸LBL "ZHPPV"
38 STO "I"
39▸LBL 60
40 RCL "I"
41 RCL 00
42 3
43 ×
44 +
45 STO "J"
46 2
47 LN
48 RCL IND "I"
49 ÷
50 STO "K"
51 RCL "PIO"
52 RCL IND "J"
53 -
54 RCL "R"
55 RCL "K"
56 ÷
57 -
58 RCL "K"
59 RCL "TR"
60 ×
61 +/-
62 E^X
63 ×
64 +/-
65 RCL "PIO"
66 +
67 RCL "TR"
68 RCL "K"
69 1/X
70 -
71 RCL "R"
72 ×
73 +
74 RCL "I"
75 RCL 00
76 4
77 ×
78 +
79 X<>Y
80 STO IND ST Y
81 ISG "I"
82 GTO 60
83 RTN
84▸LBL "ZHPPB2C"
85 RCL "BN2"
86 XEQ 70
87 RCL "BHE"
88 XEQ 70
89 RTN
90▸LBL 70
91 STO "I"
92▸LBL 71
93 RCL "I"
94 RCL 00
95 +
96 STO "J"
97 RCL IND "I"
98 STO IND "J"
99 ISG "I"
100 GTO 71
101 RTN
102▸LBL "ZHPPC2B"
103 RCL "BN2"
104 XEQ 80
105 RCL "BHE"
106 XEQ 80
107 RTN
108▸LBL 80
109 STO "I"
110▸LBL 81
111 RCL "I"
112 RCL 00
113 +
114 STO "J"
115 RCL IND "J"
116 STO IND "I"
117 ISG "I"
118 GTO 81
119 RTN
@   ===========================================
@   we compute ceiling first for N2 then for He
@   ===========================================
120▸LBL "ZHCEIL"
@   we compute the ceiling using Buhlmann equation
@   extended with gradient factors by Erik Baker
121 XEQ 10
@   we have the ceiling in PALIER2
@   we first check if we are near surface
122 RCL "EPSILON"
123 RCL "PALIER2"
124 X<Y?
@   celiling is 0 (surface)
125 GTO 12
@   else we fing the nearest stop (multiple of 3m)
126 3
127 ÷
128 RCL "EPSILON"
129 +
130 IP
131 1
132 +
133 3
134 ×
135 GTO 13
136▸LBL 12
137 0
138▸LBL 13
139 STO "PALIER2"
140 RTN
141▸LBL 10
142 RCL "N2A"
143 LSTO "I"
144 RCL "HEA"
145 LSTO "J"
146▸LBL 11
@   we retreive PBN2b (BN2)
147 RCL "I"
148 RCL 00
149 2
150 ×
151 +
@   PPN2
152 RCL IND ST X
153 LSTO "PN2"
@   P = PPN2 (+ PPHE)
154 LSTO "P"
@   we retreive N2A
155 RCL IND "I"
156 RCL "PN2"
157 ×
@   A = PPN2 x N2A
158 LSTO "A"
@   we retreive PBHEb (BHE)
159 RCL "J"
160 RCL 00
161 2
162 ×
163 +
@   PPHE
164 RCL IND ST X
165 LSTO "PHE"
@   P = PPN2 + PPHE
166 STO+ "P"
@   we retreive HEA
167 RCL IND "J"
168 RCL "PHE"
169 ×
@   A = PPN2 * N2A + PPHE * HEA
170 STO+ "A"
171 RCL "P"
@   A = A/P
172 STO÷ "A"
@   we retreive N2B
173 RCL "I"
174 RCL 00
175 +
@   N2B
176 RCL IND ST X
@   B = N2B * PN2
177 RCL "PN2"
178 ×
179 LSTO "B"
@   we retreive HEB
180 RCL "J"
181 RCL 00
182 +
@   HEB
183 RCL IND ST X
@   B = N2B * PN2 + HEB * PHE
184 RCL "PHE"
185 ×
186 STO+ "B"
187 RCL "P"
@   B = B/P
188 STO÷ "B"
@   we retreive N2A
189 RCL "P"
190 RCL "A"
191 RCL "GF"
192 ×
193 -
194 RCL "GF"
195 RCL "B"
196 ÷
197 1
198 +
199 RCL "GF"
200 -
201 ÷
202 RCL "PATM"
203 -
204 RCL "MTOB"
205 ÷
@   did we find a greater ceiling?
@   if yes, we must store it
206 RCL "PALIER2"
207 X<Y?
208 X<>Y
209 STO "PALIER2"
210 1
211 STO+ "J"
212 ISG "I"
213 GTO 11
214 RTN
215▸LBL "ZHSHOWV"
216 RCL "TR"
217 1ᴇ3
218 ÷
219 RCL "PROF2"
220 +
221 STO "I"
222 RCL "TR"
223 IP
224 STO "J"
225 RCL "TR"
226 FP
227 60
228 ×
229 100
230 ÷
231 STO+ "J"
232 GTO 97
233▸LBL "ZHSHOW"
234 RCL "T2"
235 1ᴇ3
236 ÷
237 RCL "PROF"
238 +
239 STO "I"
240 RCL "T2"
241 IP
242 STO "J"
243 RCL "T2"
244 FP
245 60
246 ×
247 100
248 ÷
249 STO+ "J"
250 GTO 97
251▸LBL "ZHSHOWP"
@   I = dd.mmm = stop.time
252 RCL "T2"
253 1ᴇ3
254 ÷
255 RCL "PROF"
256 +
257 STO "I"
@   J = time reel sans la remontee pour palier
258 RCL "T2"
259 RCL "TR"
260 -
261 IP
262 STO "J"
263 RCL "T2"
264 RCL "TR"
265 -
266 FP
267 60
268 ×
269 100
270 ÷
271 STO+ "J"
272▸LBL 97
@   we start with 100% O2
273 100
@   we retreive now the N2 part
274 RCL "%N2"
275 100
276 ×
277 IP
278 -
@   we retreive now the HE part
279 RCL "%HE"
280 100
281 ×
282 IP
283 -
@   we add the fractional part of HE%
284 RCL "%HE"
285 +
286 STO "O2.HE"
287 RCL "J"
288 RCL "DTR"
289 RCL "O2.HE"
290 RCL "I"
291 RTN
292 END
===============================================

Code: Select all

00 { 1596-Byte Prgm }
01▸LBL "ZHINIT"
@  size is 5 x N2 + 5 x He = 160 elements
@  N2 is : TN2, N2A, N2B, BN2, CN2
@  He is : HE2, HEA, HEB, BHE, CHE
02 SIZE 161
03 FIX 03
04 0
05 STO "PROF"
06 STO "DTR"
07 STO "TR"
08 STO "%HE"
09 STO "PROF2"
10 STO "T2"
11 STO "%HE2"
12 0.7902
13 STO "%N2"
14 STO "%N22"
15 STO "N2SURF"
16 20
17 STO "VDWN"
18 10
19 +/-
20 STO "VUP"
21 STO "VPALIER"
22 0
23 STO "V"
24 0.3
25 STO "GFMIN"
26 0.85
27 STO "GFMAX"
28 1ᴇ-6
29 STO "EPSILON"
30 0.0627
31 STO "PWVP"
32 1.01325
33 STO "PATM"
34 0.09985
35 STO "MTOB"
36 16
37 STO "I"
38 STO 00
39 1.01601
40 STO "TN2"
41 STO "I"
42 5
43 STO IND "I"
44 ISG "I"
45 8
46 STO IND "I"
47 ISG "I"
48 12.5
49 STO IND "I"
50 ISG "I"
51 18.5
52 STO IND "I"
53 ISG "I"
54 27
55 STO IND "I"
56 ISG "I"
57 38.3
58 STO IND "I"
59 ISG "I"
60 54.3
61 STO IND "I"
62 ISG "I"
63 77
64 STO IND "I"
65 ISG "I"
66 109
67 STO IND "I"
68 ISG "I"
69 146
70 STO IND "I"
71 ISG "I"
72 187
73 STO IND "I"
74 ISG "I"
75 239
76 STO IND "I"
77 ISG "I"
78 305
79 STO IND "I"
80 ISG "I"
81 390
82 STO IND "I"
83 ISG "I"
84 498
85 STO IND "I"
86 ISG "I"
87 635
88 STO IND "I"
89 17.03201
90 STO "N2A"
91 STO "I"
92 1.1696
93 STO IND "I"
94 ISG "I"
95 1
96 STO IND "I"
97 ISG "I"
98 0.8618
99 STO IND "I"
100 ISG "I"
101 0.7562
102 STO IND "I"
103 ISG "I"
104 0.6667
105 STO IND "I"
106 ISG "I"
107 0.56
108 STO IND "I"
109 ISG "I"
110 0.4947
111 STO IND "I"
112 ISG "I"
113 0.45
114 STO IND "I"
115 ISG "I"
116 0.4187
117 STO IND "I"
118 ISG "I"
119 0.3798
120 STO IND "I"
121 ISG "I"
122 0.3497
123 STO IND "I"
124 ISG "I"
125 0.3223
126 STO IND "I"
127 ISG "I"
128 0.285
129 STO IND "I"
130 ISG "I"
131 0.2737
132 STO IND "I"
133 ISG "I"
134 0.2523
135 STO IND "I"
136 ISG "I"
137 0.2327
138 STO IND "I"
139 33.04801
140 STO "N2B"
141 STO "I"
142 0.5578
143 STO IND "I"
144 ISG "I"
145 0.6514
146 STO IND "I"
147 ISG "I"
148 0.7222
149 STO IND "I"
150 ISG "I"
151 0.7825
152 STO IND "I"
153 ISG "I"
154 0.8126
155 STO IND "I"
156 ISG "I"
157 0.8434
158 STO IND "I"
159 ISG "I"
160 0.8693
161 STO IND "I"
162 ISG "I"
163 0.891
164 STO IND "I"
165 ISG "I"
166 0.9092
167 STO IND "I"
168 ISG "I"
169 0.9222
170 STO IND "I"
171 ISG "I"
172 0.9319
173 STO IND "I"
174 ISG "I"
175 0.9403
176 STO IND "I"
177 ISG "I"
178 0.9477
179 STO IND "I"
180 ISG "I"
181 0.9544
182 STO IND "I"
183 ISG "I"
184 0.9602
185 STO IND "I"
186 ISG "I"
187 0.9653
188 STO IND "I"
189 49.06401
190 STO "BN2"
191 STO "I"
192 RCL "PATM"
193 RCL "PWVP"
194 -
195 RCL "N2SURF"
196 ×
197▸LBL 99
198 STO IND "I"
199 ISG "I"
200 GTO 99
201 65.08001
202 STO "CN2"
203 STO "I"
204 0
205▸LBL 98
206 STO IND "I"
207 ISG "I"
208 GTO 98
209 81.09601
210 STO "THE"
211 STO "I"
212 1.88
213 STO IND "I"
214 ISG "I"
215 3.02
216 STO IND "I"
217 ISG "I"
218 4.72
219 STO IND "I"
220 ISG "I"
221 6.99
222 STO IND "I"
223 ISG "I"
224 10.21
225 STO IND "I"
226 ISG "I"
227 14.48
228 STO IND "I"
229 ISG "I"
230 20.53
231 STO IND "I"
232 ISG "I"
233 29.11
234 STO IND "I"
235 ISG "I"
236 41.20
237 STO IND "I"
238 ISG "I"
239 55.19
240 STO IND "I"
241 ISG "I"
242 70.69
243 STO IND "I"
244 ISG "I"
245 90.34
246 STO IND "I"
247 ISG "I"
248 115.29
249 STO IND "I"
250 ISG "I"
251 147.42
252 STO IND "I"
253 ISG "I"
254 188.24
255 STO IND "I"
256 ISG "I"
257 240.03
258 STO IND "I"
259 97.11201
260 STO "HEA"
261 STO "I"
262 1.6189
263 STO IND "I"
264 ISG "I"
265 1.3830
266 STO IND "I"
267 ISG "I"
268 1.1919
269 STO IND "I"
270 ISG "I"
271 1.0458
272 STO IND "I"
273 ISG "I"
274 0.9220
275 STO IND "I"
276 ISG "I"
277 0.8205
278 STO IND "I"
279 ISG "I"
280 0.7305
281 STO IND "I"
282 ISG "I"
283 0.6502
284 STO IND "I"
285 ISG "I"
286 0.5950
287 STO IND "I"
288 ISG "I"
289 0.5545
290 STO IND "I"
291 ISG "I"
292 0.5333
293 STO IND "I"
294 ISG "I"
295 0.5189
296 STO IND "I"
297 ISG "I"
298 0.5181
299 STO IND "I"
300 ISG "I"
301 0.5176
302 STO IND "I"
303 ISG "I"
304 0.5172
305 STO IND "I"
306 ISG "I"
307 0.5119
308 STO IND "I"
309 113.12801
310 STO "HEB"
311 STO "I"
312 0.4770
313 STO IND "I"
314 ISG "I"
315 0.5747
316 STO IND "I"
317 ISG "I"
318 0.6527
319 STO IND "I"
320 ISG "I"
321 0.7223
322 STO IND "I"
323 ISG "I"
324 0.7582
325 STO IND "I"
326 ISG "I"
327 0.7957
328 STO IND "I"
329 ISG "I"
330 0.8279
331 STO IND "I"
332 ISG "I"
333 0.8553
334 STO IND "I"
335 ISG "I"
336 0.8757
337 STO IND "I"
338 ISG "I"
339 0.8903
340 STO IND "I"
341 ISG "I"
342 0.8997
343 STO IND "I"
344 ISG "I"
345 0.9073
346 STO IND "I"
347 ISG "I"
348 0.9122
349 STO IND "I"
350 ISG "I"
351 0.9171
352 STO IND "I"
353 ISG "I"
354 0.9217
355 STO IND "I"
356 ISG "I"
357 0.9267
358 STO IND "I"
359 129.14401
360 STO "BHE"
361 STO "I"
362 0
363▸LBL 97
364 STO IND "I"
365 ISG "I"
366 GTO 97
367 145.16001
368 STO "CHE"
369 STO "I"
370 0
371▸LBL 96
372 STO IND "I"
373 ISG "I"
374 GTO 96
375 RTN
376 END
=================================================
Last edited by Boub65 on Mon Aug 02, 2021 8:57 pm, edited 10 times in total.
Sincèrement, Sincerely, 73,
Boubker

2xDM15L, DM41L, DM42 SN#00855 (+one lost during shipping), DM41X #00707
TI-89 titanium, CASIO fx-cg50 (to play with micropython)

There are three kinds of people in the world: those who know math and those who don't.
Boub65
Posts: 148
Joined: Tue Sep 12, 2017 4:34 pm
Location: Rabat, Morocco

Re: Bulhmann decompression calculator (ZH16B)

Post by Boub65 »

This project started as a DM41X project.

Unfortunately, DM41X cannot handle such a big program with a minimum of 160 Buhlmann data (16x period, a and b values for N2 and same for He).

I should have used Hepax modules to make it possible on DM41X. I refused to go on that path, because the Hepax learning curve is "though" AND it suppresses DM42 compatibility!

So I switched to DM42 just changing registers by variables in first release.
That's why there is no use (yet) of
- Matrices
- Menus

I will improve the progam in the future using 100% of DM42 features, now that DM41X platform is excluded.

Sincerely,
Boubker.
Last edited by Boub65 on Wed Jul 21, 2021 5:49 pm, edited 1 time in total.
Sincèrement, Sincerely, 73,
Boubker

2xDM15L, DM41L, DM42 SN#00855 (+one lost during shipping), DM41X #00707
TI-89 titanium, CASIO fx-cg50 (to play with micropython)

There are three kinds of people in the world: those who know math and those who don't.
Boub65
Posts: 148
Joined: Tue Sep 12, 2017 4:34 pm
Location: Rabat, Morocco

Re: Bulhmann decompression calculator (ZH16B)

Post by Boub65 »

You have read the disclaimer :
=========================================
DISCLAIMER :
this DM42 deco program is given for educational
purpose only (RPN deco calculations)
IT SHOULD NOT BE USED TO PLAN YOUR DIVES...
... although it gives same results (around 99%) as MULTIDECO commercial planner!
=========================================
But...
... nevertheless, here is some dives that were tested against the ANDROID MULTIDECO commercial program with exact same results :
Dive#1 : 30m, 3min, Air
Dive#2 : 40m, 20min, Air
Dive#3 : 35m, 40min, Air
Dive#4 : 40m, 35min, Air
Dive#5 : 20m, 35min, Air
Dive#6 : 20m, 10min, Air
Dive#7 : 20m, 6min, Air
Dive#8 : 20m, 7min, Air
Dive#9 : 26m 25min, Air
Dive#10 : 30m, 30min, Air
Dive#11 : 32m, 15min, 32% Nitrox
Dive#12 : 32m, 50min, 32% Nitrox
Dive#13 : 32m, 25min, 32% Nitrox
Dive#14 : 32m, 49min, 32% Nitrox
Dive#15 : 30m, 10min, Air + 20m, 20min Air
Dive#16 : 36m, 20min, Air + 20m, 20min Air
Dive#17 : 20m, 7min, Air + 36m, 20min, Air
Dive#18 : 60m, 20min, 18/30 Trimix, 50% Nitrox, 100% Oxygen

Some dives give differents results when tested against MULTIDECO, but it's always a +1 or -1 minute difference in a stop and a -1 or +1 difference in next stop.
This is certainly only due to precision difference in deco calculation between different programs.
I could not reproduce a 100% MULTIDECO precision scheme in my program although I did try hard!

Sincerely,
Boubker.
Last edited by Boub65 on Mon Jul 26, 2021 12:33 am, edited 2 times in total.
Sincèrement, Sincerely, 73,
Boubker

2xDM15L, DM41L, DM42 SN#00855 (+one lost during shipping), DM41X #00707
TI-89 titanium, CASIO fx-cg50 (to play with micropython)

There are three kinds of people in the world: those who know math and those who don't.
Boub65
Posts: 148
Joined: Tue Sep 12, 2017 4:34 pm
Location: Rabat, Morocco

Re: Bulhmann decompression calculator (ZH16B)

Post by Boub65 »

Today, I added the ability :
- to use Trimix
- and to switch deco mixes

Example of a Trimix dive :

You want to plan the following dive :
20 minutes at 60m with 18/30 Trimix
You call the dive USING 18/30 Trimix as deco mix
At 21m stop you SWITCH to a 50% Nitrox deco mix
At 6m stop you SWITCH to a 100 Oxygen deco mix

Launch ZH16B, you get a "SURFACE (?)" message in ALHPA
18.30 (18/30 Trimix)
ENTER
60.020
R/S
you get a "DIVE ⬇️ (R/S)" message in ALPHA with
Z = 3 min (RUN time)
Y = 18.30 (18/30 Trimix used)
X = 60.003 (3 minutes descent time from surface to 60m)
HIT R/S
you get a ""DIVE ➡️ (?)" message in ALPHA with
Z = 20 min (RUN time)
Y = 18.30 (18/30 Trimix used)
X = 60.017 (17 minutes spent at 60m depth)
You key in
18.30
ENTER
0
R/S
you get a "ASCENT (R/S)" message in ALPHA
Z = 23 (RUN time)
Y = 18.30 (18/30 Trimix used)
30.003 (first stop is 30m and 3 minute ascent between 60m and 30m)
HIT R/S
you get a "STOP (R/S)" message in ALPHA
Z = 24 (RUN time)
Y = 18.30 (18/30 Trimix used)
30.001 (first stop is 30m and one minute stop at 30m, including the ascent time)
HIT R/S
you get a "STOP (R/S)" message in ALPHA
Z = 25 (RUN time)
Y = 18.30 (18/30 Trimix used)
27.001 (next stop is 27m and one minute stop at 27m, including the ascent time)
HIT R/S
you get a "STOP (R/S)" message in ALPHA
Z = 26 (RUN time)
Y = 18.30 (18/30 Trimix used)
24.001 (next stop is 24m and one minute stop at 24m, including the ascent time)
You then switch deco mix to a 50% Nitrox deco mix
50.00 (50% Nitrox deco mix)
ENTER
0
R/S
you get a "STOP (R/S)" message in ALPHA
Z = 27 (RUN time)
Y = 50.00 (50% Nitrox used)
21.001 (next stop is 21m and one minute stop at 21m, including the ascent time)
HIT R/S
you get a "STOP (R/S)" message in ALPHA
Z = 28 (RUN time)
Y = 50.00 (50% Nitrox used)
18.001 (next stop is 18m and one minute stop at 18m, including the ascent time)
HIT R/S
you get a "STOP (R/S)" message in ALPHA
Z = 30 (RUN time)
Y = 50.00 (50% Nitrox used)
15.002 (next stop is 15m and 2 minute stop at 15m, including the ascent time)
HIT R/S
you get a "STOP (R/S)" message in ALPHA
Z = 33 (RUN time)
Y = 50.00 (50% Nitrox used)
12.003 (next stop is 12m and 3 minute stop at 12m, including the ascent time)
HIT R/S
you get a "STOP (R/S)" message in ALPHA
Z = 37 (RUN time)
Y = 50.00 (50% Nitrox used)
9.004 (next stop is 9m and 4 minute stop at 9m, including the ascent time)
HIT R/S
You then switch deco mix to a 100% Oxygen deco mix
100.00 (100% Oxygen deco mix)
ENTER
0
R/S
you get a "STOP (R/S)" message in ALPHA
Z = 42 (RUN time)
Y = 100.00 (100% Oxygen used)
6.005 (next stop is 6m and 5 minute stop at 6m, including the ascent time)
HIT R/S
you get a "STOP (R/S)" message in ALPHA
Z = 51 (RUN time)
Y = 100.00 (100% Oxygen used)
3.009 (next stop is 3m and 9 minute stop at 3m, including the ascent time)
HIT R/S
Z = 51 (RUN time)
Y = 100.00 (100% Oxygen used)
0.000 (you reached surface)

Here is the same dive on the MULTIDECO Android commercial application (with the exact same results) :
20210725_204123.jpg
20210725_204123.jpg (169.86 KiB) Viewed 153 times
Sincèrement, Sincerely, 73,
Boubker

2xDM15L, DM41L, DM42 SN#00855 (+one lost during shipping), DM41X #00707
TI-89 titanium, CASIO fx-cg50 (to play with micropython)

There are three kinds of people in the world: those who know math and those who don't.
Boub65
Posts: 148
Joined: Tue Sep 12, 2017 4:34 pm
Location: Rabat, Morocco

Re: Bulhmann decompression calculator (ZH16B)

Post by Boub65 »

Hello All...

I am in the process of trying to convert the zh16b Bulhmann deco program for :
- DM41X with usage of HEPAX RAM because program is way too long with its 190 registers for standard memory!
- DM15L limited to Air/Nitrox usage due to limited memory (I could only fit Nitrogen data in the memory)
Sincèrement, Sincerely, 73,
Boubker

2xDM15L, DM41L, DM42 SN#00855 (+one lost during shipping), DM41X #00707
TI-89 titanium, CASIO fx-cg50 (to play with micropython)

There are three kinds of people in the world: those who know math and those who don't.
Post Reply