Hello and welcome to our community! Is this your first visit?
Register
Page 1 of 7 123 ... LastLast
Results 1 to 10 of 65
  1. #1
    TDF Member
    Join Date
    Jan 2013
    Location
    South of France
    Posts
    495
    Likes (Given)
    114
    Likes (Received)
    129

    Home-build diving computer

    Quote Originally Posted by notdeadyet View Post
    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 at 07:57 AM.

  2. #2
    TDF Member
    Join Date
    Jan 2013
    Location
    South of France
    Posts
    495
    Likes (Given)
    114
    Likes (Received)
    129
    Quote Originally Posted by Ken View Post
    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.


    Quote Originally Posted by Ken View Post
    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 at 07:51 AM.

  3. #3
    TDF Member
    Join Date
    Dec 2012
    Location
    Fife
    Posts
    85
    Likes (Given)
    63
    Likes (Received)
    24
    Quote Originally Posted by shapeshifter View Post
    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.

    Quote Originally Posted by shapeshifter View Post
    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.

  4. #4
    Established TDF Member matt's Avatar
    Join Date
    Dec 2012
    Location
    London
    Posts
    4,150
    Likes (Given)
    976
    Likes (Received)
    1236
    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.

  5. #5
    TDF Member
    Join Date
    Jan 2013
    Location
    South of France
    Posts
    495
    Likes (Given)
    114
    Likes (Received)
    129
    Quote Originally Posted by P1nky View Post
    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

  6. #6
    TDF Member
    Join Date
    Jan 2014
    Location
    Emsworth, by the sea
    Posts
    203
    Likes (Given)
    36
    Likes (Received)
    90
    [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 at 08:43 AM.

  7. #7
    #keepittea ebt's Avatar
    Join Date
    Dec 2012
    Location
    dahn saf
    Posts
    1,852
    Likes (Given)
    377
    Likes (Received)
    1119
    Blog Entries
    1
    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.

  8. #8
    Established TDF Member
    Join Date
    Dec 2012
    Posts
    894
    Likes (Given)
    9
    Likes (Received)
    238
    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.

  9. #9
    TDF Member
    Join Date
    Jan 2013
    Location
    South of France
    Posts
    495
    Likes (Given)
    114
    Likes (Received)
    129
    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.

    Quote Originally Posted by Ken View Post
    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.

  10. #10
    Established TDF Member nigel hewitt's Avatar
    Join Date
    Sep 2013
    Location
    Brighton, at the Marina end.
    Posts
    2,771
    Likes (Given)
    503
    Likes (Received)
    2019
    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.


 
Page 1 of 7 123 ... LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •