Banner Ad

Home-build diving computer

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • shapeshifter
    Established TDF Member
    • Jan 2013
    • 636

    Home-build diving computer

    Originally posted by notdeadyet
    The way I did it when I was writing deco software was to calculate the stop time in 1 minute steps.

    Say you want to work out the length of the 9m stop. Calculate what happens to the model after 1 minute at 9m. Can I ascend to the next stop? No? Then wait another minute. Can I ascend? If no then wait another min, etc. If yes then the total number of iterations is your stop time. That way no tissue ever sneaks up on you.
    So, here's two versions of the stop time calculation. The closed form is definitely faster, but has all those ugly problem cases that never seem to show up in real life. If I could demonstrate mathematically that they can't happen I'd be a lot happier.

    Closed-form solution to stop time
    /* time at Pamb before it becomes safe to ascend to Ptarget (anything from zero to INFINITY) */
    static float stop_old(diver_t& diver, const gas_t gas, const float Pamb, const float Ptarget, const float gf) {
    const float Palv = gas.PalvN2(Pamb); // alveolar gas pressure (bar) during interval
    float t = 0.0f;

    for (uint8_t i = 0; i < TISSUE_COUNT; ++i) {
    float Pigtol = diver.Pigtol(Ptarget, i, gf);

    if (diver.Pt[i] <= Pigtol /* tissue is already safe.. */) {
    if (Palv >= Pigtol /* PROBLEM CASE */)
    {
    // ..but is on-gassing and will eventually reach saturation
    }

    continue; // tissue is already safe to ascent to Ptarget, so assume that it'll carry on being safe for ever
    }

    if (Palv >= diver.Pt[i] /* tissue is on-gassing.. */) {
    if (Palv >= Pigtol /* PROBLEM CASE */)
    {
    // ..and will eventually, but not immediately, reach saturation
    }

    return INFINITY; // tissue is on-gassing, so assume that if it's not already safe it'll never become so.
    }

    if (Palv >= Pigtol /* tissue can never off-gas enough */) {
    return INFINITY;
    }

    // solve haldane to find out how long it will take for the tissue to become safe
    const float Tt = (-1.0f / constants.k_N2[i]) * LOG((Palv - Pigtol) / (Palv - diver.Pt[i]));

    t = MAX(t, Tt);
    }

    t = CEIL(t);
    diver.loadInert(gas, Pamb, Pamb, t);

    return t;
    }


    Iterative solution to stop time
    /* wait at Pamb until it becomes safe to ascend to Ptarget, return the time waited */
    static float stop(diver_t& diver, const gas_t gas, const float Pamb, const float Ptarget, const float gf) {
    const float Palv = gas.PalvN2(Pamb);

    // check if not already off-gassed enough to ascend to Ptarget(gf) and make sure that
    // off-gassing enough is even a possibility. save Pigtol(Ptarget, gf) for future
    // reference.

    float Pigtol[16];
    bool safe = true;
    uint16_t Tstop = 0;

    for (uint8_t i = 0; i < TISSUE_COUNT; ++i) {
    Pigtol[i] = diver.Pigtol(Ptarget, i, gf);
    safe = safe && diver.Pt[i] <= Pigtol[i];

    if (Palv > Pigtol[i] /* off-gassing to Pigtol isn't going to be happening */) {
    return INFINITY;
    }
    }

    // run simulation in 1min steps until diver is safe at Ptarget

    while (!safe) {
    safe = true;

    for (uint8_t i = 0; i < TISSUE_COUNT; ++i) {
    diver.Pt[i] = Palv - (Palv - diver.Pt[i]) * EXP(-constants.k_N2[i]); // haldane

    safe = safe && diver.Pt[i] <= Pigtol[i];
    }

    ++Tstop;
    }

    // all tissues are now safe at Ptarget(gf) so assume that they're safe
    // at all points during the ascent. no idea if this is a good assumption or not.

    return float(Tstop);
    }
    Last edited by shapeshifter; 14-02-2016, 07:57 AM.
  • shapeshifter
    Established TDF Member
    • Jan 2013
    • 636

    #2
    Originally posted by Ken
    It depends on what the diver 'state' is. Are they midway through an ascent, in which case TTS will be what it will be and will converge, or are they still in the bottom phase thinking 'I will go up at x TTS'?



    This is where my question comes in. Do you allow for the offgasing in the time it takes to ascent or just look at the ceiling NOW?
    In practice it looks like the first is what is done and in anycase doing the second just makes stuff a little less conservative, maybe.
    I don't think its really possible or even necessarily desirable to reliably distinguish between "bottom time" and "ascent" phases. The computer can continuously work out and propose an ascent solution, but it's always going to be predicive (aka a guess). What I do is just that, in fact. The computer works out a an ascent solution by iterating through steps to the surface (so yes, it takes into account on-gassing during the predicted ascent phases) and displays the resulting TTS and deco stops, but the really important bit is "what is the instantaneous ceiling and is the diver below it".

    Since the predicted ascent is recalculated continuously it must eventually converge to a real decompression schedule at the first hard stop depth.

    The NDL calculation whilst at depth is also a bit vague since I just solve Haldane for the remaining time before the ceiling drops below the surface and don't take into account the off-gassing which will occur during the ascent. At fourty metres this seems to make the NDL a bit pessimistic by about two minutes.


    Originally posted by Ken
    While playing with my own software a number of things have made it through my skull which had previously eluded me. In particular what a difference the stop sizes make to the ascent. I have been very keen on planning with the same model the computer uses but of course the computer hasn't go a stop size, it calculates for what you do. This may make more of a difference that particular GF numbers, Suunto vs Bulhmann or whatever.

    What processor are you using?
    Actually implementing the standard algorithms certainly does give a bit of insight into why main-stream dive computers behave the way they do, doesn't it? Pessimistic NDL? Deco stops that disappear on the way to the surface? Deco minutes that last longer than 60 seconds ? Been there ; done that : (

    I'm using an ATMega 32U4 arduino running at 3.3V/8MHz. These are cheap, small and really easy to use but only have 16K of RAM and s/w floating point. Another option I'm considering is an AT91SAM3X8E arduino Due which run a load faster, have proper floating point support and 512K of RAM, but the boards are fairly big : 4" by 2" so finding a housing is going to be difficulty. Plus I can't find a way to power one off a 3.3V battery.

    I also looked at using a raspberry pi board, but the idea of having an actual OS running in the computer isn't very appealling.
    Last edited by shapeshifter; 14-02-2016, 07:51 AM.

    Comment

    • P1nky
      TDF Member
      • Dec 2012
      • 113

      #3
      Originally posted by shapeshifter
      I'm using an ATMega 32U4 arduino running at 3.3V/8MHz. These are cheap, small and really easy to use but only have 16K of RAM and s/w floating point. Another option I'm considering is an AT91SAM3X8E arduino Due which run a load faster, have proper floating point support and 512K of RAM, but the boards are fairly big : 4" by 2" so finding a housing is going to be difficulty. Plus I can't find a way to power one off a 3.3V battery.
      Have you looked at the Teensy boards. Alternatively, the M0 Feather board from Adafruit is probably more than capable. I have been looking at both of these for some of my projects.

      Originally posted by shapeshifter
      I also looked at using a raspberry pi board, but the idea of having an actual OS running in the computer isn't very appealling.
      Much as the Pi is a great little board, I certainly wouldn't use it for this kind of thing - I've seen the odd lock-up of the OS while idle, which you definitely don't want in the middle of tracking deco.

      Comment

      • matt
        Established TDF Member
        • Dec 2012
        • 4081

        #4
        I think I missed something, or perhaps the funky layout did it (doesn't help that [code] is bust and space doesn't layout)...

        If you are ongassing:

        if (diver.Pt[i] <= Pigtol /* tissue is already safe.. */)
        { if (Palv >= Pigtol /* PROBLEM CASE */)
        {
        // ..but is on-gassing and will eventually reach saturation
        }
        }
        and

        if (Palv >= diver.Pt[i] /* tissue is on-gassing.. */)
        { if (Palv >= Pigtol /* PROBLEM CASE */)
        {
        // ..and will eventually, but not immediately, reach saturation
        }
        }
        and can never reach an ascent position then isn't the answer that an ascent is never possible so for your code return INFINITY.

        I guess that is your question because in this case your staying underwater forever!

        I don't know if your code can ever reach that state but agree having those corner-cases in there isn't a good idea! Perhaps return something else like USE_TABLES!

        Matt.

        Comment

        • shapeshifter
          Established TDF Member
          • Jan 2013
          • 636

          #5
          Originally posted by P1nky
          Have you looked at the Teensy boards. Alternatively, the M0 Feather board from Adafruit is probably more than capable. I have been looking at both of these for some of my projects.
          I hadn't really considered the teensies although looking at them now it seems like the 32 bit versions might be a pretty good choice.

          I think I'm going to get an Feather M0 Bluefruit which seems to be ideal: 3.3V, built-in LIPO charger. Plenty of CPU and RAM. Thanks for the idea

          Comment

          • MattS
            TDF Member
            • Jan 2014
            • 203

            #6
            [QUOTE=shapeshifter;292526]
            [edit] too late with a teensy recommendation

            Whichever way you go, power will almost certainly be the big challenge and lead you to a 1S (single cell) ~3.7V LIPO. 500mAh to 700mAh are not too bulky but LCD displays are another major power consumption challenge. I can get ~12Hrs from my cobbled together GPS speedo but I have to powering down the LCD to achieve that.

            Good luck with the project. I wrote a deco engine in Delphi (object pascal) many moons ago. Wouldn't want to dive it though
            Last edited by MattS; 14-02-2016, 08:43 AM.

            Comment

            • ebt
              #keepittea
              • Dec 2012
              • 1917

              #7
              float maths are a bit slow and messy on micro-controllers. Theres a few tricks to avoid float maths, but its very dependent upon variable sizes. What sort of value range do you expect to hold in them?

              For low power consumption, the modern OLED's are pretty damn amazing, although I've found the library i was using to drive them (u8lib) essentially blocks the code while it's updating the display (it buffers the whole screen and writes the whole lot out). Other than that, you can save swathes of power using watchdog/sleep modes. Nick Gammons site has a lot of good stuff covering that.

              For a simple dive computer I'd be surprised if you need more oomf than you can get out of a 328. Usually its just a question of writing efficient code and avoiding blocking situations.
              Free "cloud" store with Dropbox // Cheap Mobile SIM only deals with GiffGaff

              Comment

              • Ken
                Established TDF Member
                • Dec 2012
                • 943

                #8
                The main number which counts is the current tissue saturation. Now that will be being updated over time. Thus lots of multiplies, probably of small increments Iie close to 1) due to passing time. If you use a fixed point format you risk significant error accumulation. At least you'd want to model how bad that could get. Personally I'd just go with floating point and make sure I had a sensible enough CPU. There may be better ways to reduce CPU use such as avoiding doing the calculations unless necessary.

                My totally un-optimised c++ can do about 200 full planning calcs a second generating json strings of an ascent plan on 2ishGHz laptop. Maybe it would take a second to do it on an atmel, avoiding memory allocations etc. How often do you need to generate a complete plan? When the current ceiling changes by x?

                Premature optimisation is the root of all evil.

                Comment

                • shapeshifter
                  Established TDF Member
                  • Jan 2013
                  • 636

                  #9
                  As you point out, the heart of the calculation is incrementally maintaining the tissue loadings so, in principle at least, using fixed point arithmetic might allow a slight boost in precision. Not really sure what sort of impact that would have on the results though. The controllers I've been looking at until now are approximately 1000 times slower than your 2GHz machine, so that coupled with the FP operations potentially taking several hundreds or cycles instead of one or two might put the performance on the edge of acceptable.

                  The architecture I'm using has the ascent profile calculation broken down into individual steps; the main loop updates the depth, tissue loadings, ceiling and alarms and then executes a single step (which basically amounts to a sort-of poor man's non-preeemptive multithreading with the ascent calculation running in a low priority thread). That way I maintain reactivity without worrying too much about performance.

                  Of course, all of this might very well become moot if the Feather M0 board turns out to be usable.

                  Originally posted by Ken
                  The main number which counts is the current tissue saturation. Now that will be being updated over time. Thus lots of multiplies, probably of small increments Iie close to 1) due to passing time. If you use a fixed point format you risk significant error accumulation. At least you'd want to model how bad that could get. Personally I'd just go with floating point and make sure I had a sensible enough CPU. There may be better ways to reduce CPU use such as avoiding doing the calculations unless necessary.

                  My totally un-optimised c++ can do about 200 full planning calcs a second generating json strings of an ascent plan on 2ishGHz laptop. Maybe it would take a second to do it on an atmel, avoiding memory allocations etc. How often do you need to generate a complete plan? When the current ceiling changes by x?

                  Premature optimisation is the root of all evil.

                  Comment

                  • nigel hewitt
                    Established TDF Member
                    • Sep 2013
                    • 3199

                    #10
                    I'm probably well out of date but fixed point (B scaled fractions) was in my day the only way we built death support equipment.
                    FPUs were not predictable enough and struggled to keep up with a proper hardware multiplier (8x8=16 table).

                    My OSTC rewrite is all B scaled. You get exactly the same 'value creep' on floating point but it's much harder to document and prove it won't bite you.
                    Helium, because I'm worth it.
                    Waterboarding at Guantanamo Bay sounded like a radical holiday opportunity until I looked it up.

                    Comment

                    • shapeshifter
                      Established TDF Member
                      • Jan 2013
                      • 636

                      #11
                      Implementation details are all very interesting but as a slight change of tack, what to display and how to display it?

                      The small number next to the depth is the average (or possibly maximum, which is more pertinent?) depth.

                      The horizontal bar shows leading tissue super saturation, Pamb at the left, Pigtol at the right. As super saturation changes, the little bar not only moves towards the right but gets redder and redder.

                      "MOD exceeded" causes the depth to turn red, "stop depth exceeded" causes the depth and stop depth to turn orange, "ceiling exceed" causes the depth and stop depth to turn red. Fast ascent causes the surface time to turn red.

                      There's space at the bottom which is going to be used to display current and available gasses. I'm not really planning on displaying anything else there.

                      Indefinite NDL or NDL more than 99 minutes:


                      Finite NDL

                      NDL displayed in minutes.

                      Decompression obligation:

                      First stop depth and estimated total decompression time displayed.

                      At or near decompression stop:

                      Current stop depth and estimated remaining time at stop displayed.

                      Too complicated, not enough information shown?
                      Last edited by shapeshifter; 15-02-2016, 03:30 PM.

                      Comment

                      • shapeshifter
                        Established TDF Member
                        • Jan 2013
                        • 636

                        #12
                        I've got my home-build running on the 3MHz, 8-bit, 32K Atmel and the display handling is coming along nicely:



                        Should be able to get nicer fonts when I switch to the cortex M0 controller.

                        Comment

                        • shapeshifter
                          Established TDF Member
                          • Jan 2013
                          • 636

                          #13
                          All working out rather nicely.

                          The new M4 processor even gives me enough program space to implement anti-aliasing, and the off-gassing-o-meter seems quite nice:





                          Just need to add gas-switching and seal it all in a big box and it'll be dive to take it diving.

                          Comment

                          • shapeshifter
                            Established TDF Member
                            • Jan 2013
                            • 636

                            #14
                            Still on-going, but I have a question for those who may know about these things:

                            During the dive I need to keep track of - and latch - Plow, the ambient pressure of the deepest first stop induced by GF low. When should Plow be reset? At the end of the dive? When all tissues are pretty much back to normal? None of the above or something in-between?

                            Comment

                            • Ken
                              Established TDF Member
                              • Dec 2012
                              • 943

                              #15
                              When you surface.

                              Comment

                              Working...