Forum Upgrade

We’re excited to announce that the Garmin Forums will soon be moving to a new platform that should greatly improve our forum experience for everyone. We will update everyone as more information becomes available.
See more
See less

Algorithm Help!!!

  • Time
  • Show
Clear All
new posts

  • Algorithm Help!!!

    I want to add a feature to my LAPSTATS data field. Capture the Distance and Elapsed Time every 1/10th of a mile during a LAP. Then when the athlete hits lap again for their next lap, I can let them know how far ahead or behind they are relative to their last completed lap. (eg: -125m, +73m, etc).

    However, I don't know in advance how long each lap is. It could be 1/4 mile, or 50 miles. For ultracyclists like me, 100 mile laps are not unreasonable to break down a 24 hour race into big chunks.

    Here are two challenges:

    1. I can't just compute the distance delta based based on average lap speed, because the lap could include steep hills or headwinds, and one section of the lap could be much slower/faster than another section. So I need to break it up into small sections. Like possibly every 1/10th of a mile. So to allow for a 100 mile lap, I'd need a 1000 element static array! Ugh. Lots of wasted memory for most laps that are much shorter. I have never used dynamic arrays. If these are a thing and not too expensive of an operation, I could simply extend the array every 1/10th of a mile when I capture the timestamp. Good idea?

    2. For a short lap distance, like 1/4 mile... every 1/10th of a mile is too long. So I really need a dynamic segment size. But I don't know how long the lap will be. So I guess I could START out saving a timestamp every 50 meters, and if the lap extends beyond a mile, reduce the timestamp frequency to every 100 meters, and finally if the lap extends beyond 5 miles, reduce it to every 160 meters (about 1/10th of a mile). Or some dynamic adaptation like that. To provide good resolution and still not waste a ton of memory.

    If you've done anything like this, let me know if you have ideas. THANKS!

  • #2
    This pretty much sounds like the virtual Trainer. A feature to upload a previous run/ride/hike and the watch tells you if you are ahead or behind.
    That´s done "quite" easy by comparing two fit files. The current and the uploaded one, appropriate to your location and elapsed time.
    But this is a native built in feature, which you cannot reuse.

    Your problem or challenge will be, that you cannot use the storage (fit files). The ram is very, very limited and 1000 entries in an array are not only a waste, they are more or less impossible (according to the size of an entry [Time, distance, GPS, ...]).

    In my opinion, you only have one chance: Calculate how many points (Time & Distance) you can store to the memory, before the watch runs out.
    Take your greatest distance and divide it. Make this value/interval to be set up for shorter distances.

    With both values (Time & Distance) you can now calculate how many meters or seconds you are ahead, to the very next point in your list.
    But be aware: If you want to ride >2 laps, you always rely on the first one. Or you have to override the last entry, after you reached the next.
    Last edited by HerrRiebmann; 01-18-2019, 04:17 AM. Reason: typos...
    Devices: Forerunner 405, Vivoactive & Virb X & XE
    GitHub: Read diagnostic system via Bluetooth
    YouTube: My channel
    App: Stretch


    • #3
      Couple of comments.

      - Dynamic arrays can be worse than static arrays because of memory fragmentation. I.e. lots of small allocations can fail where one large allocation (beforehand) would’ve succeeded.

      - You actually can use disk storage with Application::Storage (newer devices) although it will be slow. If you are only reading or writing every minute or so maybe it will be okay.


      • #4
        When working with large arrays, one other thing to look at is trying to use "simple objects" in the array (number, float, etc). If you use doubles instead of floats, the array will take much more memory.
        My Connect IQ Apps in the Store
        Facebook - Instagram -


        • #5
          Great tip Jim.

          Another tip is if you have arrays of arrays (like one array where each element is an array of 3), flatten them out.

          e.g. Instead of
          [ [Time0, Distance0, GPS0] , [Time1, Distance1, GPS01], ... ]
          [ Time0, Distance0, GPS0 , Time1, Distance1, GPS01, ... ]

          In general, to save memory:
          - Replace classes/complex objects with arrays/simple objects
          - Avoid dictionaries
          - Avoid nested arrays. If you must nest arrays, put the longer arrays inside the shorter arrays

          Another trick is if you know that your data has limited range, you can pack more than one number into a single 32-bit value.

          For example, you could store Time in seconds, then you'd have enough room for 4.5 hours in 14 bits. Then you could use the remaining 18 bits to store Distance in units of 100 metres, which would give you a range of 0 to 26214.4 metres. If that's not enough, you could store Distance in 200 metres. (I'm assuming you only need to store time/distance relative to the beginning of a lap).

          The downside is the limited range of values, and the additional calculations you need to do to get/set data. But usually these are one liners.


          • #6
            The "Array of arrays" had the largest impact when the number of objects was more limited (as it still is on some of the older devices). An array of 1000 arrays takes far more objects that a flat array with the same data.

            There's still an impact with 64k available objects, but it could crash the app when there were far less.
            My Connect IQ Apps in the Store
            Facebook - Instagram -


            • #7
              I agree with everything said above, but you'd might find it better to organize your data with one array for each data type. Using FlowState's notation:

              [ Time0, Time1, ... ]
              [ Distance0, Distance1, ... ]
              [ GPS0, GPS1, ... ]
              You can also use ByteArray to store many 8-bit values, but I'd think bit packing an [/i]Array[/i] of Number would be more flexible.



              • #8
                It sounds to me like in your description of challenge (2) you have already described a good solution with the dynamic segment sizes - my suggestion would just be that when you change the segment size you double it. This way you can have a fixed size array of however many segments you want to store. When you double the segment size then you can go through the array and combine elements 0 & 1 (in 0), elements 2 & 3 (in 1), elements 4 & 5 (in 2) etc. If your array was full before, then now it will be only half full. Start off with your initial segment size as small as you like (1 metre even) and this system will scale up to as large as you like (… 10000km?!)


                • #9
                  Yes, I've used that a few times, where I have something like an array of 1000 for samples, and start taking samples each second. When it fills, I save every other one (back to the same array so no memory increase during that time), and then save new samples every 2 seconds, and the next time I reduce, every 4 seconds, etc., so the interval is constant for all samples Something to be careful of here is the watchdog timer, as while doing 500 copies might be fine, 5000 could trigger the watchdog.
                  My Connect IQ Apps in the Store
                  Facebook - Instagram -