[{"content":"野外深空拍摄有两个网络问题需要处理：ASIAIR 自带的 Wi-Fi 覆盖范围有限，iPad 接入该网络后无法访问互联网。另外，希望拍摄期间就把文件同步到家里的 NAS，收工后不必再把设备搬回家、通过家庭 Wi-Fi 传输。\n本文记录这套组网与回传方案，以及实施过程中实测得到的结果。\n拓扑 1 相机 ──5G Wi-Fi── 旅行路由 ──STA 上行── 现场 Wi-Fi ──Tailscale── 家里的 NAS 相机与 iPad 接入旅行路由的 5 GHz 热点，处于同一局域网，ASIAIR 监看正常。 路由以 STA 模式接入现场已有的 Wi-Fi，提供互联网上行；iPad 的流量经此上行，监看期间仍可访问外网。 路由通过 Tailscale 与家庭网络建立隧道，用于把文件写入 NAS。 路由上行实测为 5 GHz、信号 −35 dBm、协商速率 866.7 Mbit/s（PHY 速率，非应用层吞吐）。\n下文用 CAM_IP 代指相机的固定地址，用 192.168.3.0/24 作为路由内网的示例网段。\nASIAIR 提供的信息 SMB 共享。 ASIAIR 将存储以 SMB 共享出来，名称为 EMMC Images。目录结构为 Autorun/\u0026lt;类型\u0026gt;/\u0026lt;目标\u0026gt;/，类型包括 Light、Flat、Dark、Bias；每张 FIT 旁附一个 _thn.jpg 缩略图。本方案只挂载该共享，且挂载为只读。\nApp 状态。 拍摄进度、单张剩余时间、相机温度、导星曲线显示在 iPad 上的 ASIAIR App 中。这些信息用于现场判断，但没有可供脚本读取的稳定接口。\n接口与日志。 本方案未使用 ASIAIR 的接口，所有判断都以文件为准：目录结构、文件名中的时间戳、文件大小。判断依据单一，避免 App 显示与实际文件不一致时产生歧义。\n链路与实测带宽 用途 路径 实测速度 现场监看、参数调整 iPad 连路由的 Wi-Fi 16.9 MB/s 路由读取相机存储 同一局域网 约 10 MB/s 路由写入 NAS Tailscale 隧道 0.48–0.53 MB/s 家庭网络直接读取相机文件 Tailscale 隧道 0.40–0.59 MB/s 局域网链路不构成瓶颈；隧道是全程最慢的一段，约 0.5 MB/s。\n传输能力与拍摄节奏 单张曝光 300 秒，一张 FIT 约 50 MB（实测 52,188,480 字节）。按 0.48–0.53 MB/s 计算，单张传输耗时约 100–110 秒，占 300 秒曝光窗口的三分之一左右，可与拍摄并行。\n按一晚 8 小时、每张另计 30 秒开销估算，约 87 张、合计 4.3 GB；全部传输约需 2.5 小时，分散在整晚完成。稳态下隧道带宽不影响拍摄。\n风险在积压：链中断 1 小时后，需要补传十余张，约 20 分钟才能追平。因此脚本按文件比对，已完成则跳过，链路恢复后从缺失的文件继续。\n验证过程 以下结论来自设备上的实际读取与测试，由 AI 协助逐项完成：\n检查项 方法 结果 隧道能否到达相机所在网段 查看本机路由表，ping 网关 192.168.3.0/24 经 utun9，网关往返 19–35 ms 路由发布了哪些子网 读取 Tailscale prefs 广告两条，仅批准相机所在的一条 相机地址是否固定 读取路由的 DHCP host 表 已配置地址保留 上行连接方式 读取无线配置，查看链路状态 STA 接入现场 Wi-Fi，5 GHz，−35 dBm，866 Mbit/s 各段链路带宽 分段实测 局域网 16.9 MB/s，隧道 0.48–0.53 MB/s 单张传输耗时 52,188,480 字节 ÷ 0.48 MiB/s 约 104 秒 传输工具选择 同一链路对照测试 rsync 两次停滞于 10.5 MB，dd bs=64k 完成 负载下路由是否稳定 连续传输时观察 uptime 23:02 出现一次归零，原因未确定 其中两项问题是通过检查发现的：\n子网路由范围。 路由同时广告了相机网段和上行网段。若家庭网络恰好使用同一网段，批准上行路由会使家庭局域网流量被错误导向远端，打印机与 NAS 将无法访问。 只读挂载未生效。 挂载参数中指定 ro 后，首次挂载时 /proc/mounts 仍显示 rw，需要重新挂载并确认。 回传流程 拍摄期间，路由挂载 ASIAIR 共享（只读）与 NAS 共享，逐文件写入并按大小校验：\n1 2 3 4 5 6 7 8 SRC=/mnt/asiair/Autorun DST=/mnt/nas/media/activities/$NIGHT find \u0026#34;$SRC\u0026#34; -type f | while read -r f; do rel=${f#$SRC/}; d=\u0026#34;$DST/$rel\u0026#34; [ -s \u0026#34;$d\u0026#34; ] \u0026amp;\u0026amp; [ \u0026#34;$(stat -c%s \u0026#34;$f\u0026#34;)\u0026#34; = \u0026#34;$(stat -c%s \u0026#34;$d\u0026#34;)\u0026#34; ] \u0026amp;\u0026amp; continue mkdir -p \u0026#34;$(dirname \u0026#34;$d\u0026#34;)\u0026#34; dd if=\u0026#34;$f\u0026#34; of=\u0026#34;$d\u0026#34; bs=64k 2\u0026gt;/dev/null || logger -t astro_sync \u0026#34;FAIL $rel\u0026#34; done 源端不做任何修改或删除。文件大小一致视为传输完成，重连后从缺失的文件继续。\n配置要点 固定相机地址。 在路由上为相机的 MAC 配置 DHCP 地址保留，避免重连后地址变化导致脚本路径失效。\n仅启用 5 GHz。 路由的 2.4 GHz 热点保持关闭，相机与 iPad 均使用 5 GHz，减少需要排查的频段。\n子网路由只批准相机网段。 路由会同时广告自身网段与上行网段（示例为 192.168.3.0/24 与 192.168.1.0/24），仅批准前者。若家庭网络也使用 192.168.1.0/24，批准上行网段会造成网段冲突。\nCIFS 缓冲区设为 64 KB。 该路由内存为 120 MB，默认 4 MB 的 rsize/wsize 会带来内存压力：\n1 2 mount -t cifs \u0026#34;//$CAM_IP/EMMC Images\u0026#34; /mnt/asiair \\ -o guest,ro,vers=3.0,iocharset=utf8,rsize=65536,wsize=65536,cache=none,actimeo=1 确认只读挂载生效。 挂载后执行：\n1 2 mount -o remount,ro /mnt/asiair grep mnt/asiair /proc/mounts 确认输出以 ro 开头后再开始传输。相机存储是当晚唯一的原始数据副本，写入错误无法恢复。\n已知问题 rsync 在同一链路上两次停滞于约 10.5 MB，其中一次伴随路由器重启；现改用逐文件 dd。 路由器在负载下重启过一次（23:02，uptime 归零），原因未确定，可能是供电或内存压力；拆分传输并调小缓冲后未再复现。 当前供电使用普通适配器，未验证长时间传输下的电流余量。 自动搬运脚本与定时任务尚未部署到路由器，目前为手动触发。 结论 该方案解决了两项现场网络需求：扩展 ASIAIR 的 Wi-Fi 覆盖，并在监看期间保留互联网访问。数据回传提前到拍摄期间完成，收工时 NAS 上已有当晚的原始帧，不再需要搬运设备后重新传输。\n隧道带宽约 0.5 MB/s，低于局域网，但在 300 秒的拍摄节奏下足以并行完成单张传输；主要风险是链路中断造成的积压，而不是稳态带宽。\n","permalink":"https://stargazer1995.github.io/tech/asi-remote-connection/","summary":"\u003cp\u003e野外深空拍摄有两个网络问题需要处理：ASIAIR 自带的 Wi-Fi 覆盖范围有限，iPad 接入该网络后无法访问互联网。另外，希望拍摄期间就把文件同步到家里的 NAS，收工后不必再把设备搬回家、通过家庭 Wi-Fi 传输。\u003c/p\u003e","title":"ASI2600MC Air 现场组网与 NAS 自动回传"},{"content":"三批数据里，六月那两张是主力：一张给构图和颜色，一张给细节。十月这批是后来补的，没通过检查，留在硬盘上当 Hα 素材。\n最后的成片是六月的构图，加上细致图里通过检查的那部分高频。\n三批数据 六月广域是一整片星场，鹰状星云在画面中间占一小块。ASI2600MC Air，280 mm，2.77″/px，NoFilter，9 张 300 秒，视场 4.79° × 3.20°。\n2026-06-06，ASI2600MC Air，2.77″/px，4.79° × 3.20°\n六月细致图是同一个晚上的另一台镜子：ATR2600C，414.7 mm，1.87″/px，HO 双窄带，视场 3.22° × 2.10°。星云填满了画面，代价是窄带把恒星压掉了九成多，噪声也更大。\n同一晚，ATR2600C，1.87″/px，3.22° × 2.10°\n十月那批还是 ASI2600MC Air、280 mm，10 张 300 秒，和六月广域完全同一个像素尺度。\n2026-10-07，10 张 300 秒；ABE 去背景、校色之后的线性 master，再按 STF 拉伸\n三批直接倒进一次叠加，广域的构图会被另外两批的噪声拉走。我的做法是先各自 stack 成 master，再一批一批地比。\n怎么判断一批数据能不能用 新数据进来，我先不看它好不好看，按顺序看三样：能不能对齐、能不能提高分辨率、高频是不是真的。三样都通过，才考虑并进去。\n配准。 用星点做 Hough 匹配，先估尺度、旋转和平移，再用最小二乘精修。十月那批对广域：尺度 1.00007、旋转 +1.042°、平移 (439.2, 4.5) px，717 对星点，RMS 0.368 px。它不是纯平移，还带 1° 旋转，不 warp 直接叠，高频相关度是 0；warp 之后是 0.54。\n分辨率和噪声。 像素尺度决定分辨率的上限，FWHM 决定实际的锐度。十月这批 FWHM 4.99 px，成片 5.16 px，基本一样；单位像素噪声 0.00029，成片 0.00013。尺度和锐度都跟成片一样，它提不了分辨率；噪声更大，并进去会把噪声也带进来。噪声不是平场或堆叠的问题：背景比成片亮 2.5 倍（0.0214 对 0.0087），帧数还少，是光子噪声的极限。\n高频的真假。 找一张同网格、深、低噪、结构确定的 starless 当标尺，在星云区算高频相关度。相关度高，说明高频跟着真结构走；低，说明主要是噪声。六月广域的 starless 就是这张标尺。6 px 尺度上，成片的高频 89% 是真结构，十月这批只有 40%：\n高频尺度 十月 HO 对照：成片 3 px 0.12 0.83 6 px 0.40 0.89 12 px 0.68 0.95 3 px 尺度只剩 0.12，12 px 以下都不可用，所以不并入。\n真正把细节提上去的是六月那张 1.87″/px 的细致图。合成之后，星云高频和它的相关度 0.998，原广域只有 0.695。\n同一套判断也用在 NGC 7380 上：13 个晚上的数据最后只叠了 11 晚，哪两晚不要，看完每晚的 master 再定。\n合成时只换高频 通过检查的数据，只替换 6px 以下的高频。处理在线性域完成，先用 SXT 分离星点和星云。\n1 $T + mask_overlap * ( B_starless - gconv(B_starless, 6) - ( $T - gconv($T, 6) ) ) $T 是基准图的 starless 工作副本，B_starless 是新数据的 starless。6px 以上的低频全部来自基准图，构图、背景和颜色保持不变。合回时只用基准图自己的星点——细致图是窄带，星点对比度只有广域的 8%，不先分离就替换高频，星点会被抹掉一大半。\nmask_overlap 从新数据的数据边界向内收缩，再平滑。配准后的边界外是精确的 0，gconv 的零填充会在边界内侧抬高一圈高频，拉伸后就是一条亮边。\n流水线 阶段 入口 做什么 0 校准帧归档 calib_ingest.py 按相机、温度、滤镜、场次收进 NAS 校准库，生成 calibration_paths.json 1 准备 pipeline_prepare.py 读 FITS 头 / RAW EXIF，按夜晚和指向分组 2 单批叠加 run_all_seestar_nights.sh / run_wbpp_target.sh 每一晚或每一批单独 WBPP 3 质量判断 人看 master + 数值测试 决定这一批进不进最终图，以什么方式进 4 叠加或合成 WBPP / pipeline_union_pair.js + pipeline_finish.js 多晚同目标做总叠加，视场不够做 mosaic，多来源做高频替换 5 校准 pipeline_correct.js SPFC 流量校准，可选 MGC 6 校色 pipeline_spcc.js SPCC 分光光度校色 7 预览 pipeline_preview.js 自动拉伸、导出 JPEG、归档 单次目标叠加：\n1 2 3 4 ./run_wbpp_target.sh \\ \u0026#34;$HOME/nas/media/activities/2026-06-06\u0026#34; \\ m16_wide_20260606 \\ --calib-json \u0026#34;$HOME/nas/media/activities/2026-06-06/calibration_paths.json\u0026#34; 帧数超过 140 时分块：\n1 ./run_wbpp_chunked.sh \u0026lt;src_dir\u0026gt; \u0026lt;work_name\u0026gt; --chunk-size 140 mosaic 只在视场装不下目标时使用。IC 5070 的 Seestar 视场是 1.29° × 0.72°，3553 帧、5 个晚上、6 个指向，按指向聚成 3 组，各自叠加，再拼到一张并集画布上。数据仍然来自同一台相机。\n代码 这套脚本已经脱敏，放在文章下面，MIT 许可。\n完整目录和说明：README · 下载全部（zip）\n主要文件：\ncalib_ingest.py：校准帧归档 pipeline_prepare.py：按夜晚和指向分组 run_all_seestar_nights.sh：逐夜 WBPP run_wbpp_target.sh：单目标 WBPP pipeline_correct.js：SPFC / MGC pipeline_spcc.js：SPCC 校色 pipeline_preview.js：拉伸和预览 所有绝对路径都换成了 $HOME 或环境变量。SEESTAR_WORK_ROOT、SEESTAR_NAS_ACTIVITIES、SEESTAR_TARGET_DIR、MARS_DATA_DIR 按自己的目录设置。\n脚本按原样提供，不保证适配所有相机和所有数据。\n数据放在哪 原始帧按夜归档：activities/\u0026lt;夜\u0026gt;/Light/、Flat/、Dark/、Bias/。校准帧单独集中：\n1 2 3 4 5 calibration/ └── ZWO_ASI2600MC_Air/ ├── Dark/set-10C/\u0026lt;场次\u0026gt;/ ├── Flat/Ha/\u0026lt;场次\u0026gt;/ └── Flat/NoFilter/\u0026lt;场次\u0026gt;/ 温度看 FITS 头里的 SET-TEMP。历史目录里写着 _5_degree 的那批，实际是 -10°C。\n本地只保留正在跑的那一份。有一次清掉 130 GB 中间文件，根分区从 148 GB 可用回到 278 GB。跑完确认 NAS 上有 master 和预览，删除本地目录。原始光帧留在 NAS。\n踩过的坑 FITS 的字节序和符号。 FITS 是大端存储，16 位数据是有符号 int16，物理值要加 BZERO。用 \u0026lt;u2 读，图像看起来平滑，也有 RGGB 图案，绝对电平和通道比例全错。数据偏移按 END 卡向上取整到 2880 的整数倍，每个文件可能不一样。\n读错字节那次，我同时怀疑平场、WBPP 校色和窄带数据。后来改用 PixInsight 的 ImageStatistics（Normalized Real 模式看 median）读数，问题很快定位。\n窄带的 plate solve。 Hα / OIII 星点稀疏，WBPP 会报 Unable to find an initial linear transformation，master 拿不到 PCL:AstrometricSolution。事后单独跑 ImageSolver，用 master 头里的 RA/DEC 和已知像素尺度当种子。\nPixInsight 的实例槽位。 GUI 占槽位 1，无头进程落到槽位 2，星表会“消失”。跑批之前先关掉 GUI。\nFILTER 关键字。 ASIAIR 不一定写 FILTER，WBPP 默认标成 NoFilter。correct 阶段显式传 --filter 和 --filter-nm。\n验收 看产物，不看退出码。\nmaster 有 WCS：hasAstrometricSolution=true SPCC 打印通道缩放，例如 0.0623 / 0.0616 / 0.0622 多来源合成时，成片星云高频与真结构标尺的相关度高于原图 配准后星点最近邻偏移中位接近 0 SPCC 依赖 Gaia DR3/SP，MGC 依赖 MARS DR1。星表路径配置不对，脚本也会跑完，结果不对。\n最后 脚本负责把每一批数据做成可以比较的东西，决定哪一批进最终成品的是人。\nM16 最后的成片，是六月的构图，加上六月细致图里通过检查的那部分高频。十月那 50 分钟留在硬盘上，没有并进去。\n","permalink":"https://stargazer1995.github.io/tech/astro-data-pipeline/","summary":"\u003cp\u003e三批数据里，六月那两张是主力：一张给构图和颜色，一张给细节。十月这批是后来补的，没通过检查，留在硬盘上当 Hα 素材。\u003c/p\u003e\n\u003cp\u003e最后的成片是六月的构图，加上细致图里通过检查的那部分高频。\u003c/p\u003e","title":"M16 拍了三批，十月那批我没并进去"},{"content":"这篇笔记的第一行写于丽江的三联书店：此刻我是丽江最富有的人。\n那时候我在读《黑金：咖啡秘史》。一个觉得自己很富有的下午，一本讲这杯东西怎么把成本推给别人的书。\n作者安东尼·怀尔德在咖啡行业做了十三年采购，后来去写殖民史。这个履历决定了这本书的写法：它不是风味笔记，也不是咖啡百科，而是一条商品链的账本。原书名里的 dark history 比中文的“秘史”更直接，说的不是秘密，是黑暗。\n咖啡的路线，是资本的路线 书从埃塞俄比亚讲起。咖啡原产于东非高地，后来传到也门。也门人很快发现这东西能卖钱，于是把种植和出口都攥在手里。摩卡港（书里译作穆哈港）是那个时代的出口口岸，也是后来“摩卡”这个词的来历。\n也门垄断了很多年。为了不让别人拿到能发芽的豆子，出口前要把豆子处理过。今天看，这只是贸易保护；放到当时，这是一个国家把一种植物变成了独家商品。\n再往后是奥斯曼帝国、威尼斯、伦敦、巴黎。咖啡进入欧洲的路径，和丝绸、香料、糖的路径没有本质区别：都是贸易公司、船队和殖民地。书里有一章专门讲穆哈港的贸易，另一章讲它的衰落。一个港口的兴衰，背后是海上霸权的转移。\n读这部分的时候我一直在想：咖啡的传播路线，其实不是风味地图。它是贸易路线，是殖民路线，是资本找得到的地方。\n咖啡馆的平等，种植园的不平等 书里最让我停下来的，是咖啡馆那一章。\n伦敦的咖啡馆曾经被叫作“一便士大学”：花一便士买一杯咖啡，就能听人讨论政治、科学和生意。劳埃德保险社是从爱德华·劳埃德的咖啡馆里长出来的；皇家学会的早期成员也常在咖啡馆里见面、通信。哈贝马斯后来把这种空间叫作公共领域。\n同一时期，加勒比海的咖啡种植园里是另一套秩序。法属圣多明各、牙买加、爪哇，咖啡是靠奴隶种出来的。欧洲人喝咖啡的时候讨论自由和平等，种咖啡的人没有自由。\n书里没有把这两件事写成一句口号，它只是把它们放在相邻的章节里。但这个并置本身已经够刺人了：启蒙运动的公共空间，和奴隶制的种植园，是同一个帝国的两面。\n便宜是怎么来的 书里还有一个我很喜欢的故事：拿破仑搞大陆封锁，欧洲喝不到英国商船运来的咖啡，法国人就开始用菊苣根代替。后来他被流放到圣赫勒拿岛——那也是一座跟咖啡有关的岛。一个皇帝的最后几年，和一种饮料的替代品，被写在同一本书里。\n咖啡在这里不只是饮料，它是战略物资。谁能运、谁能种、谁能定价，都是政治。\n十九世纪，咖啡的中心转到巴西。巴西有土地、有奴隶、有港口，很快成了世界上最大的咖啡产区。废奴之后，又用移民和铁路把种植园经济接着往前推。\n到二十世纪，咖啡变成大宗商品。价格在期货市场里定，品牌在超市和连锁店里定，种豆的人只能在产地等收购价。书里写到雀巢、星巴克这些公司，也写到世界银行、国际货币基金组织和世贸组织推动的全球化。\n这部分读起来最无力。因为你会发现，一杯咖啡的价格里，种植者的劳动只是很小的一块，而且是最没有议价权的一块。我们平时说的“咖啡贵”，和产地说的“咖啡贱”，可以同时成立。\n公平贸易能解决什么 书里最后一章讲公平贸易。1988 年，荷兰出现了第一批 Max Havelaar 认证咖啡。它没有否定这件事：公平贸易确实能让一部分农场的处境变好，但它改不了整个结构。只要定价权、期货市场和品牌渠道还在原来的位置，认证只能在链条末端做一点修补。\n我同意这个判断，但想补一句：公平贸易至少把“生产者在哪里”写进了商品标签。它让消费者知道自己喝的东西有产地、有具体的人，而不是一个凭空出现在货架上的口味。\n知道不等于改变。但不知道，连改变的入口都没有。\n回到那句话 合上书的时候，丽江那句话还在。\n我不会因为这本书戒掉咖啡。我大概还是会坐在某个书店里，点一杯，觉得自己拥有了一整个下午。但“此刻我是丽江最富有的人”这句话，现在有了另一半：我的富有，是因为这条链把成本推到了我看不见的地方。\n书里没有给解决办法。它做的事情更基本：把账单摊开，让你看见自己坐在哪一头。\n","permalink":"https://stargazer1995.github.io/coffee-ledger/","summary":"\u003cp\u003e这篇笔记的第一行写于丽江的三联书店：此刻我是丽江最富有的人。\u003c/p\u003e\n\u003cp\u003e那时候我在读《黑金：咖啡秘史》。一个觉得自己很富有的下午，一本讲这杯东西怎么把成本推给别人的书。\u003c/p\u003e","title":"一杯咖啡的账"},{"content":"去耶路撒冷的人，第一眼看到的边界通常是墙。高高的混凝土墙，检查站，轻轨从墙边穿过去。但这本书把镜头放低了：橄榄山上的一条巷子，一家咖啡馆，几户人家；然后再把镜头抬起来，越过城门，落到墙下。\n《耶路撒冷以东》是一本民族志。作者赵萱在橄榄山的巴勒斯坦社区做了十五个月的田野调查。他想回答的不是“巴以冲突为什么会发生”，而是一个更小、也更难的问题：边界是怎么被日常生活的动作做出来的。\n书名里的“以东”不是随手起的。在《圣经》的叙事里，以东是圣城东边的地方，是蛮荒、混乱、不信上帝的代名词；圣城和圣城以西才是文明、解放、肩负使命的一边。作者把这个词拿过来，等于先承认了这套眼光，再反过来用它：被当成“蛮荒”的那一边，正是他要认真看的地方。\n边界作为方法 他一开始就不同意一种常见的分析方式：把“国家”和“社会”当成两个清楚的实体，好像边界一画，两边就分开了。在橄榄山，边界是模糊的；但模糊不等于没有。作者说，当界限渗透到某些“真理实践”里的时候，一个原本不存在的东西就会诞生——变化积累到一定程度，性质就变了。整本书跟着这条线走：边界怎么生成，怎么消失，又怎么重新生成。\n更准确地说，他不是把东耶路撒冷当成“在边界上”的城市，而是当成“作为边界”的城市。前者只是地理位置，后者是一种方法：用边界去重新看国家、社会、宗教、家族这些范畴，看它们怎么被边界切开，又怎么反过来生产边界。批判边界研究里有一个说法，叫 bordering——边界化就是秩序化。作者要写的，是这套秩序化的过程。\n这也解释了他为什么对“地缘政治”保持距离。地缘政治把领土、主权、边界当成给定的框架，然后在这个框架里解释冲突；作者想把这个框架本身打开。他引入生命政治，是为了把边界从地图上拿下来，放到人口、身体、日常生活里去看：边界不只划在土地上，也划在谁可以住哪里、谁可以走哪条路、谁可以娶谁、谁可以进哪座清真寺里。\n说实话，绪论我读得很吃力。作者大量引用社会学理论，概念一个接一个，我一度想跳过。真正读进去是从橄榄山的咖啡馆开始的：有人、有椅子、有男人在打牌，理论才落到地上。这本书最好的部分，都是理论退到后面、人走到前面的时候。\n家族：第一层边界 作者先写榄村的日常。这里住得很密，大部分男人白天去耶路撒冷城里上班，做旅游、餐饮、零售；少数留在社区的人开餐馆、修车、看店。男人有男人的咖啡馆，信息、游戏、家族里的议事都在那里发生。女人大多数时间在家里。\n一个外来者能不能被这个社区接受，顺序是：中老年女性、年轻女性、中老年男性、青年男性；最难被接受的是单身青年男性。作者的解释不是“他们保守”，而是：未婚的人不属于任何一个家庭，也就不属于任何一个家族。身份不确定，就不容易被信任。婚姻因此不是两个人的事，是两个家族的事。\n我读到这里才意识到，自己以前把“女人不出门”直接归因于宗教，是一种偷懒。宗教当然在场，但作者看到的是家族：内婚能保住家族的财产和血统，也让男方在家庭里拥有绝对权力；家族的声望、族谱、居住历史，把橄榄山划成一块一块的地盘。家族才是这个社区非宗教性质的社会基础，宗教更像是它说话的语言。\n这个解释让我不太舒服，因为它太完整了。一个东西一旦能解释一切，就容易把人的选择抹掉。作者后面用早婚来补这一层，我才觉得他是在认真处理这个问题。\n作者把 18 岁作为早婚的阈值，然后引了一批学术史：早婚不是阿拉伯穆斯林独有的，很多本地族群都有；现代化程度提高，早婚会减少；但也有人认为，早婚有利于家族内部和家族之间关系的稳固。榄村的观察更细：经济更好的社区，结婚反而更晚；宗教在这里给男性提供保护，宗教禁忌让女性彼此孤立、难以团结，外来的“传播者”也就难以发挥作用；家庭环境在潜移默化地影响女性的想法；近亲结婚能维持家族内的联系，尽管要承担遗传疾病的风险。\n作者的结论是：女性因为选择对象的限制和家族内婚的传统，主动或被动地维持了早婚。阿拉伯社会因此是一个区块分化很明显的民族社会。\n“主动或被动”这几个字，我读了好几遍。它没有把女性写成纯粹的受害者，也没有把她们写成自由的决策者。它说的是：在一个把安全、财产、身份都放在家族里的社会，婚姻是一套生存策略，不只是压迫。可这套策略的代价，确实主要由女性承担。作者没有回避这一点，但也没有用一个道德判断把它盖过去。\n拜节那一节也是同样的写法。开斋节和宰牲节，人们置办衣物、梳洗打扮，第一天礼拜，然后各家拜节。男人出去拜节，女人留在家里招待客人。拜节的顺序看起来是随意的，走到哪家算哪家；但作者跟着走了几天，发现它其实沿着父系亲属关系展开。因为内婚普遍，亲属称谓是乱的——你管我叫叔，我管你叫哥——但“父系”这条线一直在。\n这一段我很喜欢，因为它把一个看起来没有秩序的动作拆开了。作者没有说“他们很传统”，而是说：秩序不在先后里，在关系里。谁先去谁家不重要，重要的是走的是父系这条线。内婚让称谓混乱，但也让代际遗忘变得困难——一个人从小就在一张过密的亲属网里长大，很难不知道自己是谁家的。\n面纱那一节，也没有停在“伊斯兰要求女性遮体”这种解释上。历史上阿拉伯女性有过不戴面纱的时期。20 世纪 60 年代，第三次中东战争之后，阿拉伯民族主义和社会主义的理想受挫，伊斯兰复兴运动起来；80 年代，哈马斯把民族主义装进伊斯兰的语言里。面纱在这个背景下重新变成政治符号：当人们在现实里没办法获得成功，就回到宗教里；政治和宗教搅在一起。\n但今天的面纱又变了：颜色多了，款式开始显身材，和传统教义并不完全一致。作者说，这是审美和现代性的变化；男性这边反而没有同步变化，因为在巴勒斯坦，家族已经给了男人足够强的身份，不需要靠穿着去强化；在欧洲的阿拉伯人没有家族，才更需要兜帽、胡须这些标记。\n我对作者解释男性动机的这一段有一点保留：它太功能主义了，好像人只有在缺少家族的时候才需要符号。但他说对了一件更重要的事：传统不是一块不动的石头。它会被政治重新激活，也会被市场重新设计。面纱既可以是复兴运动的旗帜，也可以是一件显身材的时装，这两件事可以在同一个人身上同时成立。\n书的后半段把家族叫作“装置”。作者先讲了这个概念的学术史，我又卡住了；好在他很快给了一个朴素的定义：装置是权力体系的一环，用法律这种话语性的东西，或者社会共识这种非话语性的东西，来治理社会。家族就是这样一个东西：它不只是一个亲属网络，也在替国家维持一块地方的秩序。\n社区里的纠纷，先由族长调解。族长要有资历、有威信、有好口碑，像中国乡村里的村长。以色列政府在一定程度上承认这种以家族为单位的领土划分，也承认家族的自治；有时还扶植族长，通过他们来管理巴勒斯坦社区。只有当冲突严重到违背教义、又为现代社会不容、民愤难以平息时，家族才会把国家司法请进来；家族压不住的时候，警察和军队才会介入。\n所以这里的治理不是“国家对社会”，而是三层：家族内部协调、家族之间协商、以色列通过族长进行间接治理。作者说，这种结构不是自然长出来的，也不是线性的，它是和以色列的治理实践一起长出来的。\n“装置”这个词有力量，但也有风险：它把家族说成一台治理机器，容易忽略人的犹豫——族长也会老，也会失去威信，年轻人也会不认这套。不过作者在讲历史经纬的时候，至少承认了结构是历史地生成的，不是“阿拉伯人天生如此”。这一点很重要，它把本质主义的门关上了。\n圣地：民族国家之外 第二章从隔离墙和轻轨写起。作者想说明：不管耶路撒冷的统治者怎么换，宗教都是绕不开的议题。他先批评传统的耶路撒冷研究：太关注国家、宗教这些大主体之间的冲突，忽略了主体之间在日常里的弹性和丰富性。只有进入宗教实践和个人生命史，才能看到这座城市真正的复杂。\n他选基督教作“第三只眼”：在犹太教和伊斯兰教的双边叙事之外，基督教既跨民族国家，又深度参与本地社会，能看到民族国家叙事看不到的东西。他用了三个人物，从个体到群体再到世界社会，拉出三种尺度。\n第一个是西格莉德，一个受德国修女感召、从挪威来到橄榄山的女人。她不给当地人布道，而是给附近的孩子缝衣服、发食物，给女孩子做心理辅导，因此成了附近阿拉伯家族的贵客。作者说，从个体的角度看，她的行为是宗教性的；从实践上看，又是超越宗教的——她在把“社会性”还给一个饱经战乱的地方。\n第二个是耶路撒冷的上帝教会。它受德国教会资助，实习生和管理者由德国指派，但牧师以阿拉伯人和说阿拉伯语的亚美尼亚人为主，唱诗和布道用阿拉伯语。它给当地孩子办学校，只收少量学费，周末和假期组织活动，促进教派之间的融合，甚至与伊斯兰教和解。作者引福柯说，现代国家治理的核心是对人口的培育；教会办教育，其实暗合了民族国家的世界体系。\n第三个是万国祷告院。它是耶路撒冷最大的基督教团体，认为阿拉伯人和以色列人都应该被拯救；工作人员来自二十多个国家；一年一度的祷告特会，把不同文化、民族、国家的教徒聚在一起，尝试推动当下的难题。作者把它和同一天山下的冲突、山上的儿童生日会放在一起：一边是对立，一边是下一代在一起玩。\n这一章后半段转到遗产。作者问：遗产的存续一定要“领土化”吗？共同体的存续一定要以民族国家为前提吗？在耶路撒冷，宗教遗产保护上的冲突，很多来自民族国家竞争造成的实际缺位，但又很难靠重新划一次国界来解决。他把民族国家还原成一种描述世界的方式、一个治理主体、一种定义圣地的力量：它可能外在、虚幻、缺位，但不会消失。\n他还提出“安全阀”：社会需要给敌意一个出口，让冲突在可控范围内释放，行动者就不必真的去解决那个令人不满的现状。国家暂时让渡公共空间，用这种制度设计维持秩序。读到这里我想到的是：耶路撒冷的日常平静，可能不是冲突消失了，而是冲突被安排进了某些可以承受的容器里。\n再往后是“文明与国家”。作者把文明研究的实体论和虚体论都过了一遍：实体论把文明当成有边界的单元，容易滑向文明冲突论；虚体论强调流动和交融，却回避了民族国家仍然是现实行动的基本单位。他借莫斯说，文明是建立在社会整合体之上的超社会体系。这部分我读得最吃力，但它支撑了全书的一个判断：民族国家框架应该是被思考的问题，而不是思考的起点。\n作者的落点不是选边，而是说：文明不应被民族国家收编，也不该被当成没有边界的虚体；它最终指向社会生活本身。这句话听起来抽象，但放回耶路撒冷就具体了：圣地的意义不只属于哪个国家，它也在信徒的日常实践里活着。\n写上帝教会那一节，作者说宗教事业暗合民族国家的世界体系。我读到这里有一点不同意见：也许方向反了。现代国家治理人口的那套办法，本来就有很深的宗教教育影子。教会不是“暗合”国家，国家是在借用教会早就做过的事。这不是要反驳作者，只是提醒自己：民族国家不是唯一的起点，宗教有时候比国家更早地在做治理。\n另一个让我犹豫的地方是西格莉德。作者说她“超越宗教”，可她做的事情——缝衣服、发食物、心理辅导——本身就是一种宗教实践的方式。也许“超越”的不是宗教，而是教派；她把宗教从布道台上拿下来，放进了日常生活里。\n墙：分割与缝合 第三章从墙写起，但作者很快把“墙”拆开了。墙不是一条线，而是一套由点、线、面组成的体制：定居点是点，检查站是点，巴勒斯坦人的家族社区也是点；道路、桥梁、隧道、高墙把它们连起来，或者隔开。墙的形状之所以崎岖破碎，是因为它要尽可能把犹太定居点圈进来，又把巴勒斯坦社区排出去。\n作者为什么一定要用“点—线—面”？因为只把墙当成一条线，就会以为边界是连续的、可以用地图画出来的。可他在田野里看到的边界是碎的：定居点是点，检查站是点，家族社区也是点；路、桥、隧道是线；墙和检查站构成的管控面，把人的一天切成一段一段。边界不是一条线，是一套让人不断绕行的装置。\n书里有个开家具店的巴勒斯坦人，叫亚金。墙修起来以后，热闹的街道冷清了，原来走几分钟的路变成半小时车程。作者说，这不只是生意变差，而是亚金的“社会自然性”被改变了：他开始用类似墙的方式，追求个人的安全和自由。我读到这里才明白，边界不只切路，也切一个人对自己的想象。\n土地交易那一节也很关键。巴以的领土竞争不总是军队和炮火，也可以是市场交易和法律诉讼。以色列用市政手段让土地长成国家的一部分；巴勒斯坦家族的土地逻辑是丰富的、整全的，和以色列司法逻辑下的可计算、可分割发生冲突。于是问题从“这块地归谁”变成“何以为敌、与谁为敌”。作者的回答是：土地政治根本上是人的政治；敌人不是主权一次决断出来的，而是在日常里一点点展演出来的。\n墙边还长出了贸易市镇：以色列需要劳动，巴勒斯坦人需要工作，边界就从隔离区变成了互动空间。书里还写了一位 89 岁的以色列女医生，在巴勒斯坦人中间靠日常行动赢得尊重。这些细节让“敌我”变得不那么整齐：边界在分开人的同时，也在制造依赖。\n作者用“缝合”这个词，不是说墙在修复关系，而是说它在切开的同时，又把两边缝进同一套经济和管理里：以色列需要巴勒斯坦的劳动力，巴勒斯坦人需要以色列的工作和市场。墙既是分隔，也是缝合，这两个动作同时发生。\n第三章最后一节落到身份证和检查点。作者把它们叫作生命政治的第二期：不只是控制人口，而是培育出以色列所期待的巴勒斯坦人。“差异化包含”这个词很关键：不是简单地排斥，而是把巴勒斯坦人分门别类地包进来，给不同的身份证、不同的通行权、不同的生活可能。人为了活得下去，会发展出自我技术，慢慢把边界装进自己心里。\n这一章推翻了我读前两章时的一个舒服结论。我本来想说“边界不在墙上，而在家族里”；但墙分明在，而且它在生产秩序、生产依赖、生产人的自我理解。更准确的说法是：边界不止在墙上。\n边界不止在墙上 读到最后，我回头看这本书的结构：家族、宗教、墙。三层不是并列的，是一层套一层。家族是橄榄山内部的边界，宗教是民族国家之外的边界，墙是把两者都包进去、又切开的边界。作者没有把哪一层说成“真正的”原因，他说的是一套互相生成的关系。\n结语落到“生命、人口与自我”。作者说，边界有生命，会流动、收缩、扩张；它不只在外面的地上，也在人的身体和自我理解里。一个人为了活得下去，会学会哪些路能走、哪些证件要带、哪种身份该露出来、哪种身份该藏起来。边界就这样从外面走进来，变成人的一部分。\n书里有一句话，大意是：土地的政治根本上是人的政治。我读完的理解是：边界不是先画好一条线，再让生活去适应它；边界是在生活里被反复做出来的，做一次，秩序就成立一次。墙会被拍进照片，家族的边界不会；但家族的边界、身份证的边界、检查站的边界，每天都在被重复。\n这本书没有给我一个关于巴以冲突的答案。它给的是一个更小的尺度：一家人怎么结婚，一个节怎么拜，一块面纱怎么戴，一场纠纷找谁评理，一个修女怎么和邻居相处，一个人怎么绕过检查点去上班。正是这些小事，把“我们”和“他们”分开了；也正是这些小事，让边界在分开人的同时，又制造出依赖、协商和共处。\n读完我再想“耶路撒冷以东”这几个字，想到的不只是地理。东边是橄榄山，是巴勒斯坦人的社区，是墙下的检查站，是那些没有出现在新闻镜头里的日常。边界不止在墙上，边界在他们每天怎么做。\n下一本书预告：\n大马士革事件 ","permalink":"https://stargazer1995.github.io/east-of-jerusalem/","summary":"\u003cp\u003e去耶路撒冷的人，第一眼看到的边界通常是墙。高高的混凝土墙，检查站，轻轨从墙边穿过去。但这本书把镜头放低了：橄榄山上的一条巷子，一家咖啡馆，几户人家；然后再把镜头抬起来，越过城门，落到墙下。\u003c/p\u003e","title":"边界不止在墙上"},{"content":"9 月中旬，我们把 Seestar 的数据迁到无头 WBPP 流水线上跑。NGC 1491 是那批里帧数最多的一个目标：440 帧、10 秒一张，按常规流程叠一次就行。\n结果叠出来的 master 不对。\n现象：master 不像用了 440 帧 成片的问题不是“有点噪”，而是和输入规模对不上：星点稀疏、背景脏，看起来像只用了不到一半的数据。但 WBPP 的退出码是 0，日志最后也没有报错。\n第一反应是参数问题。但在动参数之前，先回去看 WBPP 日志里的配准统计——这一步改变了后面的方向。\n取证：先看配准数，而不是看参数 日志里能读到每一帧的注册结果。把“成功注册”的数量和输入帧数一除，结果是 42.3%——440 帧里只有不到一半真正进了叠加，其余被跳过，而且没有在流程层面报错。\n这就解释了成片：不是参数没调好，是数据根本没进去。\n追因：为什么注册会大面积失败 下一步是看这些帧为什么没注册上。\nWBPP 在输入帧数达到 150 时，会自动改用 FastIntegration 这条快速配准路径。它的设计目标是大批量数据的处理速度，但在部分数据集上匹配会失败，失败的帧被直接跳过，流程继续。\nNGC 1491 这批正好超过 150 帧，于是走了这条路。几十帧的小批量不会触发这条路径，所以这个行为一直没有暴露。\n这里有一个容易误判的地方：日志里没有“错误”，只有“注册数少了”。如果只看退出码，或者只看 master 有没有生成，就会以为成功了。\n验证：两版 master 的直接对比 NAS 上还留着两版 master：..._fastIntegration_autocrop.xisf 和分块处理后的 ..._RGB_autocrop.xisf。在同一份 autocrop 输出上统计每通道的 MAD（中位绝对偏差，乘 1.4826 作为噪声估计）：\n版本 R G B FastIntegration 2.75e-5 2.41e-5 2.59e-5 分块 + 标准配准 2.11e-5 1.81e-5 1.91e-5 同一目标、同一裁切，分块版每通道噪声低 23% 到 26%。这和“更多帧进入叠加”的预期一致，也把问题从“感觉不好看”变成了可复核的数字。\n处理：按时间分块，每块走标准配准 修法的核心是别让单次 WBPP 的输入超过 150 帧：\n把帧按拍摄时间排序，按不超过 140 帧切成若干块； 每块单独跑一次 WBPP，走标准 StarAlignment 路径； 收集各块 master，用 strip_cfa_xisf.py 抹掉 CFA 元数据——这些已经是叠加结果，不能再让下游按 Bayer 阵列处理； 再跑一次 WBPP，把各块 master 合成最终 master。 140 而不是 150，是留余量：分块边界、参考帧选择和重试都可能让实际输入数浮动。\n这套流程固化成了 run_wbpp_chunked.sh，参数是 --chunk-size 140。脚本在跑之前把水冷拉到全速，结束后按快照恢复——分块把一次叠加拆成多次，总时长变长，散热不能按单次叠加估。\n结果 两次实测：\n目标 帧数 分块前配准率 分块后 NGC 1491 440 42.3% 99.3% IC 443 406 73.4% 98.8%（401/406） IC 443 那次在流水线文档里有完整记录：401/406 进入叠加，后面接 SPFC、MGC、SPCC，全流程约 16 分钟。\n复盘 退出码不代表成功。 WBPP 丢帧不报错，流程照样结束。验收要看日志里的注册数，或者看 master 的实际噪声水平。\n分块不是越多越好。 每块都要单独做参考帧选择、局部归一化和积分，块太多会让边界处的背景和噪声不一致。140 是在“不触发 FastIntegration”和“块数尽量少”之间取的。\n合并前要处理元数据。 各块 master 如果还带着 CFA 标记，第二次 WBPP 会按 Bayer 阵列处理已经 debayer 过的数据，颜色直接错。\n散热按最长连续时间准备。 分块后总时长变长，水冷和电源策略要提前拉满。\n现在流水线里有一条硬规则：帧数超过 140 一律分块，不看单次结果好不好。WBPP 是黑盒，它会在你不知情的时候换算法；能做的不是调参数，是把输入控制在它不会换算法的范围内。\n","permalink":"https://stargazer1995.github.io/tech/wbpp-chunking/","summary":"\u003cp\u003e9 月中旬，我们把 Seestar 的数据迁到无头 WBPP 流水线上跑。NGC 1491 是那批里帧数最多的一个目标：440 帧、10 秒一张，按常规流程叠一次就行。\u003c/p\u003e\n\u003cp\u003e结果叠出来的 master 不对。\u003c/p\u003e","title":"WBPP 超过 150 帧会自己换算法：一次丢帧排查"},{"content":"这套东西不是一次设计出来的。下面按时间顺序写，从换车型就失效，到能跑、能部署，再到开始怀疑指标。\n2026 年 8 月：单一车型能跑，换一辆就不行 最初的端到端模型只在一辆车上验证过。相机装在哪、朝哪、FOV 多大，都是固定的，模型把这些几何关系隐式记了进去。\n问题在于我们手上的车不止一种：相机数量不同，安装位置不同，内外参也不同。换一辆车，投影关系变了，模型就掉。每换一次布局就重采数据、重训一遍，这条路走不远。\n8 月底先做了一轮多录制审计。原来的参考模型只在自己的训练录制上有效，换到别的录制，重建和端到端指标都崩。这次审计改掉了评估口径：以后所有对比必须跨录制、同口径。这件事看起来是评估问题，实际上决定了后面所有结论可不可信。\n2026 年 9 月上旬：先把输入统一 9 月初开始评估 UniDrive。它的思路是在原始图像和感知模型之间插一层虚拟相机：定义一组虚拟相机，用 CMA-ES 优化它们的位置、朝向和 FOV，把任意配置的原始图像重投影到这组统一视图上。\n我们按这个思路做了三轮：\n9 月 3 日，多视角统一的可行性； 9 月 9 日，七相机候选环视的可行性； 9 月 11 日，真实图像管线跑通； 9 月 14 日，正式固化成候选几何工具。 落地路径是：七路严格同步的原生图像 → 车身为中心的等距柱面全景 → 重采样出 6 个虚拟相机，拼成 3×2 的 grid。\n这一步比看上去难。9 月 14 日的侧向围栏诊断里，在约 10 米远、1 米高的合成围栏上，四个侧向过渡接缝的上沿仰角差 0.504°、下沿 0.358°，换算到虚拟视图上大约是 4.8 px 和 3.4 px 的上下错位。原因是所有相机被映射到同一个 40 米共同曲面，而侧向相邻相机的基线有 1.8 到 3.3 米；前方那对只有 0.058 米，误差就小得多。\n我们试过曝光归一化和车身遮挡，它们能改善亮度和遮挡，但修不了这类几何错位。真圆柱也评估过，没有直接升级成默认方案。最后这批数据明确标成 candidate_geometry_only：它是候选几何拼接，不是生产标定。对我们来说，这一层的价值是把输入固定下来，而不是宣称拼接已经完美。\n2026 年 9 月 19 日：连续 flow 头第一次跑通 输入统一之后，才开始做世界模型。第一版照 SV-WAM 的因式分解来：\n1 p(A | Ω) · p(Z_fut | Ω, A) 动作和未来视频 latent 在同一个 DiT 里联合去噪，用非对称 mask 保证动作 token 看不到未来视频 token。这条约束是硬的：部署时要删掉整个视频分支，动作路径一旦依赖它，就删不掉。\n第一次跑通只用了连续 flow 头。跑通之后遇到两个问题。\n第一个是 warm start。 加动作头之后，序列多出 state 和 10 个动作 token，未来视频的行号整体后移。直接联合训练，视频分支掉得厉害：从零训只能到 24.62 dB，而从已经训好的视频臂 warm start 是 28.41 dB。动作 token 对视频分支是有信息量的条件，不是噪声。\n第二个是归一化。 动作目标一开始用固定范围 [-1,1]，ADE 停在 0.192 m。换成零均值单位方差之后，ADE 降到 0.099 m、FDE 降到 0.158 m，第一次超过 causal-CV 基线（0.160 / 0.228）。结构没动，只是目标尺度变了。时间调度单独几乎无效，两者叠加才最好。\n这段的代价是视频分支 PSNR 从 28.41 掉到 27.00，仍高于纯视频臂的 26.37。\n2026 年 9 月 20 日：换成六相机 grid，删掉一条更简单的路 9 月 20 日把输入从单路换成六相机 3×2 grid，视觉后端换成冻结的 Wan2.1 VAE：8 倍下采样、16 通道 latent。\n同一时期，另一台机器上实现过第二条出轨迹的路：在 pooled DiT 特征上接一个 MLP，直接回归 dx/dy/yaw，用 SmoothL1 做辅助损失。它看起来更简单，也被删了。原因是部署时视频分支整体删除，任何读视频特征的轨迹头都没有输入——这正好违反 p(A|Ω) 的出发点。\n删掉之后留下一条验收准则：在非对称 mask 下，不带 V_tgt 的 action-only 采样，必须和联合采样逐位一致。这条后来变成了回归测试，实测最大差异 0.00e+00。\n2026 年 9 月 22 日：promote 成主线，以及一次改名事故 9 月 22 日把这条线从“视频世界模型 + ego 轨迹头”提升为主线，改名为 wam / train_wam。提升的实质不是改名，而是部署口径变了：一次前向同时给出未来视频 latent 和 1 秒轨迹，部署时删掉视频分支，只留动作路径。\n同一天加了离散 token 动作头：把 (dx, dy) 量化成词表 token 自回归预测，dψ 仍走连续回归。两种头由 action_vocab_size 切换，共用同一个视频分支。\n改名的重构出过一次事故：CVAE 路径和 warm start 一起丢了，continuous 后端会直接以 --cvae is required 退出。修回来之后，warm start 的位置编码平移抽成了函数，用测试钉住平移范围、默认 delta 和不合法输入。\n2026 年 9 月底到 10 月 8 日：离散 token、自行车模型、2 秒 horizon 这一段的目标是给后面的 RL 铺路：把动作改成离散 token 自回归，把 horizon 从 1 秒推到 2 秒。\n三个改动：\n去掉 teacher forcing。 训练时用模型自己的 argmax 作为下一步输入，训练分布和推理分布一致，避免 exposure bias； curriculum。 先只监督前 2 个 token（1 秒），再逐步加到 4 个 token（2 秒）； 用自行车模型代替独立的 dyaw 回归。 从 token 位移直接推 heading 变化，少一个 head。 同时把数据扩到三个 session 的六相机 grid，完成了 2 秒 horizon 的 overfit 验证。这一步证明链路能走通，但没有证明泛化。\n2026 年 10 月 14 日：盘一次现状 到 10 月中旬，状态需要说清楚：当前主线是 WAM 的小数据拟合，不是 episode-isolated 的 held-out。\n连续 flow 头和离散 token 头已经合并进同一个模型，由 action_vocab_size 选择； 六相机构建代码在，但本地参考集还没换成六相机； 六相机编目被卡住：可计数的 session 只有 2 个，计划要求 train / val / test 各至少 3 个； 数据里绝大多数是直线，转弯样本非常少，聚合 ADE 被纵向项主导。 还有一个没解决的现象：高速窗口的最大误差始终在 16 米左右，不随采样步数下降。至少有一个窗口，模型预测“几乎不动”，真值走了 16 米。\n2026 年 10 月 18 日：低 ADE 不等于理解动作 走到这里，有一个问题必须问：ADE 降低了，PSNR 提升了，模型真的理解到物理世界的变化了吗？\n训练目标是 p(Z_fut | Ω, A)，这是一个观测条件分布；真正想要的是动作的因果效应 p(Z | do(A), Ω)。存在未观测的驾驶意图或场景上下文时，两者可以完全不同。\n现有数据能支持三种解释：\nH1（因果）：模型学到了动作的后果；\nH2（场景先验）：模型学到的是“看到这个场景该怎么开”，动作只是场景的代理；\nH3（辅助正则）：视频分支只是有用的表征正则，真正出轨迹的是动作头看到的 Ω 和 S。\n0.099 m 的 ADE、27 dB 的 PSNR 无法区分这三者。而且这个 ADE 是在同一批拟合窗口上得到的，不是 held-out。\n视觉基准也提示过同一件事：Physics-IQ、VideoPhy、IntPhys 2 都显示，画面保真度和物理正确性可以脱钩。ADE 和 PSNR 衡量的是“像不像”，不是“懂不懂”。\n现在的样子 工程上，链路已经打通：不同车型的输入先统一到六虚拟相机，世界模型输出 1 秒轨迹，部署删掉视频分支。延迟在 bs=1、bf16 下：动作分支 2 步 7.1 ms、20 步 64.1 ms，联合 20 步 123.2 ms；部署端到端 14.8 到 71.8 ms，同等步数下只走动作路径比联合快 1.8 倍。\n但少步采样没成功：2 步误差在米级，2 到 20 步单调改善，所以部署固定 20 步。这条没有绕过去，只是接受了。\n回头看，这半年分成两段：先把输入统一、把模型压成能部署的动作路径；然后承认输入统一和指标好看，都不等于理解了动作。\n前者是工程，后者是因果。两者之间还差一次干预实验。\n","permalink":"https://stargazer1995.github.io/tech/wam-story/","summary":"\u003cp\u003e这套东西不是一次设计出来的。下面按时间顺序写，从换车型就失效，到能跑、能部署，再到开始怀疑指标。\u003c/p\u003e\n\u003ch2 id=\"2026-年-8-月单一车型能跑换一辆就不行\"\u003e2026 年 8 月：单一车型能跑，换一辆就不行\u003c/h2\u003e\n\u003cp\u003e最初的端到端模型只在一辆车上验证过。相机装在哪、朝哪、FOV 多大，都是固定的，模型把这些几何关系隐式记了进去。\u003c/p\u003e","title":"从 E2E 到 WAM：先把输入统一，再谈世界模型"},{"content":"决定今晚出不出去，我一般先看云。云量可以，再翻光污染地图；找到一块够黑的地方，还要看路能不能开到山脚；最后打开星图，确认想拍的东西今晚能升多高，这台镜子装不装得下。\n这几步我做了很多年，每一步都有工具。问题是这些工具互相不知道对方存在：光污染地图不知道路通不通，星图不知道我带的什么镜子，天气也不知道我要去的地方在哪儿。\n这套工具链没有一开始就想清楚要做成什么样。它是按顺序回答上面那些问题的，第一个是：这个地方够不够黑。\n先有一张光污染地图 2025 年 3 月底，我先写的是一个很小的计算服务：给目标、时间和坐标，算高度、方位和升落。四月初把光污染分析加了进来，读 VIIRS 的 GeoTIFF，把辐射度换算成波特尔等级。\n到这一步，它能回答两个问题：这个东西今晚升多高，这个地方够不够黑。但都是一个点一个点地查。真正想要的是另一件事：给一个范围，告诉我里面哪些地方值得去。这个想法后来变成了另一个项目。\n黑的地方，不一定去得了 2025 年 8 月底，我加了山峰搜索。原因很直接：光污染地图上最黑的那块，往往在山里，或者在离公路很远的地方。我需要知道那里有没有一个能停车、能架三脚架的位置。\n九月初又加了天文台和观景平台，项目也从 MountainPeakFinder 改名成 StarGazingPlaceFinder。名字变了，问题也变了：从“这座山有多高”变成“这个地方能不能去”。\n路网可达性是这时候进来的。最早的判断很粗：离公路 5 公里以内就算可达。后来改成 200 米。不是因为数据变准了，是因为我背着赤道仪、三脚架和电源，5 公里和 200 米不是一回事。\n海拔也不是越高越好。光污染低、视野开阔、车能到，这三件事经常不在同一个点上。地点评分就是在这时候成形的：光污染等级、海拔、道路距离，各自算分，再合成一个数。\n那时候地点这边的光污染还是 KML 图像瓦片，颜色是渲染过的，只能根据颜色反推等级。MCP 那边一开始就用 GeoTIFF，但那是单点查询；区域分析这条线为了省事，用的是瓦片。\n到这里，工具能回答“哪里值得去”了。但它还是一个点一个点地查。\n五十个点，最多等了八分钟 2026 年 6 月，我想让它一次分析一整片区域。第一次跑 50 个候选点，用了 200 到 500 秒。\n我原以为是数据量大：光污染要读栅格，海拔要查库，路网要算连通性。拆开看才发现，最贵的一步是每个点都重新去 Overpass 下载一次路网。同一片区域，50 个点，下载了 50 次同一张图。单点用 OSMnx 走一遍要 143 秒，区域大一点还会超时。\n那次还遇到一个更没道理的错误：Overpass 主站返回 406 Not Acceptable。请求本身没错，是缺了 User-Agent 和 Accept: application/json。加上之后才正常。\n真正的改法是换数据源。我把 OSM 的路网导进本地 PostGIS，直接从 planet_osm_line 查。单点连通性变成一次 kNN 查询，50 毫秒；一片 95 平方公里的区域建一次 NetworkX 图，大概 15 秒，区域内所有点共用这张图。\n再加上海拔批量查询、光污染栅格批量读、四个线程并行，50 个点从 200–500 秒降到 3–5 秒。\n这次之后我改了一个习惯：先量每一步的耗时，再决定优化哪里。那次真正慢的不是计算，是重复下载。\n换了更准的数据，答案反而更错 2026 年 6 月，我把地点这条线的光污染从 KML 换成了 VIIRS DNB 2025 的 GeoTIFF。KML 是上过色的图，GeoTIFF 里是原始辐射度，可以直接算，看起来是一次干净的升级。\n换完之后，工具告诉我：崇明东滩，波特尔 1–2 级。\n那个地方离上海城区不到一小时车程。我知道不对。\n查下来，问题不在数据精度，在模型少了一项。VIIRS 测的是向上的灯光辐射，而城市附近的天光有很大一部分来自远处灯光在大气里的散射。只算头顶的辐射度，会把城市边缘算得比实际暗很多。\n补的办法是对辐射度做高斯模糊，模拟天光扩散，sigma 按公里配置；再把扩散部分按权重加回去。同一个点从 1–2 级回到 4–5 级，和肉眼看到的一致。\n这件事之后，我不再默认“换了更好的数据”就等于“结论更对”。数据越精确，模型缺的那一项越容易被掩盖。\n地图供应商会改规则 地点这一层还有一件事：把地名变成坐标。\nOSM 的路网我导进本地 PostGIS 之后够用了，真正撑不住的是中文地名。很多乡镇、村、山口在 Nominatim 里查不到，或者查到同名的地方。我接了高德的地理编码接口，中文地名的解析结果稳定得多。\n后来高德调整了政策，个人开发者不再能免费使用这个服务。\n代码里的高德从默认链路退成了显式选项：必须在 GEOCODER_PROVIDERS 里写上 amap，并且配了 AMAP_KEY，才会走付费接口。默认链路改成离线的中国行政区划表 → Photon → Nominatim。行政区划表是三千二百多行，覆盖省、市、区县，坐标是 GCJ-02。\n这不是换一个 API 的事。地址解析是天气查询的入口：地名解析不出来，后面查天气、排计划全都做不了。所以这条链路从一开始就写成了级联，一个源不通，后面还有；高德只是其中一个可以付费打开的选项。\n天气决定这一晚有没有意义 地点再黑，云一盖就什么都没有。\n天气在我的流程里不是参考信息，是出门的前提。地点可以下个月再去，天气错过就是错过。\n最早的版本只接一家天气源。后来发现两个问题：云量预报本身就是概率，不同模式给出的结果经常差得很远；任何一家也都会超时、限流或者临时抽风。\n现在服务里同时接了三家：Open-Meteo（免 key）、和风天气（需要 host 和 key）、wttr。provider=all 时三家并行查询，每家的原始结果都保留在返回里；摘要按 Open-Meteo 优先，缺的字段用其他源补；哪家失败就记进 failed_providers，不让整次查询失败。同时，ai 调用时候也会得到这个结果，让外部知道查询是不是失败了；\n我没有把三家平均。平均会把分歧抹掉，而分歧恰恰是我要看的：如果两家说晴、一家说八成云，这一晚就是有赌的成分。三家都说晴，也不代表一定晴，但至少我知道这个判断有多少支撑。\n多源的作用不是把预报变准，是让我知道这条预报有多可信。\n把地点、天气和路放在一张表里 有了地点和天气，还要回答：今晚这几个候选点，去哪个。\n2026 年 6 月底，我把这件事做成了一个组合工具。它先搜候选地点，再对每个地点并发查天气和夜间目标，最后排序。\n分数是两个部分加权：地点分占 0.65，天气分占 0.35。\n地点分来自光污染等级、海拔和路网可达性。天气分从云量（100 减云量）、能见度（每公里 1.5 分，最多 20 分）、风速（超过 20 km/h 开始扣）、降水概率和月相（照明超过 70% 开始扣）算出来。\n这个比例是我拍的：地点是我愿意多开一小时车去换的东西，天气是那一晚的运气。比例可以改，但要改在一个地方，不能散在十个函数里。\n结果不只给一个数字，还给理由：波特尔几级、当前云量多少、能见度多少、最佳窗口是几点到几点、月面照明多少。分数可以争，理由必须能看懂。看不懂的分数，我不会拿它做决定。\n选定设备之后，今晚拍什么 地点定了，下一个问题是目标。\n望远镜模式先做光学匹配：用焦距和传感器尺寸算视场，用目标角尺寸判断装不装得下；表面亮度决定要不要更长曝光；滤镜类型决定这个目标是宽带还是窄带更合适；再加上当晚的高度和月光。\n评分里视场占 40，表面亮度 30，滤镜 20，高度 10。装不下的目标会标出来，可以走马赛克。\n马赛克按重叠率算网格，重叠率 5% 到 40% 可调，输出行列数、总块数和每块中心的 RA/Dec。大目标不再只能“拍不全”或者“换短焦”。\n然后是时间。把每个候选目标的高度曲线插值到分钟，每分钟选当前分数最高的那个，再把连续相同的选择合并成时段。月亮没落就等，落山后再加 10 分钟缓冲；整夜都有月亮，就提示改窄带；暗时空档超过一小时，单独给一条警告。\n前端用 Aladin Lite 把这些画出来：目标位置、视场框、马赛克网格都能看到；点一个时段，天图跳到对应的目标。\n这套匹配一开始很慢。目录里一万多个目标，每个都算高度曲线，一次要十几秒。后来把 O(n²) 的名字查找换成字典，3900 万次比较降到 3600 次；把高度曲线推迟到截断之后算；再用 numpy 批量做坐标变换。13.73 秒降到 141 毫秒，结果不变。\n两套入口，一份计算 同样的能力，给人用是网页，给 AI 用是 MCP。\n网页是 FastAPI + Leaflet + Aladin Lite；MCP 把能力包成十几件工具。两套入口带来的第一个问题是：同一套天文计算写了两遍。改一处，另一处不一定跟着改。\n2026 年 7 月，我把纯计算的部分拆成 stargazing-core，发到 PyPI，两边锁版本引用。它不连数据库、不发网络请求，只做坐标、时间、光学、目标匹配、拍摄计划和马赛克。\n回头看，这套东西自然分成了三层：\n1 2 3 4 5 6 AI 客户端 ──MCP :3001──┐ ├──▶ stargazing-core（纯计算） 浏览器 ──HTTP─▶ FastAPI :5001 ─┘ │ └──▶ stargazing-place-finder PostGIS · VIIRS · OSM 路网 层 管什么 不管什么 stargazing-core 天体位置、升落、月相、光学、目标匹配、拍摄计划、马赛克 数据库、网络请求、调用方是谁 stargazing-place-finder 光污染、海拔、路网、地点评分 网页还是 AI 在调用 mcp-stargazing 天气、地名解析、组合规划、MCP 协议 重复实现天文计算 MCP 这一层的麻烦不在算法，在返回值的形状：结果要能 JSON 序列化、时间统一带时区、大结果分页并给稳定的 resource_id、同步计算放线程里跑。工具是给模型读的，形状不对，模型就会反复试错。\n和 AI 一起写，留下的三个坑 这套东西大部分是我和 AI 一起写的。它写得快，但有几类问题很隐蔽，都是“看起来能跑”。\n第一类是散在函数签名里的默认值。road_radius_km=10、min_height_diff=100、max_distance_to_road_km=0.2、zoom=10，单看都合理。改一个数字，所有没显式传参的调用方一起变，而 diff 里只有一行。后来这些值收进配置对象，调用方要么显式传，要么用同一个来源。\n第二类是静默 fallback。高程查询有一条四级链：OSM 标签 → PostGIS → Open-Elevation → 0.0。最后一级的意思是：查不到海拔，这座山就变成海平面，评分照算，不报错。\n更典型的一次在前端。望远镜模式要拿观测点的经纬度，代码写的是 window._stargazingMap，可这个变量根本不存在。表达式永远是 undefined，于是每次都退回硬编码的 (40, 116)。页面不报错，目标列表也照常出，只是在给北京算。\n我怎么发现的？换了一个地点，结果没变。\n后来改成先读跳转时记下的地点，再退回地图中心；高程和评分的 fallback 也都加了日志，返回的 _meta 里写清楚实际走了哪一级。这类错误最难查，因为症状不是异常，是“结果不太对”。\n第三类是数据结构。最早坐标是 (lat, lon) 元组，谁在前谁在后靠约定；dataclass 也不校验。后来换成 Pydantic：GeoPoint 限制经纬度范围，GeoBounds 校验 north ≥ south，TimeInfo 拒绝不带时区的时间。非法输入在入口就失败，不会一路流到 SQL 里变成一个空结果。\n这些模型后来放进了 core，网页和 MCP 共用同一套定义。\n现在 一个容器，两个进程：MCP 在 3001，网页在 5001，共用一套虚拟环境。网页上看到的计划和 AI 调出来的计划，是同一个函数算的。\n出门前我把范围和时间丢进去，先看候选点的分数和理由；选定地点，再选望远镜，排目标；装不下的目标看马赛克方案。\n它还没有解决所有事。天气仍然是预报，seeing 和透明度没有实测；路网数据有滞后；评分权重还是我拍的。但结果不对的时候，我能顺着三层往回找，知道是哪一层的假设错了。\n这大概就是它和四个 App 之间最大的区别。\n","permalink":"https://stargazer1995.github.io/tech/stargazing-toolchain/","summary":"\u003cp\u003e决定今晚出不出去，我一般先看云。云量可以，再翻光污染地图；找到一块够黑的地方，还要看路能不能开到山脚；最后打开星图，确认想拍的东西今晚能升多高，这台镜子装不装得下。\u003c/p\u003e","title":"从一张光污染地图，到一晚拍摄计划"},{"content":"MHA[Multi-Head Attention] The thinking behind the MHA is simple here:\nGiven an input sequence $X[x_1, x_2, \u0026hellip;, x_n]$，MHA is equal to the concatenation of multiple outputs from attention process.\n$$ \\begin{gathered} O[o^{(1)}, o^{(2)}, \\dots, o^{(m)}] \\\\ o^{(h)} = Attn(q^{(h)}, k^{(h)}, v^{(h)}) \\\\ Attn = \\frac{\\sum_{i \\le t} exp(q_t*k_i^T)v_i}{exp(q_t*k_i^T)}\\\\ h : head \\\\ t : the\\ number\\ of\\ token \\\\ q = MLP_q(X) \\\\ k = MLP_k(X) \\\\ v = MLP_v(X) \\\\ \\end{gathered} $$ assume the output dimension is $d$, and the number of heads is $h$. Experimentally, we have the following equation: $d_k = d_v = d /h$. In the most of base cases, we only need to predict the t+1 word. and we can just cache the attention result, KV Cache, for our next use.\nBottle Neck of the MHA Me can easily find that the attention process becomes very expensive when the sequence becomes longer. We not only need to store the KV result, making more memory needs to be used for process. We also need to calculate the result of this long sequence. Even we have the most advanced GPU, communicating with multiple GPUs is very expensive for both training and inference jobs.\nSo, people start working on how to reduce the huge KV cache without loss the model performance.\nMQA[Multi-Query Attention] MQA is quite intuitive that all heads share the same KV cache. The equation of MQA could be:\n$$ \\begin{gathered} O[o^{(1)}, o^{(2)}, \\dots, o^{(m)}] \\\\ o^{(h)} = Attn(q, k, v^{(h)}) \\\\ Attn = \\frac{\\sum_{i \\le t} exp(q_t*k_i^T)v_i}{exp(q_t*k_i^T)}\\\\ h : head \\\\ t : the\\ number\\ of\\ token \\\\ q = MLP_q(X) \\\\ k = MLP_k(X) \\\\ v = MLP_v(X) \\\\ \\end{gathered} $$ Based on the equation, we can easily find that the method is quite aggressive that we directly use only one KV cache to do the job, losing the possibility that the model can more. But it is the most memory we can save from the KV cache side.\nGQA[Grouped-Query Attention] GQA is rather a kind of trade off when we look at the MHA and the MQA. It first group the heads and heads in the same group share the KV cache. We can use the following equation to model the method\n$$ \\begin{gathered} O[o^{(1)}, o^{(2)}, \\dots, o^{(m)}] \\\\ o^{(h)} = Attn(q^{(g)}, k^{(g)}, v^{(h)}) \\\\ Attn = \\frac{\\sum_{i \\le t} exp(q_t*k_i^T)v_i}{\\sum_{i \\le t}exp(q_t*k_i^T)}\\\\ g : group \\\\ h : head \\\\ t : the\\ number\\ of\\ token \\\\ q = MLP_q(X) \\\\ k = MLP_k(X) \\\\ v = MLP_v(X) \\\\ \\end{gathered} $$ MLA [Multi-Head Latent Attention] Deepseek team proposed this method in their deepseek v2 paper, and they said the method is inspired by Low-rank approximation. In this part of the page, we’re going to have a close look on the MLA.\nPart 1 we first look back to the GQA method. In GQA method, the input $X$ will be first separated equally, generating two $K,V$ pairs. These pairs, will be separated equally into $G$ groups and copied $h/g$ times. In MLA, there is a little difference from GQA. Instead of separate the input, MLA choose first project the input into $C$ space, then do the attention. The whole process could be formulated as the following equation:\n$$ \\begin{gathered} O[o^{(1)}, o^{(2)}, \\dots, o^{(m)}] \\\\ o^{(h)} = Attn(q^{(h)}, k^{(h)}, v^{(h)}) \\\\ Attn = \\frac{\\sum_{i \\le t} exp(q_t*k_i^T)v_i}{\\sum_{i \\le t}exp(q_t*k_i^T)}\\\\ h : head \\\\ t : the\\ number\\ of\\ token \\\\ c = MLP_c(X) \\\\ q = MLP_q(X) \\\\ k = MLP_k(C) \\\\ v = MLP_v(C) \\\\ \\end{gathered} $$ Wait, it seems not right that by introducing the C space that the KV cache is still needed.\nWe look back to the equation of the Dot-Attention:\n$$ q_{t}^{(s)}k_{i}^{(s)} = (x_{t}W_q^{(s)})(c_{i}W_k^{(s)})^T = x_{t}(W_q^{(s)}W_k^{(s)T})c_i^T $$ Which means, when the model is in inference mode, we can cache the product of $W_q^{(s)}W_k^{(s)T}$. Based on the same meaning, we can find that there is another projection matrix after the $o^s$, named as $W_{proj}$, and also the $v_i^{s} = c_iW_i^{s}$, which means that we can also cache the product of $W_i^{s}W_{proj}$.\nIt can be easily observed that by caching the product result of these matrix, all the attention head share the same $c$ value. Which means the MLA, when inferencing, becomes a MQA.\nappend The merge of the matrix product like $W_q^{(s)}W_k^{(s)T}$only works when the precising is infinity. When we use it in BF16, the error share be observable and accumulated in the network. In practice, we keep the original computing procedure for the computing source requires lower in the low rank and the precision loss the smaller. Part 2 The drawback for the current method is the MLA does not fit in RoPE.\nGiven:\n$$ \\begin{gathered} q_i^{(s)} = x_iW_q^{(s)}R_i,\\ k_i^{s} = c_iW_k^{(s)}R_i \\\\ q_t^{(s)}k_i^{sT} = x_t(W_q^{(s)}R_tR_i^TW_k^{(s)T})c_i^T = x_t(W_q^{(s)}R_{t-i}W_k^{(s)T})c_i^T \\end{gathered} $$ As the value of $R_{t-i}$ position related, we cannot just cache the result of $W_q^{(s)}W_k^{(s)T}$.\nDeepSeek Team use an appended dimension to fit in RoPE. They add $d_r$ dimensions to Q and K for RoPE, and K share the dimension with each head.\nSo, in mathematically, we can formulate the method in following equations.\n$$ \\begin{gathered} o_t = [o_1, o_2, o_3, \\dots, o_h] \\\\ o_t^{s} = Attention(q_t^s, k_{i \\le t}^s, v_{i \\le t}^s) = \\frac{\\sum_{i \\le t} exp(q_t^s*k_i^{sT})v_i^s}{\\sum_{i \\le t}exp(q_t^s*k_i^{sT})}\\\\ q_i^{(s)} = [x_iW_{qc}^{(s)}, x_iW_{qr}^{(s)}R_i], W_{qc} \\in \\mathbb R^{d*d_k}, W_{qr} \\in \\mathbb R^{d*d_r}\\\\ k_i^{(s)} = [c_iW_{kc}^{(s)}, x_iW_{kr}^{\\sout {(s)}}R_i], W_{kc} \\in \\mathbb R^{d*d_k}, W_{kr} \\in \\mathbb R^{d*d_r}\\\\ v_i^{(s)} = c_iW_v^{(s)}, W_v \\in \\mathbb R^{d_c * d_v} \\\\ c_i = x_i W_c, W_c \\in \\mathbb R^{d*d_c} \\end{gathered} $$ By doing so, those dimensions do not have rope information can just repeat the operation in Part 1, caching the result of $W_q^{(s)}W_k^{(s)T}$. And for those dimension who has the RoPE information, they can be done using the conviction method.\nAlso, because of the RoPE information is shared cross the head, for K cache there is only $d_r$ dimension is added.\nPart 3 One and the final modification is that the DeepSeek team apply Lowrank approximation method on Q\n$$ \\begin{gathered} o_t = [o_1, o_2, o_3, \\dots, o_h] \\\\ o_t^{s} = Attention(q_t^s, k_{i \\le t}^s, v_{i \\le t}^s) = \\frac{\\sum_{i \\le t} exp(q_t^s*k_i^{sT})v_i^s}{\\sum_{i \\le t}exp(q_t^s*k_i^{sT})}\\\\ q_i^{(s)} = [c'_iW_{qc}^{(s)}, c'_iW_{qr}^{(s)}R_i], W_{qc} \\in \\mathbb R^{d'_c*d_k}, W_{qr} \\in \\mathbb R^{d'_c*d_r}\\\\ k_i^{(s)} = [c_iW_{kc}^{(s)}, x_iW_{kr}^{\\sout {(s)}}R_i], W_{kc} \\in \\mathbb R^{d'_c*d_k}, W_{kr}^{\\sout {(s)}} \\in \\mathbb R^{d'_c*d_r}\\\\ v_i^{(s)} = c_iW_v^{(s)}, W_v \\in \\mathbb R^{d_c * d_v} \\\\ c'_i = x_i W_c', W_c' \\in \\mathbb R^{d *d_c'} \\\\ c_i = x_i W_c, W_c \\in \\mathbb R^{d*d_c} \\end{gathered} $$ LOOK AT the 2nd part of the $k_i^{(s)}$, the part with RoPE, the input is still the $x_i$. $d’ = 1536$ in the original paper, which is different from $d_c = 512$.\nWhen compared with the original MHA with RoPE, we can find that there is no big difference between them in training mode except only some dimension has RoPE in MLA while all dimension has RoPE in MHA.\nIn the inference mode, MLA goes to the MQA fashion that some dimension on K and V are shared cross the heads.\n","permalink":"https://stargazer1995.github.io/tech/from-mha-mqa-gqa-to-mlacache-is-all-your-need/","summary":"\u003ch1 id=\"mhamulti-head-attention\"\u003eMHA[Multi-Head Attention]\u003c/h1\u003e\n\u003cp\u003eThe thinking behind the MHA is simple here:\u003c/p\u003e\n\u003cp\u003eGiven an input sequence $X[x_1, x_2, \u0026hellip;, x_n]$，MHA is equal to the concatenation of multiple outputs from attention process.\u003c/p\u003e\n\u003cdiv class=\"math-display\"\u003e\n$$\n\n\\begin{gathered}\nO[o^{(1)}, o^{(2)}, \\dots, o^{(m)}] \\\\\no^{(h)} = Attn(q^{(h)}, k^{(h)}, v^{(h)}) \\\\\nAttn = \\frac{\\sum_{i \\le t} exp(q_t*k_i^T)v_i}{exp(q_t*k_i^T)}\\\\\nh : head \\\\\nt : the\\ number\\ of\\ token \\\\\nq = MLP_q(X) \\\\\nk = MLP_k(X) \\\\\nv = MLP_v(X) \\\\\n \n\\end{gathered}\n\n$$\n\u003c/div\u003e\n\n\u003cp\u003eassume the output dimension is $d$, and the number of heads is $h$. Experimentally, we have the following equation: $d_k = d_v = d /h$. In the most of base cases, we only need to predict the t+1 word. and we can just cache the attention result, \u003cstrong\u003eKV Cache\u003c/strong\u003e, for our next use.\u003c/p\u003e","title":"From MHA, MQA, GQA to MLA——Cache is all your need"},{"content":"简介 这是一篇介绍如何从零开始构建 MCP server 的简单说明。本说明由三部分组成：UV 介绍、代码开发和部署。\nUV 简介 UV是一个基于 rust 的 Python 软件包和项目管理器。除了 UV 非常快之外，UV 与其他管理器没有什么区别。此外，MCP 使用 UVX（运行 python 包的 UV 工具）来运行服务器。因此，在本说明中，我们将使用 UV 来管理我们的项目。\n安装 UV 现在可以使用 PyPi 进行安装：\n1 pip install uv [optional] 更改源代码 由于特殊的网络环境，我们有时需要更改 UV 的源。需要在环境中添加下面的命令。\n1 export UV_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple 此命令将 UV 的源从官方网站暂时改为 TUNA。可以参考文档来彻底对源的使用路径进行彻底修改。\nPython 设置 为方便起见，我们使用 UV 设置 python 解释器。\n1 uv python install 然后，我们使用下面的命令在一个目录中设置一个 Python 项目。\n1 2 3 4 mkdir note # build a new directory for our code uv init ./note # setup the direcory as our workspace cd note # get into the workspace uv venv # starts a new virtual environment 如果成功，UV 会生成一些新文件，如下图所示：\n总结 我们已经安装了 UV，设置了解释器，并为我们的项目初始化了一个新的工作区。下一步，我们将完成项目，并实现一个非常简单的 MCP 服务器。\n代码开发 在本节中，我们将开始实现一个非常简单的 MCP 服务器。首先，我们将浏览 workspace，安装一些项目以来，执行一些代码来验证 pipeline 是否通畅。\n浏览工作区 我们可以在这里看到我们的项目结构。工作区中有一些由 UV 生成的文件。不过不用担心。我们只需注意三个文件：main.py、README.md 和 pyproject.toml。\nmain.py文件是执行代码的地方。 在README.md文件中，你可能想写下一些关于代码的内容。 pyproject.toml 是打包时管理项目的文件，稍后会介绍。 安装依赖项 在本项目中，我们主要使用 FastMCP 。有关该 python 软件包的信息，请点击此处。简而言之，FastMCP 是使用 python 实现 MCP 服务器的一个简单但非常有用的工具。这里直接使用 uv 来进行安装。\n1 uv pip install fastmcp 执行代码 安装好 FastMCP 后，我们就可以像下面这样执行代码了。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from fastmcp import FastMCP # Import the FastMCP class from the fastmcp module # Create a FastMCP server instance with the name \u0026#34;note\u0026#34; server = FastMCP(\u0026#34;note\u0026#34;) # Register a tool/endpoint named \u0026#34;hello_world\u0026#34; using the @server.tool() decorator @server.tool() def hello_world(): return \u0026#34;Hello World\u0026#34; # The function returns \u0026#34;Hello World\u0026#34; when called def main(): server.run() # Standard Python idiom to check if the script is being run directly if __name__ == \u0026#34;__main__\u0026#34;: main() # Start the FastMCP server 如何运行代码 在终端中，我们可以使用 fastmcp 命令运行代码。\n1 2 3 # in our project directory source .venv/bin/activate #activate the virtual environment we built fastmcp dev main.py # run the code in development code 如果运行顺利，你会在终端中看到一些信息。\n这些信息告诉你，mcp inspector 正在 6274 端口运行，你可以通过它提供的 URL 链接访问。MCP inspector 是我们验证服务器是否起来的工具。我们不会花太多时间来介绍。\n访问检查器服务器后，你会看到如下界面。点击左侧的连接按钮。\n连接建立后，界面会变成这样。\n我们首先点击 \u0026ldquo;工具 \u0026ldquo;按钮，然后选择 \u0026ldquo;列表工具\u0026rdquo;，检查我们所使用的工具。然后运行。\n如果工具执行成功，就会看到如下界面的结果。那么你就成功运行了一个 mcp 工具。\n调试代码 我个人建议使用 UT、AT 或回归测试等各种测试在本地测试代码。因为这样更方便我们使用。MCP inspector 提供的工具不太好用。\n一些建议 给函数写一些详细的注释，这样 llm 方便理解这个函数是什么「可以用 LLM 来生成」。 在输入跟输出中添加所期望的类型信息，可以避免一些因为输入类型带来的错误。 软件包部署 在本节中，我们可以部署 mcp 服务器供 LLM 使用。我们需要更新之前提到的 pyproject.toml 以打包我们的代码。\n更新可执行信息 在我们的项目中，在 pyproject.toml 中添加以下几行：\n1 2 [project.scripts] note = \u0026#34;main:main\u0026#34; # Executes the `main()` function in `main.py` 添加依赖项信息 我们还需要为软件包添加依赖项，可以使用以下命令将我们使用的软件包添加到 pyproject.toml 中\n1 uv add fastmcp 当然，如果我们有很多软件包需要依赖，这看起来会很不舒服。我们也可以使用其他工具来实现这一点。\n部署代码 我们使用以下命令打包代码并运行。\n1 2 3 uv build --wheel # packaging your code into wheel uv install ${PATHTOYOURPACKAGE} # install the packaged code uvx --python=$(which python) ${PACKAGE} # run the package using specific python interpreter 如果一切顺利，你会在 CLI 中看到以下信息。它会告诉你 MCP 服务器正在运行。\n","permalink":"https://stargazer1995.github.io/tech/%E5%A6%82%E4%BD%95%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E6%9E%84%E5%BB%BA%E7%AE%80%E5%8D%95%E7%9A%84mcp/","summary":"\u003ch1 id=\"简介\"\u003e简介\u003c/h1\u003e\n\u003cp\u003e这是一篇介绍如何从零开始构建 MCP server 的简单说明。本说明由三部分组成：UV 介绍、代码开发和部署。\u003c/p\u003e\n\u003ch1 id=\"uv-简介\"\u003eUV 简介\u003c/h1\u003e\n\u003cp\u003e\u003ca href=\"https://docs.astral.sh/uv/\"\u003eUV\u003c/a\u003e是一个基于 rust 的 Python 软件包和项目管理器。除了 UV 非常快之外，UV 与其他管理器没有什么区别。此外，MCP 使用 UVX（运行 python 包的 UV 工具）来运行服务器。因此，在本说明中，我们将使用 UV 来管理我们的项目。\u003c/p\u003e","title":"如何从零开始构建简单的MCP"},{"content":"Pre-assumption This guide assumes that readers are familiar with Linux or MacOS command line interface (CLI) and what is a MCP server.\nBrief introduction This guide shows how to build a MCP server from scratch. This note is composed by three parts: UV introduction, Code development, and deployment.\nUV introduction UV is a rust based Python package and project manager. There are no differences between UV and other managers except UV is very fast. Also, MCP uses UVX, a UV tool for running python package, to run the server. So in this note, we’ll use UV to manage our project.\nInstallation UV now can use PyPi for installation:\n1 pip install uv Change the source [optional] Sometimes we need to change the source of UV because of the special network environment. Please consider add the following command to your environment.\n1 export UV_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple This command changes the source of UV from the official site to TUNA temporarily. If you want to persist your modification, please refer doc from tuna.\nPython setup For convenience, we use UV to setup our python interpreter.\n1 uv python install Then, we use the following command to setup a python project in a directory.\n1 2 3 4 mkdir note # build a new directory for our code uv init ./note # setup the direcory as our workspace cd note # get into the workspace uv venv # starts a new virtual environment If success, there will be some new files generated by UV and the directory should be like this:\nSummary We have installed the UV, set up a interpreter, and initialized a new workspace for our project. In the next step, we’ll go through the project and implement a very simple MCP server.\nCode development In this section, we’ll start implementing a very simple MCP server. We’ll start with going through our workspace, install some dependencies, implement some code, and debug the code.\nWorkspace go through We can see our project structure in here. There are some files in this workspace which is generated by UV. But do not worry about it. We only need to take care about three files: main.py, README.md, and pyproject.toml.\nThe main.py file is the place where the code will be executed and is the place we’ll focus on in this section. The README.md is the place you might want to write something. The pyproject.toml is the file we manage our project when packaging, which will be introduced later. Dependencies installation In this project, we mainly use FastMCP for developing our server. You can find information about the python package here. In a short, FastMCP is a simple yet very useful tool for us to implement MCP servers using python. The installation command using UV is demonstrated as below.\n1 uv pip install fastmcp Implement code After we have installed the FastMCP, we then can implement our code like the following.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from fastmcp import FastMCP # Import the FastMCP class from the fastmcp module # Create a FastMCP server instance with the name \u0026#34;note\u0026#34; server = FastMCP(\u0026#34;note\u0026#34;) # Register a tool/endpoint named \u0026#34;hello_world\u0026#34; using the @server.tool() decorator @server.tool() def hello_world(): return \u0026#34;Hello World\u0026#34; # The function returns \u0026#34;Hello World\u0026#34; when called def main(): server.run() # Standard Python idiom to check if the script is being run directly if __name__ == \u0026#34;__main__\u0026#34;: main() # Start the FastMCP server How to run the code In our terminal, we can run our code by using fastmcp commands.\n1 2 3 # in our project directory source .venv/bin/activate #activate the virtual environment we built fastmcp dev main.py # run the code in development code if it goes well, you’ll see some information in your terminal.\nThe information is telling you that the inspector server is running in port 6274 and you can access to the inspector server using the URL link it provides. The inspector server is a tool for us to verify our code. We’ll not spend too much time to introduce.\nYou’ll see the screen once you access to the inspector server. And click the connect button on the left side.\nAfter connection is established, your screen will be like this.\nWe’ll first click Tools button and choose List Tools to check the tools we implement. And run the tool.\nIf the tool is executed successfully, you’ll see the result in the following screen. Then you have successfully run a mcp tool.\nDebug the code I, personally, recommend to use various of tests like UT, AT, or regression tests to test your code locally. Because it is much more convenient for us to use.\nSome suggestions: Write detailed comment for the tool we implement, it’ll help LLM to understand the function it can use. Add type expectations to your function inputs and outputs. It’ll avoid some mistakes from input side. Summary In this section, we have gone through our project, implemented some code, and run it using MCP inspector.\nPackage deployment In this section, we can deploy our mcp server for LLM to use. We’ll need to update the pyproject.toml we mentioned before to package our code.\nupdate executable information In our project, we add the following lines to our pyproject.toml:\n1 2 [project.scripts] note = \u0026#34;main:main\u0026#34; # Executes the `main()` function in `main.py` Add dependencies information we need to include dependencies in our package, we can use the following command to add the package we use to the pyproject.toml\n1 uv add fastmcp Of course it looks uncomfortable if we have many packages we need to depend. We also can use other tools to do this.\ndeploy your code we use the following commands packaging our code and run it.\n1 2 3 uv build --wheel # packaging your code into wheel uv install ${PATHTOYOURPACKAGE} # install the packaged code uvx --python=$(which python) ${PACKAGE} # run the package using specific python interpreter If all goes well, you’ll see the following information in the CLI. It tells you that your MCP server is running.\n","permalink":"https://stargazer1995.github.io/tech/how-to-build-a-simple-mcp-tool-server-from-scratch/","summary":"\u003ch1 id=\"pre-assumption\"\u003ePre-assumption\u003c/h1\u003e\n\u003cp\u003eThis guide assumes that readers are familiar with Linux or MacOS command line interface (CLI) and what is a MCP server.\u003c/p\u003e\n\u003ch1 id=\"brief-introduction\"\u003eBrief introduction\u003c/h1\u003e\n\u003cp\u003eThis guide shows how to build a MCP server from scratch. This note is composed by three parts: UV introduction, Code development, and deployment.\u003c/p\u003e\n\u003ch1 id=\"uv-introduction\"\u003eUV introduction\u003c/h1\u003e\n\u003cp\u003e\u003ca href=\"https://docs.astral.sh/uv/\"\u003eUV\u003c/a\u003e is a rust based Python package and project manager. There are no differences between UV and other managers except UV is very fast. Also, MCP uses UVX, a UV tool for running python package, to run the server. So in this note, we’ll use UV to manage our project.\u003c/p\u003e","title":"how to build a simple mcp tool server from scratch"},{"content":"hacking is a kind of art\n也许是读了上一本《禅与摩托车维修艺术》之后对这些书产生了 PTSD，起初并没有对这本书有多上心。但是在读完了之后，我发现我的 PTSD 被治好了。2333333\n这本书可以看作是Paul Graham的一本随笔集，因此这本书中的各个章节没有严格的顺序。所以你可以自由地读你想读的每一个篇章。在这里，我想要跟大家聊一下这些东西：\n代码也是一种艺术 Paul Graham 把黑客比作画家，强调编程是一种创造性的艺术表达。对 programmer 来说，手里面的文本编辑器其实就是我们的 canvas。 跟画家使用画布，摄影师使用感光芯片或者胶卷一样，我们用逻辑跟计算在计算机的世界里面进行创造。Graham 告诉我们，编程不仅是技术，更是创造力的释放。我们的创造力是可以直接在现实世界中产生出价值。\n对于一个 geek 来说，这种把编程看作艺术的角度真是再自然不过了。每一行优雅的代码，每一个巧妙的算法，都是在创造美。Graham 鼓励我们去追求这种美，不要被庸俗的商业需求压制住创意。记住，代码不仅要跑得快，还要写得美。\nhacking 的文化 《黑客与画家》中的创业思想会让我眼前一亮。Graham 自己就是一个成功的创业者（你可能听说过 Y Combinator， 举一个栗子 🌰： Sam Altman 曾经也是 YC 的掌门人），所以他的话应该需要听。他强调，创业就像编程，都是从零开始，用智慧和代码去解决现实世界的问题。\n他提出的“快速迭代”和“最小可行产品”（MVP）理念简直是创业界的黄金法则。你不用等所有功能都完美无缺才发布产品，先推出一个能用的版本，再通过用户反馈不断改进。就像写代码一样，先搞出个能跑的版本，再慢慢优化。注意：这个仅仅只对创业阶段有效，如果是在产品已经接近成熟的阶段，请务必保证功能的完善性以及产品的成熟度。\n质疑权威，追求自由 Graham 在书中充满了对传统商业文化的质疑。他主张黑客精神中的独立思考和自由创造，认为这种精神是推动技术和社会进步的关键力量。\n这不只是技术层面的反叛，也是对整个商业文化的一次颠覆。Graham 鼓励我们挑战传统的工作方式，勇于追求自己的创意和梦想，而不是被公司和市场束缚住。这种反传统的思维模式，正是现代科技创业文化的核心，驱动着无数创新和变革。\n人生苦短，我用 python ","permalink":"https://stargazer1995.github.io/%E9%BB%91%E5%AE%A2%E4%B8%8E%E7%94%BB%E5%AE%B6/","summary":"\u003cp\u003ehacking is a kind of art\u003c/p\u003e\n\u003cp\u003e也许是读了上一本《\u003ca href=\"/f1a1f945e61f42068d1ac9f9e8e66d8a\"\u003e禅与摩托车维修艺术\u003c/a\u003e》之后对这些书产生了 PTSD，起初并没有对这本书有多上心。但是在读完了之后，我发现我的 PTSD 被治好了。2333333\u003c/p\u003e\n\u003cp\u003e这本书可以看作是\u003ca href=\"https://www.paulgraham.com/\"\u003ePaul Graham\u003c/a\u003e的一本随笔集，因此这本书中的各个章节没有严格的顺序。所以你可以自由地读你想读的每一个篇章。在这里，我想要跟大家聊一下这些东西：\u003c/p\u003e","title":"黑客与画家"},{"content":"这是一场亲子之间的公路旅行，也是一个对自己的探索。更是一个如何“维修摩托车”的手册吗？\n这是一本双线发展的书。在公路旅行的过程中，作者不断与儿子发生着互动，也在跟读者们阐述着什么是 “良质”。虽然跟儿子的故事线是一个重要的篇章，但是我想要记录一下在读这本书的时候我对“良质”的粗浅理解以及看法。\n良质真的需要到二元论的高度吗？ 从文章开头来看，良质更像是一种优良的品质【quality】。它表明了一个东西是好的。或者说，我们认为他是好的。他实际上反映的是我们对事物的一种看法。这种看法的标准并不是同一的，是随着主观想法时刻发生着变化的。也因此我不同意将良质放在二元论的高度。\n我并不能理解深奥的哲学还有修辞学。但是我理解这个世界并非二元论就能够解释清楚的。只是良质并不应该属于在这黑与白之间的“灰”。作者认为“良质”是能够连接由科学代表的理性主义跟由艺术代表的浪漫主义的桥梁。这种方式显然是在夸大“良质”的作用。$e^{i\\pi} + 1 = 0$ 这个公式就能够作为一个代表了理性主义的美，一个简单的公式就把有理数，无理数，实数，虚数以及数学大厦最基本的 0，1 串联起来。这难道说不是一种纯粹理性的美的吗？ 同样的，毕加索的抽象艺术，毫无理性可言，也同样是美的。在这两个例子中“良质”扮演了什么样的桥梁的角色了吗？我认为没有。它没有承担起作者原本想象的“桥梁”的作用。\n相反，作者似乎在扩大化解释，试图来给自己的想法找到更多的依靠。在文章中，他引用了《道德经》，我想是因为“道可道非常道”这句话很适合用来给他解释什么是良质这种在当时看来依然十分虚无缥缈的东西。扯完了道家之后，他又开始扯佛教了。但是似乎他对于佛教的理解如同对于道家一样，只是一个用来给良质贴标签的工具。同样的手法，他讨论起来了黎曼几何跟欧氏几何。就这样，所谓的良质成了道；成了佛；成了和谐… 良质成了 “真善美”。\n这种论点的扩大化，在论述中非常的危险。因为这极大的增加了对于论点进行论证所需要的工作量。而且给别人更多的攻击你的论点的空间。那么作者为什么要这么做呢？在我看来，作者极力想要证明他是对的，并且不惜一切努力来找到符合他的论点的内容来当作解释。这不就是证明他的论点其实并不能站住脚吗？\n所以，在我看来，作者所谓的“良质”。实际上只是一个人为的，主观的，判断。它没有足够的资格也不能够被上升到古典哲学的二元论这一水平中。\n那么，良质能用来做什么呢？ 如果良质是一种 quality 的话，那这本书的确算是教授了我们怎么样正确“维护”一辆摩托车。作者提出了一些观点来说“什么是正确的，有价值的”。从工程实践的角度来看，作者的想法是正确的。作者认为在“卡住”的时候应该适当的休息，这个在研发的过程中也是应该被提倡的。“大力出不了奇迹” 这个一直是我认为的观点。如果没有从有价值的方向开始，那么任务就会完成得很慢；如果没有适当的休息，在程序员所身处的高度紧张的工作环境中，因为疲劳所带来的 bug 数量以及工作量就会剧烈的增加，身体也就会承受不住。听说最近虾皮有一位同行撑不住倒下了…默哀…\n我想，应该是这么多年的软件工程师前辈们传下来的经验让我们能够贴近作者所谓的“良质”以及拥有“维修摩托车”所应该有的“禅”的精神。导致我在看书的时候一直在想：这不就是写代码的正确的样子吗？这不就是应该做的事情吗？ 那么，如果从这里来看的话。在学校以及工作中，已经有足够的事物来教导我们了。因此，在我看来，如果是有着正确的训练的工程师们，良质对我们的作用就微乎其微了。\n那么，这就是我的结语 所以，良质并不能教导我们在日常学习工作中以外的东西。它是一个虚无缥缈的概念，它并不能传递出新的观点，也没办法改变人们的思想。\nBTW：机械键盘相比起 HHKB 更适合让我写一点血压高的东西 23333333. 果然 HHKB 还是比较适合禅意的状态下使用。\n","permalink":"https://stargazer1995.github.io/%E7%A6%85%E4%B8%8E%E6%91%A9%E6%89%98%E8%BD%A6%E7%BB%B4%E4%BF%AE%E8%89%BA%E6%9C%AF/","summary":"\u003cp\u003e这是一场亲子之间的公路旅行，也是一个对自己的探索。更是一个如何“维修摩托车”的手册\u003cstrong\u003e吗\u003c/strong\u003e？\u003c/p\u003e\n\u003cp\u003e这是一本双线发展的书。在公路旅行的过程中，作者不断与儿子发生着互动，也在跟读者们阐述着什么是 “良质”。虽然跟儿子的故事线是一个重要的篇章，但是我想要记录一下在读这本书的时候我对“良质”的粗浅理解以及看法。\u003c/p\u003e","title":"禅与摩托车维修艺术"},{"content":"Introduction We\u0026rsquo;ve been experiencing an application crash on the QNX platform, which initially seemed like a common occurrence since core dumps happens. However, this issue is different. After the crash, we\u0026rsquo;re unable to enter engineering mode, making it impossible to use SSH to retrieve the core file. Furthermore, the crash occurs near the application start, leaving no time to enter engineering mode when the system boots up. This page serves to document how I\u0026rsquo;ve dealt with this issue, which is perhaps my proudest achievement so far at the new company.\nAddressing the code Given the limitations we face, such as the inability to retrieve the core file, use gdb for debugging, engage the engineering mode for logs, or get console prints from the application, it feels like we\u0026rsquo;ve been transported back to the 1960s. However, despite these challenges, I\u0026rsquo;ve found that a simple yet effective approach, like binary search, can still be incredibly useful in resolving the issue.\nThe following code demonstrates a simple pipeline.\n1 v2x_receiver -\u0026gt; v2x_adapter -\u0026gt; other_functions[we do not modify] After removing the v2x_adapter from the pipeline, the crash persists, suggesting that it occurs within the v2x_receiver. Given the rapid occurrence of the crash, I suspect it happens during the receiver\u0026rsquo;s construction phase.\nThe structure of the v2x_receiver is quite simple. I will show a simple example in the following snippet.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class V2xReceiver{ public: V2xReceiver(){ build_connection(); } void excute(){ // processing the data } private: void build_connection(){ // build a communication with antenna v2x_client(); } V2xClient v2x_client; }; I removed everything about the v2x_client in the receiver, and the crash disappeared. I did more tests and confirmed that the program crashed when we call v2x_client’s construction function.\nAnother problem rises after I have addressed the code crashes the system is that how we delay this construction function call. I moved the declaration and construction of v2x_client in the runtime function. Here I show the modified version of the code.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class V2xReceiver{ public: V2xReceiver(){ build_connection(); } void excute(){ // call the construction which crash the application // call the construction which crash the application while (counter \u0026lt; 2000){ V2xClient v2x_client(); } counter++; // processing the data } private: void build_connection(){ // build a communication with antenna } int counter = 0; }; By doing so, we have enough time to engage the engineering mode, and enable ssh function for retrieving the core dump file on our local machine.\nCore file analysis QNX provides a toolchain that we can analyze the core dump file. I would not write details on how we use the toolchain. The important part is the core stack. The backtrace information gives a fact the program received a kill signal from the system because it attempts to construct a socket for communication with the outside.\nSystem log dump Upon identifying the issue, we sought to dump the system\u0026rsquo;s kernel log for further investigation. QNX offers a tool called slog2info for this purpose. Reviewing the system log, we discovered that the socket construction was being denied by the system due to the application\u0026rsquo;s security policy.\nQNX privilege management QNX employs a strict privilege management system that uses scripts to define an application\u0026rsquo;s permissions. If an application violates these rules, the operating system sends a kill signal to terminate the application. These rules are stored in files with a .secpol extension.\nThe QNX system also provides a utility named secpol for managing privileges. I used the following script to dump the privilege specifications.\n1 secpol -c \u0026gt; ${some_where_you_want} I could give the application with the required privilege. And thus, the problem is solved.\nEnd of the story Yes, the story is short after I have omitted some details I cannot say outside the office. But I believe this could be a good story that tells what we could do when we encountered the same issue. For myself, I am very proud for what I have done during this journey.\n","permalink":"https://stargazer1995.github.io/tech/a-story-of-debugging/","summary":"\u003ch1 id=\"introduction\"\u003eIntroduction\u003c/h1\u003e\n\u003cp\u003eWe\u0026rsquo;ve been experiencing an application crash on the QNX platform, which initially seemed like a common occurrence since core dumps happens. However, this issue is different. After the crash, we\u0026rsquo;re unable to enter engineering mode, making it impossible to use SSH to retrieve the core file. Furthermore, the crash occurs near the application start, leaving no time to enter engineering mode when the system boots up. This page serves to document how I\u0026rsquo;ve dealt with this issue, which is perhaps my proudest achievement so far at the new company.\u003c/p\u003e","title":"A story of debugging"},{"content":"Transforming through coordination systems can be confused for some developers like me. But we have to know those commonly used systems and know the bridge between these words.\nAs an autonomous system developer, the commonly used coordination systems are: WGS84, local Cartesian, and ego. Although it is not that important to know the projection theory behind these coordinates, it is good to know how to transform between the coordinations.\nConversion from WGS84 to Cartesian We first need to choose a reference point in WGS84 as the cartesian’s origin. Convert the WGS84 coordinates of the reference point to Earth-Centered, Earth-Fixed (ECEF) Cartesian coordinates. Convert the WGS84 coordinates of the point you want to transform to ECEF Cartesian coordinates. Translate and rotate the ECEF coordinates of the target point to the local ENU coordinate system centered at the reference point. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 import math import numpy as np # WGS84 ellipsoid constants a = 6378137.0 # Semi-major axis in meters f = 1 / 298.257223563 # Flattening e2 = 2 * f - f * f # First eccentricity squared def wgs84_to_ecef(lat, lon, alt): lat_rad = math.radians(lat) lon_rad = math.radians(lon) N = a / math.sqrt(1 - e2 * math.sin(lat_rad) ** 2) X = (N + alt) * math.cos(lat_rad) * math.cos(lon_rad) Y = (N + alt) * math.cos(lat_rad) * math.sin(lon_rad) Z = (N * (1 - e2) + alt) * math.sin(lat_rad) return X, Y, Z def ecef_to_enu(x, y, z, lat0, lon0, h0): lat0_rad = math.radians(lat0) lon0_rad = math.radians(lon0) X0, Y0, Z0 = wgs84_to_ecef(lat0, lon0, h0) dx = x - X0 dy = y - Y0 dz = z - Z0 sin_lat0 = math.sin(lat0_rad) cos_lat0 = math.cos(lat0_rad) sin_lon0 = math.sin(lon0_rad) cos_lon0 = math.cos(lon0_rad) t = np.array([ [-sin_lon0, cos_lon0, 0], [-sin_lat0 * cos_lon0, -sin_lat0 * sin_lon0, cos_lat0], [cos_lat0 * cos_lon0, cos_lat0 * sin_lon0, sin_lat0] ]) enu = np.dot(t, np.array([dx, dy, dz])) return enu[0], enu[1], enu[2] # Reference point (example: latitude, longitude, altitude) ref_lat = 41.8902 ref_lon = 12.4924 ref_alt = 0 # Target point to be transformed (example: another point near the reference) target_lat = 41.8912 target_lon = 12.4934 target_alt = 0 # Convert target point to ECEF target_x, target_y, target_z = wgs84_to_ecef(target_lat, target_lon, target_alt) # Convert to ENU coordinates relative to the reference point enu_x, enu_y, enu_z = ecef_to_enu(target_x, target_y, target_z, ref_lat, ref_lon, ref_alt) print(f\u0026#34;ENU coordinates: E={enu_x}, N={enu_y}, U={enu_z}\u0026#34;) Convert local cartesian to ego position In our system, the difference between the local cartesian to the ego coordinate system is only the rotation.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import numpy as np def local_to_ego(local_x, local_y, ego_yaw): # Translate coordinates to the ego vehicle\u0026#39;s position translated_x = local_x translated_y = local_y # Create the rotation matrix based on the ego vehicle\u0026#39;s yaw angle cos_yaw = np.cos(ego_yaw) sin_yaw = np.sin(ego_yaw) rotation_matrix = np.array([ [cos_yaw, sin_yaw], [-sin_yaw, cos_yaw] ]) # Rotate the translated coordinates to align with the vehicle\u0026#39;s orientation local_coords = np.array([translated_x, translated_y]) ego_coords = np.dot(rotation_matrix, local_coords) return ego_coords ","permalink":"https://stargazer1995.github.io/tech/complicated-geo-coordinate-systems/","summary":"\u003cp\u003eTransforming through coordination systems can be confused for some developers like me. But we have to know those commonly used systems and know the bridge between these words.\u003c/p\u003e\n\u003cp\u003eAs an autonomous system developer, the commonly used coordination systems are: WGS84, local Cartesian, and ego. Although it is not that important to know the projection theory behind these coordinates, it is good to know how to transform between the coordinations.\u003c/p\u003e\n\u003ch2 id=\"conversion-from-wgs84-to-cartesian\"\u003eConversion from WGS84 to Cartesian\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003eWe first need to choose a reference point in WGS84 as the cartesian’s origin.\u003c/li\u003e\n\u003cli\u003eConvert the WGS84 coordinates of the reference point to Earth-Centered, Earth-Fixed (ECEF) Cartesian coordinates.\u003c/li\u003e\n\u003cli\u003eConvert the WGS84 coordinates of the point you want to transform to ECEF Cartesian coordinates.\u003c/li\u003e\n\u003cli\u003eTranslate and rotate the ECEF coordinates of the target point to the local ENU coordinate system centered at the reference point.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e 1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 8\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 9\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e10\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e11\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e12\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e13\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e14\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e15\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e16\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e17\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e18\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e19\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e20\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e21\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e22\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e23\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e24\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e25\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e26\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e27\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e28\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e29\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e30\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e31\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e32\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e33\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e34\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e35\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e36\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e37\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e38\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e39\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e40\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e41\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e42\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e43\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e44\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e45\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e46\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e47\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e48\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e49\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e50\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e51\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e52\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e53\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e54\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e55\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e56\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e57\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e58\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e59\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e60\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e61\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e62\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kn\"\u003eimport\u003c/span\u003e \u003cspan class=\"nn\"\u003emath\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kn\"\u003eimport\u003c/span\u003e \u003cspan class=\"nn\"\u003enumpy\u003c/span\u003e \u003cspan class=\"k\"\u003eas\u003c/span\u003e \u003cspan class=\"nn\"\u003enp\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# WGS84 ellipsoid constants\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mf\"\u003e6378137.0\u003c/span\u003e  \u003cspan class=\"c1\"\u003e# Semi-major axis in meters\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003ef\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e \u003cspan class=\"o\"\u003e/\u003c/span\u003e \u003cspan class=\"mf\"\u003e298.257223563\u003c/span\u003e  \u003cspan class=\"c1\"\u003e# Flattening\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003ee2\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e2\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003ef\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"n\"\u003ef\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003ef\u003c/span\u003e  \u003cspan class=\"c1\"\u003e# First eccentricity squared\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003edef\u003c/span\u003e \u003cspan class=\"nf\"\u003ewgs84_to_ecef\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003elat\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003elon\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ealt\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003elat_rad\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003emath\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eradians\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003elat\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003elon_rad\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003emath\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eradians\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003elon\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003eN\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e \u003cspan class=\"o\"\u003e/\u003c/span\u003e \u003cspan class=\"n\"\u003emath\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esqrt\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"n\"\u003ee2\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003emath\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003elat_rad\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e**\u003c/span\u003e \u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003eX\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eN\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"n\"\u003ealt\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003emath\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecos\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003elat_rad\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003emath\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecos\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003elon_rad\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003eY\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eN\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"n\"\u003ealt\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003emath\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecos\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003elat_rad\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003emath\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003elon_rad\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003eZ\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eN\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"n\"\u003ee2\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"n\"\u003ealt\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003emath\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003elat_rad\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eX\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eY\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eZ\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003edef\u003c/span\u003e \u003cspan class=\"nf\"\u003eecef_to_enu\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003elat0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003elon0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eh0\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003elat0_rad\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003emath\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eradians\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003elat0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003elon0_rad\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003emath\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eradians\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003elon0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003eX0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eY0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eZ0\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ewgs84_to_ecef\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003elat0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003elon0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eh0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003edx\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ex\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"n\"\u003eX0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003edy\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ey\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"n\"\u003eY0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003edz\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ez\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"n\"\u003eZ0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003esin_lat0\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003emath\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003elat0_rad\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003ecos_lat0\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003emath\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecos\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003elat0_rad\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003esin_lon0\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003emath\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003elon0_rad\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003ecos_lon0\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003emath\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecos\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003elon0_rad\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003et\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003earray\u003c/span\u003e\u003cspan class=\"p\"\u003e([\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003esin_lon0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ecos_lon0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003esin_lat0\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003ecos_lon0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003esin_lat0\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003esin_lon0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ecos_lat0\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ecos_lat0\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003ecos_lon0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ecos_lat0\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003esin_lon0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003esin_lat0\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e])\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003eenu\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edot\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003et\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003earray\u003c/span\u003e\u003cspan class=\"p\"\u003e([\u003c/span\u003e\u003cspan class=\"n\"\u003edx\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003edy\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003edz\u003c/span\u003e\u003cspan class=\"p\"\u003e]))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eenu\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e \u003cspan class=\"n\"\u003eenu\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e \u003cspan class=\"n\"\u003eenu\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# Reference point (example: latitude, longitude, altitude)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eref_lat\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mf\"\u003e41.8902\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eref_lon\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mf\"\u003e12.4924\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eref_alt\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# Target point to be transformed (example: another point near the reference)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003etarget_lat\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mf\"\u003e41.8912\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003etarget_lon\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mf\"\u003e12.4934\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003etarget_alt\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# Convert target point to ECEF\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003etarget_x\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003etarget_y\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003etarget_z\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ewgs84_to_ecef\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etarget_lat\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003etarget_lon\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003etarget_alt\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# Convert to ENU coordinates relative to the reference point\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eenu_x\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eenu_y\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eenu_z\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eecef_to_enu\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etarget_x\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003etarget_y\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003etarget_z\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eref_lat\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eref_lon\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eref_alt\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"sa\"\u003ef\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;ENU coordinates: E=\u003c/span\u003e\u003cspan class=\"si\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003eenu_x\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e, N=\u003c/span\u003e\u003cspan class=\"si\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003eenu_y\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e, U=\u003c/span\u003e\u003cspan class=\"si\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003eenu_z\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003ch2 id=\"convert-local-cartesian-to-ego-position\"\u003eConvert local cartesian to ego position\u003c/h2\u003e\n\u003cp\u003eIn our system, the difference between the local cartesian to the ego coordinate system is only the rotation.\u003c/p\u003e","title":"complicated geo coordinate systems"},{"content":"\nFrom the perceptive of the structure of mamba, this is a discrete selective space machine that runs in linear time using linear space.\nlets say, matrix A is a state space matrix for the last system status h(t). we then can calculate the next h(t+1) based on the following equation:\n$$ \\begin{equation}h(t) = A*h(t-1) + B*x(t)\\end{equation} $$ $$ y = C*h(t) $$ Where B is a weight for input x(t) and C is the weight for output y.\nWe define A matrix in a HiPPO matrix manner.\n$$ A = \\begin{cases} \\sqrt{(2n+1)(2k+1)} \u0026\u0026 everything-below -diagonal \\\\ n+1 \u0026\u0026 on-diagonal \\\\ 0 \u0026\u0026 everything-beyond-diagonal \\end{cases} $$ By doing this, we can use SVD partition for reducing the computing demand.\n$$ A=V\\Lambda V^* - PQ^T = V(\\Lambda - (V^*P)(V^*Q)^*)V $$ This can be done\n","permalink":"https://stargazer1995.github.io/tech/first-touch-to-mamba/","summary":"\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/images/notion/0fa39399d0e0bb67.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003eFrom the perceptive of the structure of mamba, this is a discrete selective space machine that runs in linear time using linear space.\u003c/p\u003e\n\u003cp\u003elets say, matrix A is a state space matrix for the last system status h(t). we then can calculate the next h(t+1) based on the following equation:\u003c/p\u003e\n\u003cdiv class=\"math-display\"\u003e\n$$\n\n\\begin{equation}h(t) = A*h(t-1) + B*x(t)\\end{equation}\n\n$$\n\u003c/div\u003e\n\n\u003cdiv class=\"math-display\"\u003e\n$$\n\ny = C*h(t)\n\n$$\n\u003c/div\u003e\n\n\u003cp\u003eWhere B is a weight for input x(t) and C is the weight for output y.\u003c/p\u003e","title":"First touch to mamba"},{"content":"Introduction: Recently, while acquainting myself with the new company, I encountered a piece of unusual code.\nIt seems quite straightforward. We start by declaring a base class with a private virtual function, which is then called by a public member function. Next, we derive a class from the base class and override the virtual function. This pattern is known as the Template Pattern. It defines the skeleton of an algorithm but allows subclasses to override specific steps without altering its structure. The code appears sound until we scrutinize the derived class.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 #include\u0026lt;iostream\u0026gt; #include\u0026lt;memory\u0026gt; class base { public: base() = default; void callPrivateFunction(){ privateFunction(); } private: virtual void privateFunction(){ std::cout\u0026lt;\u0026lt;\u0026#34;The call comes from a private function\u0026#34;\u0026lt;\u0026lt;std::endl; } }; class derived : public base { public: void privateFunction() override { std::cout\u0026lt;\u0026lt;\u0026#34;The cal comes from the overrided function\u0026#34;\u0026lt;\u0026lt;std::endl; } }; int main(){ base *ptr = new derived(); ptr-\u0026gt;callPrivateFunction(); derived *ptr_derived = new derived(); ptr_derived-\u0026gt;privateFunction(); return 0; } github.comhttps://github.com/StarGazer1995/code_examples/blob/main/cpp_examples/01_myth_of_override/src/main.cpp My initial thought was, \u0026lsquo;How can we override a private virtual function? It wouldn\u0026rsquo;t pass the compilation test.\u0026rsquo; However, I was surprised by the real compiler\u0026rsquo;s response: PASS.\nNot only does it override the private virtual function, but it also changes the access level of the function in the derived class.\nThis seems to violate coding rules. The virtual function shouldn\u0026rsquo;t be accessible by derived classes. However, it appears that the override has a higher priority than the public and private declarations. I sought clarification from ChatGPT but didn\u0026rsquo;t receive a satisfactory answer. After consulting the C++ reference, I found a solution on our favorite platform, Stack Overflow.\nen.cppreference.comhttps://en.cppreference.com/w/cpp/language/virtual#In_detail It\u0026rsquo;s surprising that the C++ committees have left this issue to developers, essentially telling us to \u0026lsquo;handle it ourselves.\u0026rsquo; This approach grants too much freedom to manipulate virtual functions, potentially leading to violations of coding rules. The committees should address this to prevent such issues during development. One possible solution could be to restrict the override syntax to the protected level, thus providing more control and reducing the risk of unintended violations.\n","permalink":"https://stargazer1995.github.io/tech/myth-of-override/","summary":"\u003ch1 id=\"introduction\"\u003eIntroduction:\u003c/h1\u003e\n\u003cp\u003eRecently, while acquainting myself with the new company, I encountered a piece of unusual code.\u003c/p\u003e\n\u003cp\u003eIt seems quite straightforward. We start by declaring a base class with a private virtual function, which is then called by a public member function. Next, we derive a class from the base class and override the virtual function. This pattern is known as the Template Pattern. It defines the skeleton of an algorithm but allows subclasses to override specific steps without altering its structure. The code appears sound until we scrutinize the derived class.\u003c/p\u003e","title":"Myth of Override"},{"content":"Introduction This is the very first touch for me to learn how to use cutlass and how it works. Until this moment, there is a little textbook teach us how to use cutlass and how to develop with it. So most of the paper I read are from Zhihu and official. As the first touch on cutlass, I would not dig deep into how to manipulate the cutlass.\nWhy cutlass? I try to avoid cliche. It just because the cutlass is the only high performance open-source computing library we can use on Nvidia’s chips. You need to master it if interested in HPC( high performance computing) or model deployment.\nThe first lesson Official examples are good for us, the beginner, to learn how to use the library. I started read the code from example of basic_gemm . The core of the example is quite simple: achieve gemm call.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 /// Define a CUTLASS GEMM template and launch a GEMM kernel. cudaError_t CutlassSgemmNN( int M, int N, int K, float alpha, float const *A, int lda, float const *B, int ldb, float beta, float *C, int ldc) { // Define type definition for single-precision CUTLASS GEMM with column-major // input matrices and 128x128x8 threadblock tile size (chosen by default). // // To keep the interface manageable, several helpers are defined for plausible compositions // including the following example for single-precision GEMM. Typical values are used as // default template arguments. See `cutlass/gemm/device/default_gemm_configuration.h` for more details. // // To view the full gemm device API interface, see `cutlass/gemm/device/gemm.h` //----------------------define problem dimension-------------------// using ColumnMajor = cutlass::layout::ColumnMajor; using CutlassGemm = cutlass::gemm::device::Gemm\u0026lt;float, // Data-type of A matrix ColumnMajor, // Layout of A matrix float, // Data-type of B matrix ColumnMajor, // Layout of B matrix float, // Data-type of C matrix ColumnMajor\u0026gt;; // Layout of C matrix // Define a CUTLASS GEMM type CutlassGemm gemm_operator; // Construct the CUTLASS GEMM arguments object. // // One of CUTLASS\u0026#39;s design patterns is to define gemm argument objects that are constructible // in host code and passed to kernels by value. These may include pointers, strides, scalars, // and other arguments needed by Gemm and its components. // // The benefits of this pattern are (1.) a structured, composable strategy for passing host-constructible // arguments to kernels and (2.) minimized initialization overhead on kernel entry. // CutlassGemm::Arguments args({M , N, K}, // Gemm Problem dimensions {A, lda}, // Tensor-ref for source matrix A {B, ldb}, // Tensor-ref for source matrix B {C, ldc}, // Tensor-ref for source matrix C {C, ldc}, // Tensor-ref for destination matrix D (may be different memory than source C matrix) {alpha, beta}); // Scalars used in the Epilogue //-------------------call gemm operation -------------------// // // Launch the CUTLASS GEMM kernel. // cutlass::Status status = gemm_operator(args); //--------------------retrieve gemm results-----------------// // // Return a cudaError_t if the CUTLASS GEMM operator returned an error code. // if (status != cutlass::Status::kSuccess) { return cudaErrorUnknown; } // Return success, if no errors were encountered. return cudaSuccess; } It only does 3 jobs: implement the gemm function based on the problem dimensions, call the function, and retrieve computing result.\nIt is quite simple but far from usable. It hard for programmers to maintain the code because they have to remember every input parameters. It is nice to have a data structure that wraps the data. In the cutlass, it follow the convention that use tensor as the basic data structure. In the example of cutlass_utilities we can define a tensor using the following code.\n1 2 3 4 5 6 7 8 // Defines cutlass::HostTensor\u0026lt;\u0026gt; #include \u0026#34;cutlass/util/host_tensor.h\u0026#34; // Defines cutlass::half_t #include \u0026#34;cutlass/numeric_types.h\u0026#34; using half_t = cutlass::half_t; using ColumnMajor = cutlass::layout::ColumnMajor; cutlass::HostTensor\u0026lt;half_t, ColumnMajor\u0026gt; A(cutlass::MatrixCoord(M, K)); We can access the data of tensor using the following api.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 /// Accesses the tensor reference pointing to data TensorView host_view(LongIndex ptr_element_offset=0) { return TensorView(host_data_ptr_offset(ptr_element_offset), layout_, extent_); } /// Accesses the tensor reference pointing to data ConstTensorView host_view(LongIndex ptr_element_offset=0) const { return ConstTensorView(host_data_ptr_offset(ptr_element_offset), layout_, extent_); } /// Accesses the tensor reference pointing to data TensorView device_view(LongIndex ptr_element_offset=0) { return TensorView(device_data_ptr_offset(ptr_element_offset), layout_, extent_); } /// Accesses the tensor reference pointing to data ConstTensorView device_view(LongIndex ptr_element_offset=0) const { return ConstTensorView(device_data_ptr_offset(ptr_element_offset), layout_, extent_); } Then, we can call the gemm operation.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 result = cutlass_hgemm_nn( M, N, K, alpha, A.device_data(), A.stride(0), B.device_data(), B.stride(0), beta, C_cutlass.device_data(), C_cutlass.stride(0) ); cudaError_t cutlass_hgemm_nn( int M, int N, int K, cutlass::half_t alpha, cutlass::half_t const *A, cutlass::layout::ColumnMajor::Stride::Index lda, cutlass::half_t const *B, cutlass::layout::ColumnMajor::Stride::Index ldb, cutlass::half_t beta, cutlass::half_t *C, cutlass::layout::ColumnMajor::Stride::Index ldc) { // Define the GEMM operation using Gemm = cutlass::gemm::device::Gemm\u0026lt; cutlass::half_t, // ElementA cutlass::layout::ColumnMajor, // LayoutA cutlass::half_t, // ElementB cutlass::layout::ColumnMajor, // LayoutB cutlass::half_t, // ElementOutput cutlass::layout::ColumnMajor // LayoutOutput \u0026gt;; Gemm gemm_op; cutlass::Status status = gemm_op({ {M, N, K}, {A, lda}, {B, ldb}, {C, ldc}, {C, ldc}, {alpha, beta} }); if (status != cutlass::Status::kSuccess) { return cudaErrorUnknown; } return cudaSuccess; } Driving manually:\nSmooth — it drives better than my father’s F18 Quite — Because it is a electrified vehicle Easy to handle — familiar BMW feeling Driving with ADAS[5AU]:\nThe feeling about 5AU is complex. I love it can save my energy on highway. But I would have to take some risks or failures we may encountered.\n[risk]: too close to vehicle when lane change. [failure]: going to another lane when curvature is large [failure]: do not change back after taking off. We would engage 5AU only on familiar highway. So, there is no over trust. When comparing with Tesla’s system, 5AU is not that smart.\n","permalink":"https://stargazer1995.github.io/tech/the-first-touch-on-cutlass/","summary":"\u003ch1 id=\"introduction\"\u003eIntroduction\u003c/h1\u003e\n\u003cp\u003eThis is the very first touch for me to learn how to use cutlass and how it works. Until this moment, there is a little textbook teach us how to use cutlass and how to develop with it. So most of the paper I read are from Zhihu and official. As the first touch on cutlass, I would not dig deep into how to manipulate the cutlass.\u003c/p\u003e\n\u003ch1 id=\"why-cutlass\"\u003eWhy cutlass?\u003c/h1\u003e\n\u003cp\u003eI try to avoid cliche. It just because the cutlass is the only high performance open-source computing library we can use on Nvidia’s chips. You need to master it if interested in HPC( high performance computing) or model deployment.\u003c/p\u003e","title":"The first touch on cutlass"},{"content":"Basically, v2x means vehicle to everything. But how we use this kind of technology into autonomous driving? Or, in other words, what kind of advantages does V2X provide?\nSome say the road side sensor can detect car crash and letting nearby vehicles know. And they believe that the RSU could detect pedestrians outside the detection range of vehicle as thus prevent crashing. People also argue that V2X could be used as a valuable add-on to autonomous system as it provides precise traffic information. It seems like V2X technology has a bright future.\nDespite a lot of articles buy in the future of V2X, I doubt it because of the world is real. V2X equipments are expensive and computing demanding. This drawback makes the implementation of V2X sensor impractical for now. Implementation requires a lot of resources for achieving, and the government is not interested. More, the latency of data transmission is another problem. We cannot transmit raw sensor data among vehicles. If we limit the latency into 100ms, we can do is transmit the object level information. And a objective reason is the security and privacy problem of the data, which requires a large effort from the government. So, V2X implementation could be impractical for right now.\n","permalink":"https://stargazer1995.github.io/pages/49efdfe7-7e90-49cc-8926-5ed3d3b23840/","summary":"\u003cp\u003eBasically, v2x means vehicle to everything. But how we use this kind of technology into autonomous driving? Or, in other words, what kind of advantages does V2X provide?\u003c/p\u003e\n\u003cp\u003eSome say the road side sensor can detect car crash and letting nearby vehicles know. And they believe that the RSU could detect pedestrians outside the detection range of vehicle as thus prevent crashing. People also argue that V2X could be used as a valuable add-on to autonomous system as it provides precise traffic information. It seems like V2X technology has a bright future.\u003c/p\u003e","title":"What about V2X?"},{"content":"Basically, v2x means vehicle to everything. But how we use this kind of technology into autonomous driving? Or, in other words, what kind of advantages does V2X provide?\nSome say the road side sensor can detect car crash and letting nearby vehicles know. And they believe that the RSU could detect pedestrians outside the detection range of vehicle as thus prevent crashing. People also argue that V2X could be used as a valuable add-on to autonomous system as it provides precise traffic information. It seems like V2X technology has a bright future.\nDespite a lot of articles buy in the future of V2X, I doubt it because of the world is real. V2X equipments are expensive and computing demanding. This drawback makes the implementation of V2X sensor impractical for now. Implementation requires a lot of resources for achieving, and the government is not interested. More, the latency of data transmission is another problem. We cannot transmit raw sensor data among vehicles. If we limit the latency into 100ms, we can do is transmit the object level information. And a objective reason is the security and privacy problem of the data, which requires a large effort from the government. So, V2X implementation could be impractical for right now.\n","permalink":"https://stargazer1995.github.io/pages/what-about-v2x/","summary":"\u003cp\u003eBasically, v2x means vehicle to everything. But how we use this kind of technology into autonomous driving? Or, in other words, what kind of advantages does V2X provide?\u003c/p\u003e\n\u003cp\u003eSome say the road side sensor can detect car crash and letting nearby vehicles know. And they believe that the RSU could detect pedestrians outside the detection range of vehicle as thus prevent crashing. People also argue that V2X could be used as a valuable add-on to autonomous system as it provides precise traffic information. It seems like V2X technology has a bright future.\u003c/p\u003e","title":"What about V2X?"},{"content":"About myself Here is Zhao Gong. I used to be an algorithm engineer at Plus and currently working for BMW as a software developer. I got my masters from the Technical University of Denmark. Github is one of important portals for me to connect to the world.\nBlog Pages\n页面链接\n","permalink":"https://stargazer1995.github.io/about/","summary":"\u003ch2 id=\"about-myself\"\u003eAbout myself\u003c/h2\u003e\n\u003cp\u003eHere is Zhao Gong. I used to be an algorithm engineer at Plus and currently working for BMW as a software developer. I got my masters from the Technical University of Denmark. Github is one of important portals for me to connect to the world.\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://app.notion.com/p/a5584e7fb26440b7b3fa268da9ee8560\"\u003eBlog Pages\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"/d88765d087ec4a77bf0fe76bf90043f9?v=3df8ea4719a14e1382fbee5611ba4a0f\"\u003e页面链接\u003c/a\u003e\u003c/p\u003e","title":"关于我"},{"content":"About me A Ph.D. candidate with a love of photography and programming.\nSite This site is build based on Hugo, Notion and notion2markdown-action.\nAll the images are hosted on Notion, and access to web through the temporary links valid for 1 hour.\nSo the GitHub Action will synchronize the pages every 10 minutes to keep it up to date!\nI don’t need to consider the cost of usage of GitHub Action because it’s a public repository.\nHere you can find the workflow of the GitHub Action Notion2Hugo.yml.\nContact Email: ddxid@outlook.com Feel free to comment.\n","permalink":"https://stargazer1995.github.io/about/","summary":"\u003ch1 id=\"about-me\"\u003eAbout me\u003c/h1\u003e\n\u003cp\u003eA Ph.D. candidate with a love of photography and programming.\u003c/p\u003e\n\u003ch1 id=\"site\"\u003eSite\u003c/h1\u003e\n\u003cp\u003eThis site is build based on Hugo, Notion and \u003ca href=\"https://github.com/marketplace/actions/notion2markdown-action\"\u003enotion2markdown-action\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eAll the images are hosted on Notion, and access to web through the temporary links valid for 1 hour.\u003c/p\u003e\n\u003cp\u003eSo the GitHub Action will synchronize the pages \u003ccode\u003eevery 10 minutes\u003c/code\u003e to keep it up to date!\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eI don’t need to consider the cost of usage of GitHub Action because it’s a \u003ca href=\"https://github.com/Doradx/doradx.github.io\"\u003epublic repository\u003c/a\u003e.\u003c/p\u003e","title":"About"},{"content":"","permalink":"https://stargazer1995.github.io/travel/osaka/","summary":"","title":"大阪 · 京都"},{"content":"","permalink":"https://stargazer1995.github.io/travel/puer/","summary":"","title":"普洱 · 景迈山"},{"content":"","permalink":"https://stargazer1995.github.io/travel/zhedong/","summary":"","title":"浙东大环线"},{"content":"","permalink":"https://stargazer1995.github.io/travel/dianxi/","summary":"","title":"滇西行 · 昆明 · 弥勒 · 保山 · 芒市"},{"content":"","permalink":"https://stargazer1995.github.io/travel/ganxi/","summary":"","title":"甘西大环线"}]