ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

拖一条 GPX 就知道几点登顶?我用码道 Agent 写了个_登山钟_,让三个老公式互相打架

拖一条 GPX 就知道几点登顶?我用码道 Agent 写了个_登山钟_,让三个老公式互相打架 拖一条 GPX 就知道几点登顶我用码道 Agent 写了个登山钟让三个老公式互相打架一、这玩意儿是干嘛的户外领队排一条登山线最头疼的一个问题是这条线走下来到底要几个小时8 公里爬升 600 米是 3 小时还是 6 小时差一小时内可能就是要不要带够水、要不要摸黑下山的区别。我做了个网页把一条 GPX 登山轨迹拖进去它给你画出海拔剖面然后同时用三个经典的徒步耗时公式各算一遍——Naismith1892 年的老规矩、Tobler1994 年的实测函数、Braun2001 年的简化版——三条时间条并排一放谁快谁慢、差多少一目了然。这项目真正有意思的地方不在算了个时间而在我拿它去跟苏格兰山峰的实测记录对拍结果三个公式全都系统性低估了实际耗时最多差到 77%。这个翻车反而是整个项目最值钱的部分我后面细讲。说白了一个敢把自己算不准的地方摊开的项目比一个假装很准的项目可信得多。先交代背景代码是喂华为云码道 CodeArts Agent一轮一轮建的我只负责出题、验收、填坑。仓库atomgit.com/lskcode/summit-watch8 项测试全绿。二、为什么做这个我有个朋友玩越野跑每次组队爬山前都要在群里问这条线大家一般走多久然后收获一堆看体力“看天气”我上次走了 X 小时的模糊答案。他说要是有个东西能根据轨迹直接估个时间区间就好了。我听完就觉得这需求太具体了具体到能写成一个周末项目。这东西其实有现成的科学。徒步圈估时间不是拍脑袋是有公式的最出名的就是苏格兰人 W.A.D. Naismith 在 1892 年提出的经验法则平地每小时走 800 米其实是约 5 公里/小时每爬升 100 米额外加 10 分钟。后来不断有人改进它。既然有公式、又有大量山峰的实测记录那就可以做一件很理工科的事让几个独立公式互相比再拿真实山峰的实测时间当裁判。选题三条铁律一秒看懂、有客观真值、别撞车。登山估时这个角度获奖名单里没有而且它有公开的第三方实测数据Munro’s Tables——苏格兰 282 座海拔 3000 英尺以上山峰的登顶记录可以当裁判。行。这里多说一句为什么客观真值这三条铁律里我最看重它。做技术分享最容易自嗨——功能堆一堆、界面做得漂漂亮亮但没人知道你到底算得对不对。有了第三方真值当尺子好不好这种主观判断题就被逼成了准不准这种能用数字回答的客观题你糊弄不了任何人包括你自己。这也是我三篇都死磕对拍的原因。三、先跑起来看看零依赖纯 Node 20 ES Modulegitclone https://atomgit.com/lskcode/summit-watch.gitcdsummit-watchnode--test# 8 项测试全绿nodebin/dev.mjs# http://localhost:5173拖一条 GPX 进去或者点内置的四个山峰预设之一。剖面图立刻出来下面三条时间条排开。我特意在页面底部加了一行小字把三个公式各自的假设写清楚Naismith 假设平地 800 米/小时 每 100 米爬升加 10 分钟Tobler 假设速度随坡度指数衰减、下坡过快反而更慢Braun 假设每 100 米爬升折 2 分钟。因为我觉得一个估时间的工具如果只给数字不给假设跟算命没区别。你把假设摊开用户才知道该在什么场景信哪个数。视觉我按老规矩做的纯深底#0b1120、单一冷蓝#4d9dff、纯白文字最快那条的数字标蓝其余纯白不整花活。四、怎么钉码道 Agent跟前两篇一样的打法。码道跑在华为云上、只能在我登录的 AtomGit 账号里干活参赛截图带账号。提示词钉到函数级结尾永远挂那句铁律直接建文件并git add -A git commit git push不要只描述、不要贴代码正文只回复 git log 文件树 测试 pass/fail。第一轮的核心提示词原样【R1 · 登顶钟 summit-watch 三公式核心引擎】 建 public 仓库 summit-watch。Node 20 ES Module零依赖node:test。 - src/naismith.mjs predict({dist_m, ascent_m, rest_min_per_hr}) 经典 Naismith: 平地 800 m/h 每 100 m 爬升加 10 min - src/tobler.mjs walkingSpeedKmh(slope_deg) 6·exp(-3.5·|φ0.05|) - src/braun.mjs t (dist_m/1000)/5 (ascent_m/100)/30 - src/geo.mjs haversineM cumulativeAscent MUNRO_SAMPLES(4条山峰) - test 硬断言: naismith(8000,600)≈11h; tobler(0坡度)≈5.03 km/h 直接建文件并 git commit git push只回复 git log 文件树 测试 pass/fail五、架构一条链三个独立出口数据流很直GPX 解析 → 剖面距离累计爬升分段坡度→ 三个公式各算各的 → 三角互证。公式定义式来源/假设Naismith 1892800m/h 10min/100m经验法则纯移动时间Tobler 1994W6·e^(−3.5|φ0.05|)德国徒步实测拟合Braun 2001dist/5 ascent/3000每 100m 爬升 2min关键是这三个公式出身完全独立Naismith 是 1892 年苏格兰人的经验Tobler 是 1994 年地理学家从实测数据拟合的函数Braun 是 2001 年另一套简化。它们不是同一个公式换写法所以拿来互证是有意义的——这跟我在上一篇冲奶钟里踩过的假独立坑正好相反这次我学乖了先确认三个公式来源独立才动手。六、核心算法掰开揉碎先算轨迹的三维距离和累计爬升// src/geo.mjsexportfunctionhaversineM([lat1,lon1],[lat2,lon2]){constR6371000,toRaddd*Math.PI/180;constdLattoRad(lat2-lat1),dLontoRad(lon2-lon1);constaMath.sin(dLat/2)**2Math.cos(toRad(lat1))*Math.cos(toRad(lat2))*Math.sin(dLon/2)**2;return2*R*Math.asin(Math.sqrt(a));}exportfunctioncumulativeAscent(pts){letup0;for(leti1;ipts.length;i)upMath.max(0,pts[i].elev_m-pts[i-1].elev_m);returnup;}Naismith 本体一行核心// src/naismith.mjsexportfunctionpredict({dist_m,ascent_m,rest_min_per_hr0}){constflat_hdist_m/800;constclimb_h(ascent_m/100)*(10/60);returnflat_hclimb_hrest_min_per_hr*(flat_hclimb_h)/60;}Tobler 的精髓是速度随坡度呈指数衰减而且下坡太快反而更费时间伤膝盖、要刹车所以它是个带峰的曲线// src/tobler.mjsexportfunctionwalkingSpeedKmh(slope_rad){return6*Math.exp(-3.5*Math.abs(slope_rad0.05));}Braun 是三者里最干脆的直接把距离和爬升折成小时// src/braun.mjsexportfunctionpredict({dist_m,ascent_m}){return(dist_m/1000)/5(ascent_m/100)*(1/30);// 每100m爬升2min1/30h}剖面构建按每 100 米水平距离切一段段内平均坡度这样 Tobler 才能逐段算// src/profile.mjsexportfunctionbuildProfile(pts){constsegs[];letacc0;for(leti1;ipts.length;i){consthorizhaversineM(pts[i-1],pts[i]);constdzpts[i].elev_m-pts[i-1].elev_m;acchoriz;segs.push({at_m:acc,horiz,dz,slope:Math.atan2(dz,horiz)});}return{total_dist_m:acc,segments:segs,ascent:segs.reduce((s,x)sMath.max(0,x.dz),0)};}三个公式跑完再取中位数做三角互证谁偏离中位数太多就打 flag// src/triangulation.mjsexportfunctiontriangulate(profile){constr[{name:Naismith,h:naismith(profile)},{name:Tobler,h:toblerPredict(profile)},{name:Braun,h:braun(profile)},];constmedmedian(r.map(xx.h));returnr.map(x({...x,delta_pct:(x.h-med)/med*100}));}七、最值钱的部分三个公式一起翻车我把四个苏格兰真实山峰距离、爬升取自 Munro’s Tables实际耗时是登山者的普遍记录喂进三个公式结果是这样的山峰距离爬升实测NaismithToblerBraunBen Nevis7.0km1340m8h3.632.741.85Sgora Dubh4.0km700m2.5h1.971.481.03Buachaille14.0km1500m9h5.304.073.30Stob Coire8.5km1200m6h3.702.792.10第一眼看我以为是 bug——怎么三个公式全都比实测快一大截Naismith 差 55%Braun 差到 77%查了半天不是代码错是口径对不上而且这个对不上本身就是最该写进文章的发现实测时间是往返、含休息、含拍照吃饭、含地形磨蹭而这些公式算的是纯移动的爬升时间。Ben Nevis 那 8 小时是上下山来回加歇脚公式只算了上山移动。Naismith 原始版本其实自带每爬升 600 米加 1 小时休息的补丁我第一版没开 rest偏差就更大。开上之后 Naismith 立刻变成三者里最接近实测的——这解释了为什么 130 多年后大家还在用它。所以这个项目的护城河不是我算得比谁准而是三个独立公式在同一条轨迹上互相印证它们彼此之间是自洽的并且诚实地暴露了移动时间 ≠ 实际耗时这个所有徒步公式共同的系统性偏差。我把这个 gap 用一张表摊开比给一个假装很准的数字有用得多。我特意把这个翻车做成了文章的核心而不是藏起来因为我觉得这才是这类工具最该告诉用户的话公式给你的是一条理论最快移动时间的下界你实际走下来基本要在这个基础上乘个 1.5 到 2 倍再算上歇脚。领队排线时如果只信公式的 3.6 小时很可能要摸黑下山。所以我在 UI 上干脆把三公式里最慢的那个标出来提醒用户这已经是偏乐观的估计了。顺带说个数据口径的坑Munro’s Tables 里那些8 小时是登山者记录的往返总时长而我 fixture 的 GPX 是上山单向的轨迹。这两者本来就不该直接相等。我第一版没想清楚差点闹了公式全错的乌龙。搞清楚口径之后才明白把单向移动时间 ×2 再加休息Naismith 的 3.63 小时就大致能对上 8 小时的往返实测了。这个换算我在 README 里写清楚了免得下一个看代码的人也栽进去。八、测试8 项// test/summit.test.mjstest(naismith(8000m, 600m, rest0) ≈ 11h,(){assert.ok(Math.abs(naismith({dist_m:8000,ascent_m:600,rest_min_per_hr:0})-11)0.01);});test(tobler 0 坡度速度 ≈ 5.03 km/h,(){assert.ok(Math.abs(tobler.walkingSpeedKmh(0)-5.0255)0.001);});test(haversine [0,0]→[0,1] ≈ 111194.93 m,(){assert.ok(Math.abs(haversineM([0,0],[0,1])-111194.93)0.5);});这里有个我特意坚持的原则测试断言的是公式的数学性质而不是公式算出来的具体数字。比如我断言naismith(8000, 600)必须等于 11 小时因为 8000/800 600/100×10/60 101 就是这个数这是在验证我有没有把公式写对而不是在验证这座山该走多久——后者是现实问题不该由单元测试拍板。把代码对不对和世界是不是这样分开是我这三篇一路踩坑踩出来的习惯。九、真实的坑坑 1fixture 口径没对齐集成测试差点写崩。我一开始给码道的 Ben Nevis fixture 是单向 7 公里但实测 8 小时是往返口径集成测试断言≈8h直接挂。码道一度想把 fixture 改成往返 24 公里来凑Write 还失败了。我拦住它别为了测试好看去改数据把断言改成三公式结果都是正数、落在合理区间、Naismith Braun这种不依赖口径的稳健断言反而诚实。坑 2Tobler 的分段。它要按坡度算速度所以得先把轨迹切成一段段再累加时间。第一版码道按点数切段长不均导致误差改成按每 100 米水平距离切段才对。坑 3码道配额 上下文又满了。这项目跑到 R5 时 deepseek 配额耗尽、上下文顶到 100% 自动压缩跟前两篇一样。已经见怪不怪了。压缩之后它偶尔会忘了前面定的接口我不得不在提示词里把函数签名再钉一遍才接得上。坑 4Tobler 的下坡段一开始被我算反。我最初以为下坡肯定更快给它的输入用了正斜率结果下坡速度爆表、时间反而比 Naismith 还短。后来才反应过来 Tobler 那个|φ0.05|里的加 0.05 就是专门用来惩罚陡下坡的——下坡斜率取负加 0.05 之后绝对值反而变大速度指数衰减。这个下坡更慢的反直觉设计恰恰是它比 Naismith 更贴真实的地方。十、提效数据环节码道 Agent我建仓库 写 20 文件✅出题三公式实现 GPX 解析✅验收发现系统性低估并解释❌✅ 我拦住改数据凑测试❌✅ 我写这篇文章❌✅码道能把三个公式的实现、GPX 解析、剖面算法飞快地搭出来但三个公式一起低估实测这件事意味着什么、该不该为了测试改数据——这种判断它给不了甚至会往错的方向使劲想改 fixture 凑数。人的价值就在按住它这一下。十一、五维自检眼前一亮拖条 GPX 秒出三公式登顶时间户外人一秒懂。可验证护城河三个出身独立的公式互证 对 Munro 实测的系统性偏差量化node evidence/verify.mjs一键复现。原创度不吹算得准而是把公式共同的偏差当卖点角度独一份。工程质量8 项测试、零依赖、分层清晰。诚实度移动时间≠实际耗时、rest 口径、Tobler 分段坑全写进 README。这五条里我最满意的是第二条。它没有假装自己最准而是老老实实说三个独立公式互相能对上但一起偏乐观偏多少我列给你看。我觉得这种我知道我哪里不准的项目比那种吹自己算法多牛的结果更值得信。十二、本地跑 写在最后nodeevidence/verify.mjs# Ben Nevis 8h: N 3.63 / T 2.74 / B 1.85 (三公式一致低估Naismith 最接近)三篇会算 XX 的小工具写到这我攒了个共同的心得做这类带客观真值的小项目最忌讳的是自己跟自己玩。潮汐那篇我差点拿同窗自洽当独立验证冲奶那篇差点拿同源算法当三路互证这篇我一开始想把 fixture 改了去凑那个 8 小时。三次都是同一个坑的不同马甲——让 AI 快速产出很容易让产出对得上现实很难而后者才是这类项目全部的意义。我把这三篇连起来看其实讲的是一件事AI 时代写代码的门槛在塌但可信的门槛反而在抬。码道能在一个下午帮我把三个公式、一个 GPX 解析器、一张剖面图画全但它不会主动去查 Ben Nevis 那 8 小时到底是往返还是单程也不会在我把验证做成自证的时候拍桌子。这些较真的活儿眼下还得人来干。所以与其焦虑 AI 会不会取代写代码不如练一双能一眼看出这验证到底成不成立的眼睛——这才是这类小项目真正练的东西。三个公式一起翻车这件事最后反而成了这个项目最硬的证据它证明我真的拿它们去撞了现实而不是关起门来自嗨。仓库在这欢迎拖你自己的登山轨迹来对https://atomgit.com/lskcode/summit-watch这是我会算 XX 的小工具系列第三篇也是收官。三篇用同一套打法选题一秒看懂、护城河有客观真值、评审真敢挑刺。三篇下来码道 Agent 帮我省了至少两周的敲键盘时间但真正决定项目成色的是那几次这验证到底成不成立的较真。如果这个系列对你有启发三连走起是我继续肝的动力有想看的下一个选题评论区点菜。
返回列表