2x1=10

because numbers are people, too
Persönliches
Fotografie
Programmierung
    • Naismith, Aitken-Langmuir, Tranter and Tobler: Modeling hiking speed

      While plan­ning an eleven-day trekking trip through the Hardan­gervid­da in Nor­way, I came across the age old prob­lem of esti­mat­ing the walk­ing time for a giv­en path on the map. While one is eas­i­ly able to deter­mine the times for the main west-east and north-south routes from a trav­el guide, there sad­ly is no infor­ma­tion about those self-made prob­lems (i.e. cus­tom routes). Obvi­ous­ly, a sim­ple and cor­rect solu­tion needs to be found.

      Of course, there is no such thing. When search­ing for hik­ing time rules, two can­di­dates pop up reg­u­lar­ly: Naismith’s rule (includ­ing Tranter’s cor­rec­tions), as well as Tobler’s hik­ing func­tion.

      William W. Naismith’s rule — and I couldn’t find a sin­gle sci­en­tif­ic source — is more a rule of thumb than it is exact. It states:

      For every 5 kilo­me­tres, allow one hour. For every 600 metres of ascend, add anoth­er hour.

      which reads as


      \begin{align}
      \theta &= \tan^{-1}(\frac{\Delta a}{\Delta s}) \\
      t &= \Delta s \left( \frac{1\mathrm{h}}{5\mathrm{km}} \right) + \Delta a \left( \frac{1 \mathrm{h}}{0.6 \mathrm{km}} \right) \\
      |\vec{w}| &= \frac{\Delta s}{t}
      \end{align}

      where \(|\vec{w}|\) is the walk­ing speed, \(\Delta s\) the length on the hor­i­zon­tal plane (i.e. “for­ward”), \(\Delta a\) the ascend (i.e. the dif­fer­ence in height) and \(\theta\) the slope.

      function [w, t, slope] = naismith(length, ascend)
          slope = ascend/length;
          t = length*(1/5) + ascend*(1/0.6);
          w = length./t;
      end
      

      That looks like

      Naismith's rule (plot)

      Inter­est­ing­ly, this implies that if you climb a 3 km moun­tain straight up, it will take you 5 hours. By recog­nis­ing that \(5 \textrm{km} / 0.6 \textrm{km} \approx 8.3 \approx 8\) , the 8 to 1 rule can be employed, which allows the trans­for­ma­tion of any (Nai­smith-ish) track to a flat track by cal­cu­lat­ing


      \begin{align}
      \Delta s_{flat} &= \Delta s + \frac{5 \mathrm{km}}{0.6 \mathrm{km}} \cdot \Delta a\\
      &\approx \Delta s + 8 \cdot \Delta a
      \end{align}

      So a track of \(20 \textrm{km}\) in length with \(1 \textrm{km}\) of ascend would make for \(\mathrm{km} + 8 \cdot 1 \mathrm{km} = 28 \mathrm{km}\) of total track length. Assum­ing an aver­age walk­ing speed of \(5 \mathrm{km/h}\) , that route will take \(28 \mathrm{km} / 5 \mathrm{km/h} = 5.6 \mathrm{h}\) , or 5 hours and 36 min­utes. Although quite inac­cu­rate, some­body found this rule to be accu­rate enough when com­par­ing it against times of men run­ning down hills in Nor­way. Don’t quote me on that.

      Robert Aitken assumed that 5 km/h might be too much and set­tled for 4 km/h on all off-track sur­faces. Unfor­tu­nate­ly the Nai­smith rule still didn’t state any­thing about descent or slopes in gen­er­al, so Eric Lang­muir added some refine­ments:

      When walk­ing off-track, allow one hour for every 4 kilo­me­tres (instead of 5 km). When on a small decline of 5 to 12°, sub­tract 10 min­utes per 300 metres (1000 feet). For any steep­er decline (i.e. over 12°), add 10 min­utes per 300 metres of descent.

      Now that’s the stuff won­der­ful­ly non-dif­fer­en­tiable func­tions are made of:

      Naismith's rule with Aitken-Langmuir corrections (plot)

      That is:


      \begin{align}
      \theta &= \tan^{-1}(\frac{\Delta a}{\Delta s}) \\
      t &= \Delta s \left( \frac{1\mathrm{h}}{5\mathrm{km}} \right) + \begin{cases}
      +\Delta a \left( \frac{1 \mathrm{h}}{0.6 \mathrm{km}} \right) , & \text{if $\theta > -5^\circ$} \\
      -|\Delta a| \left( \frac{\left(10/60\right) \mathrm{h}}{0.3 \mathrm{km}} \right) , & \text{if $-12^\circ \le \theta \le -5^\circ$} \\
      +|\Delta a| \left( \frac{\left(10/60\right) \mathrm{h}}{0.3 \mathrm{km}} \right) , & \text{if $\theta < -12^\circ$}
      \end{cases} \\
      |\vec{w}| &= \frac{\Delta s}{t}
      \end{align}

      It should be clear that 12 km/h is an high­ly unlike­ly speed, even on roads.

      function [w, t, slope] = naismith_al(length, ascend, base_speed)
          if ~exist('base_speed', 'var')
              base_speed = 4; % km/h
          end
      
          slope = ascend/length;
          
          t = length*(1/base_speed);
          if slope >= 0
              t = t + ascend*(1/0.6);
          elseif atand(slope) <= -5 && atand(slope) >= -12
              t = t - abs(ascend)*((10/60)/0.3);
          elseif atand(slope) < -12
              t = t + abs(ascend)*((10/60)/0.3);
          end
          
          w = length./t;
      end
      

      So Wal­do Tobler came along and devel­oped his “hik­ing func­tion”, an equa­tion that assumes a top speed of 6 km/h with an inter­est­ing fea­ture: It — though still indif­fer­en­tiable — adapts grace­ful­ly to the slope of the ground. That func­tion can be found in his 1993 report “Three pre­sen­ta­tions on geo­graph­i­cal analy­sis and mod­el­ing: Non-isotrop­ic geo­graph­ic mod­el­ing spec­u­la­tions on the geom­e­try of geog­ra­phy glob­al spa­tial analy­sis” and looks like the fol­low­ing:

      Tobler's hiking function (plot)

      It boils down to the fol­low­ing equa­tion of the walk­ing speed \(|\vec{w}|\) “on foot­paths in hilly ter­rain” (with \(s=1\) ) and “off-path trav­el” (with \(s=0.6\) ):


      \begin{align}
      |\vec{w}| = s \cdot 6e^{-3.5 \cdot | \tan(\theta) + 0.05 |}
      \end{align}

      where \(\tan(\theta)\) is the tan­gent of the slope (i.e. ver­ti­cal dis­tance over hor­i­zon­tal dis­tance). By tak­ing into account the exact slope of the ter­rain, this func­tion is supe­ri­or to Naismith’s rule and a much bet­ter alter­na­tive to the Lang­muir bug­fix, espe­cial­ly when used on GIS data.

      function [w] = tobler(slope, scaling)
          w = scaling*6*exp(-3.5 * abs(slope+0.05));
      end
      


      It how­ev­er lacks the one thing that makes the Nai­smith rule stand out: Tranter’s cor­rec­tions for fatigue and fit­ness. (Yes, I know it gets weird.) Sad­ly these cor­rec­tions seem to only exists in the form of a mys­ti­cal table that looks, basi­cal­ly, like that:

      Fit­ness in min­utes Time in hours accord­ing to Naismith’s rule
      2 3 4 5 6 7 8 9 10 12 14 16 18 20 22 24
      15 (very fit) 1 1½ 2 2¾ 3½ 4½ 5½ 6¾ 7¾ 10 12½ 14½ 17 19½ 22 24
      20 1¼ 2¼ 3¼ 4½ 5½ 6½ 7¾ 8¾ 10 12½ 15 17½ 20 23
      25 1½ 3 4¼ 5½ 7 8½ 10 11½ 13¼ 15 17½
      30 2 3½ 5 6¾ 8½ 10½ 12½ 14½
      40 2¾ 4¼ 5¾ 7½ 9½ 11½
      50 (unfit) 3¼ 4¾ 6½ 8½

      where the min­utes are a rather obscure mea­sure of how fast some­body is able to hike up 300 metres over a dis­tance of 800 metres ($20^\circ$). With that table the rule is: If you get into nas­ti­er ter­rain, drop one fit­ness lev­el. If you suck at walk­ing, drop a fit­ness lev­el. If you use a 20 kg back­pack, drop one lev­el. Sad­ly, there’s no equa­tion to be found, so I had to make up one myself.

      hours   = [2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 16, 18, 20, 22, 24];
      fitness = [15, 20, 25, 30, 40, 50];
      table   = [1,    1.5,  2,    2.75, 3.5, 4.5,  5.5,  6.75, 7.75,  10,   12.5, 14.5, 17,  19.5, 22, 24;
                 1.25, 2.25, 3.25, 4.5,  5.5, 6.7,  7.75, 8.75, 10,    12.5, 15,   17.5, 20,  23,  NaN, NaN;
                 1.5,  3,    4.25, 5.5,  7,   8.5,  10,   11.5, 13.25, 15,   17.5, NaN,  NaN, NaN, NaN, NaN;
                 2,    3.5,  5,    6.75, 8.5, 10.5, 12.5, 14.5, NaN,   NaN,  NaN,  NaN,  NaN, NaN, NaN, NaN;
                 2.75, 4.25, 5.75, 7.5,  9.5, 11.5, NaN,  NaN,  NaN,   NaN,  NaN,  NaN,  NaN, NaN, NaN, NaN;
                 3.25, 4.75, 6.5,  8.5,  NaN, NaN,  NaN,  NaN,  NaN,   NaN,  NaN,  NaN,  NaN, NaN, NaN, NaN];
      

      By look­ing at the table and the mesh plot it seems that each time axis for a giv­en fit­ness is log­a­rith­mic.

      Tranter's corrections to Naismith's rule (mesh plot)

      I did a log-log plot and it turns out that the series not only appear to be log­a­rith­mic in time, but also in fit­ness. By deriv­ing the (log-log-)linear regres­sion for each series, the fol­low­ing equa­tions can be found:


      \begin{align}
      t_{15}(t) &= e^{1.35 \,ln(t) - 1.08} \\
      t_{20}(t) &= e^{1.24 \,ln(t) - 0.55} \\
      t_{25}(t) &= e^{1.25 \,ln(t) - 0.33} \\
      t_{30}(t) &= e^{1.31 \,ln(t) - 0.21} \\
      t_{40}(t) &= e^{1.14 \,ln(t) + 0.20} \\
      t_{50}(t) &= e^{1.05 \,ln(t) + 0.44} \\
      \end{align}

      Tranter's corrections (log-log plot)

      These ear­ly approx­i­ma­tions appear to be quite good, as can be seen in the fol­low­ing lin­ear plot. The last three lines \(t_{30}\) , \(t_{40}\) and \(t_{50}\) how­ev­er begin to drift away. That’s expect­ed for the last two ones due to the small num­ber of sam­ples, but the \(t_{30}\) line was irri­tat­ing.

      Tranter's corrections (linear plot)

      My first assump­tion was that the \(t_{40}\) and \(t_{50}\) lines sim­ply are out­liers and that the real coef­fi­cient for the time vari­able is the (out­lier cor­rect­ed) mean of \(1.2215 \pm 0.11207\) . This would imply, that the inter­sect coef­fi­cient is the vari­able for fit­ness.

      Tranter's corrections in log-log plot (mean fix)

      Unfor­tu­nate­ly, this only seems to make things bet­ter in the log-log plot, but makes them a lit­tle bit worse in the lin­ear world.

      Tranter's corrections in linear plot (mean fix)

      Equi-dis­tant inter­sect coef­fi­cients also did not do the trick. Well, well. In the end, I decid­ed to give the brute force method a chance and defined sev­er­al fit­ting func­tions for the use with genet­ic algo­rithm and pat­tern search solvers, includ­ing expo­nen­tial, third-order and sig­moidal forms. The best ver­sion I could come up with was

      \(
      \begin{align}
      t_{corrected}(t, f) &= 0.31381 \,e^{1.2097 \,ln(t) + 0.81328 \,ln(f) - 1.7307}
      \end{align}
      \)

      This func­tion results in a least squared error of about 21.35 hours over all data points. The fol­low­ing shows the orig­i­nal sur­face from the table and the syn­thet­ic sur­face from the func­tion.

      Tranter's table vs. synthetic table (surface plot)

      A max­i­mum devi­a­tion of about 1 hour can be seen clear­ly in the fol­low­ing error plot for the $t_{30}$ line, which real­ly seems to be an out­lier.

      Tranter's table vs. synthetic table error (surface plot)

      For com­par­i­son (here’s the orig­i­nal table), this is the syn­thet­ic cor­rec­tion table:

      Fit­ness in min­utes Time in hours accord­ing to Naismith’s rule
      2 3 4 5 6 7 8 9 10 12 14 16 18 20 22 24
      15 (very fit) 1¼ 2 2¾ 3½ 4½ 5¼ 6¼ 7¼ 8¼ 10¼ 12¼ 14½ 16½ 18¾ 21¼ 23½
      20 1½ 2½ 3½ 4½ 5½ 6¾ 7¾ 9 10¼ 12¾ 15½ 18¼ 21 23¾
      25 1¾ 3 4 5¼ 6¾ 8 9½ 10¾ 12¼ 15½ 18½
      30 2 3¼ 4¾ 6¼ 7¾ 9¼ 11 12½
      40 2½ 4¼ 6 7¾ 9¾ 11¾
      50 (unfit) 3 5 7¼ 9½
      Juni 14th, 2014 GMT +2 von
      Markus
      2014-06-14T08:19:40+02:00 2018-03-4T14:16:13+02:00 · 0 Kommentare
      Naismith Tobler Tranter Trekking Curve Fitting
      MATLAB Data Science Mapping

      Hinterlasse einen Kommentar

      Hier klicken, um das Antworten abzubrechen.

    1. « newer
    2. 1
    3. …
    4. 17
    5. 18
    6. 19
    7. 20
    8. 21
    9. 22
    10. 23
    11. …
    12. 43
    13. older »
    • Kategorien

      • .NET
        • ASP.NET
        • Core
        • DNX
      • Allgemein
      • Android
      • Data Science
      • Embedded
      • FPGA
      • Humor
      • Image Processing
      • Kalman Filter
      • Machine Learning
        • Caffe
        • Hidden Markov Models
        • ML Summarized
        • Neural Networks
        • TensorFlow
      • Mapping
      • MATLAB
      • Robotik
      • Rust
      • Signal Processing
      • Tutorial
      • Version Control
    • Neueste Beiträge

      • Summarized: The E-Dimension — Why Machine Learning Doesn’t Work Well for Some Problems?
      • Use your conda environment in Jupyter Notebooks
      • Building OpenCV for Anaconda Python 3
      • Using TensorFlow’s Supervisor with TensorBoard summary groups
      • Getting an image into and out of TensorFlow
    • Kategorien

      .NET Allgemein Android ASP.NET Caffe Core Data Science DNX Embedded FPGA Hidden Markov Models Humor Image Processing Kalman Filter Machine Learning Mapping MATLAB ML Summarized Neural Networks Robotik Rust Signal Processing TensorFlow Tutorial Version Control
    • Tags

      .NET Accelerometer Anaconda Bitmap Bug Canvas CLR docker FPGA FRDM-KL25Z FRDM-KL26Z Freescale git Gyroscope Integration Drift Intent J-Link Linear Programming Linux Magnetometer Matlab Mono Naismith OpenCV Open Intents OpenSDA Optimization Pipistrello Player/Stage PWM Python Sensor Fusion Simulink Spartan 6 svn tensorflow Tilt Compensation TRIAD ubuntu Windows Xilinx Xilinx SDK ZedBoard ZYBO Zynq
    • Letzte Kommetare

      • Lecke Mio bei Frequency-variable PWM generator in Simulink
      • Vaibhav bei Use your conda environment in Jupyter Notebooks
      • newbee bei Frequency-variable PWM generator in Simulink
      • Markus bei Using TensorFlow’s Supervisor with TensorBoard summary groups
      • Toke bei Using TensorFlow’s Supervisor with TensorBoard summary groups
    • Blog durchsuchen

    • Juni 2014
      M D M D F S S
      « Apr   Aug »
       1
      2345678
      9101112131415
      16171819202122
      23242526272829
      30  
    • Self

      • Find me on GitHub
      • Google+
      • Me on Stack­Ex­change
      • Ye olde blog
    • Meta

      • Anmelden
      • Beitrags-Feed (RSS)
      • Kommentare als RSS
      • WordPress.org
    (Generiert in 0,473 Sekunden)

    Zurück nach oben.