Simon Willison 用 Claude Code 构建声源三角定位系统 Beep Locator
Locating the source of a mysterious beep with Claude
Simon Willison 用 Claude Code 构建了 Beep Locator:Python 服务器加多台浏览器监听设备,通过 WebSockets 协同收音并三角定位房间内的神秘蜂鸣声,最终定位精度约 40cm,找到了需要换电池的一氧化碳报警器。
2026年11月9日
我家有个杂物间,里面堆满了上次搬家到现在还没拆封的纸箱。几周前,那个房间里开始间歇性地发出哔哔声。两次哔声之间隔得太久,站在房间里试图确定声源让人很抓狂,而我实在不想把每个箱子都翻一遍。于是我让 Claude Code 帮我搭建了 Beep Locator,一个利用散落在房间各处的多台设备对神秘哔声声源进行三角定位的软件系统。
这是 Beep Locator 运行一段时间后的样子:

你运行一个 Python 网络服务器来显示主界面,然后用二维码或网址把你能腾出来的尽可能多的设备连接上来充当监听器——我用了两台 iPad、一部手机、一台 MacBook Pro 和一台 Surface Ultra。
这些设备随后会互相播放声音来帮助估算它们各自的位置。这一步效果不太理想,所以我加了一个“粗略模式”,你可以在空间中拖动它们的图标来提供大致位置,然后再根据那些声音进行调整。
设置完成后,所有设备就开始监听哔声了!
我还加了一个拍手模式,这样我就可以在房间的不同位置拍手来测试它——在地图上显示为菱形。这让我确信它确实有能力定位声源。
哔声在地图上显示为一个 X,并在“已定位声音”日志中添加一条记录。你可以重放这些声音(依次从每台设备播放)来确认它们就是你要找的神秘哔声,然后点击“这就是神秘哔声”将其标记出来。
确认了神秘哔声的频率后,系统会持续监听它,测量两次哔声之间的间隔,并利用三角定位的结果锁定地图上最可能的位置。
系统如预期般工作了。它把哔声的位置定位到了约 40 厘米以内,然后我在那堆特定的箱子里翻找,发现了一个急需更换电池的老旧一氧化碳报警器。
工作原理
当我开始和 Claude 一起解决这个问题时,它很快就找到了 BeepBeep: A High-Accuracy Acoustic-Based System for Ranging and Localization Using COTS Devices,这是 Chunyi Peng、Guobin Shen、Yongguang Zhang、Yanlin Li 和 Kun Tan 在 2007 年发表的一篇论文。以下是该论文的摘要:
我们提出了高精度声学测距系统 BeepBeep 的设计、实现与评估。它在自发、临时和设备对设备的环境中运行,无需借助任何预先部署的基础设施。它是一个纯软件解决方案,仅使用最基本的商用硬件——一个扬声器、一个麦克风以及某种设备对设备通信方式——因此可以轻松应用于许多低成本传感器平台以及大多数市售现成的移动设备,如手机和 PDA。它通过三种技术的结合实现了高精度:双向感知、自录制和采样计数。
这听起来正是我们需要构建的东西!
Beep Locator 运行一个 Python Web 应用服务器来完成大部分工作。监听设备随后通过 WebSockets 连接到该服务器,并呈现一个请求浏览器麦克风权限的 UI。监听器主要通过录制最近 60 秒的音频缓冲来工作。它们还运行一个简单的蜂鸣声检测算法(见 detector.js),该算法使用快速傅里叶变换和高温滤波器来识别潜在的蜂鸣声。它将这些事件发送到主服务器。
当报告了一个蜂鸣声时,服务器会让一台设备播放一段短促的啁啾声(往返延迟最低的那台设备),然后要求每个监听器上传一段从蜂鸣声前约 0.6 秒到该啁啾声后 0.8 秒的音频片段。这段啁啾声可以让各个片段彼此对齐,这是定位蜂鸣声的关键步骤。
我是如何构建它的
我用 iPhone 上的 Claude Code Cloud 开始了这个项目,让 Opus 5.5 运行在额外思考力度模式下。这是那个共享的起始会话,它以针对一个新建的空 GitHub 仓库的如下提示开始:
Write out a problem.md file describing the problem we want to solve
There is a device beeping in a room and I cannot find it
I want to set up several devices - laptops, phones, iPads - around the room all listening at the same time and have them help triangulate where the beep comes from
There needs to be a Python web app which coordinates it all - one device shows a web page for the app, other devices join a URL which turns them into listeners - all via browser WebAudio and WebSockets back to the Python server app
Ideally I wouldn't need to manually input the relative locations of the devices - it would be amazing if they could play sounds to each other in order to locate each other in 2D space - is that even possible though?
这让我得到了 这个 problem.md 文件。Claude 在撰写该文件时找到并阅读了 BeepBeep 论文,该论文也在那个文件中有所描述。
这项研究看起来不错,于是我对它说:
Ok try and build it, add a mechanism so you can send new code to the listeners which they will then run automatically - that way I can set everything up in the room and then leave you alone to continue hacking and experiment while I do something else
这让我走到了这一步——系统的大部分已经构建完成,但还没有真正尝试运行过。
我把新仓库克隆到笔记本电脑上,启动了 Claude Code……然后 Fable 5.2 发布了,这个项目看起来正是对它进行全面测试的绝佳机会。
我让笔记本电脑上的 Claude Code 启动服务器运行,然后确认它既能看到正在发生的事情,又能在软件运行时对其进行实时修改。
这早已内置在软件中:Opus 5.5 在监听器上构建了一个可以经由 WebSocket 连接触发的 installModule() 方法,这意味着管理服务器可以在其任意客户端上执行任意新代码。
在某些设备上,监听麦克风的网页在每次页面重新加载时都会请求用户许可。这种热插拔模块机制意味着我们可以部署新代码,而无需逐个手动操作每台监听设备。
从那时起,我的参与主要是坐在笔记本电脑旁与 Fable 5.2 讨论正在进行的工作,偶尔请求一些新功能。以下是我运行的部分功能提示:
I think we need to make it so I can drag things around on the map in “rough mode”, where my job is just to put them roughly where they are, then switch out of rough mode and it attempts to get them accurate
这让我能够在地图上拖动监听器。
what’s a good way for me to test this I wonder? Can we have it listen for claps, then I could clap and it could identify the location of the clap? [...]
Claps should use a different symbol on the map than beeps
这增加了这样的功能:每当我拍手时,地图上就会显示一个与蜂鸣声不同的符号。
each symbol on the map should include a HH:MM:SS timestamp
这让我更容易分辨哪个符号可能对应哪个现实世界中的声音。
The log should show beeps and claps with their timestamps AND have a little play button which, when clicked, replays the recorded noise from each of the listeners in sequence (with clear text on screen showing which listener recorded which snippet) while temporarily turning off microphone recording while that replay plays
现在我可以回放声音,这使得识别哪段录音片段是我要找的神秘蜂鸣声变得容易得多。
There should be a button next to a recording for “This is the mystery beep” - then I can hit replay to see and then confirm it was the mystery beep if that’s the one I am looking for
Then the system can categorize noises in the future to see if they are likely that same mysterious beep and use that information to build a more accurate idea of where it is
此时我已经很接近了——我对蜂鸣声的来源有了大致可靠的判断,但如果我能把监听器重新布置到那个位置周围以获得更精确的定位,岂不是更好?
I want a feature for this, I don’t want to have to restart each listening device etc, I want to be able to click a “Reposition the devices” button which lets me switch into repositioning, then I click “Repositioned” and it puts me into Rough mode and asks me to roughly locate them, then I do that and click, then it starts up again. The previous session can be read-only viewed through the app.
由于我还有一台闲置设备,于是我说:
add a feature where the map includes a spot that is a suggestion for a location that it would be useful to add a listener at - based on data collected so far
给 Claude Code 装上耳朵
我认为这个项目最有趣的部分在于,我证明了给 Claude Code 装上耳朵是可行的。
Claude(目前)还没有原生音频输入,但它可以运行能够分析麦克风采集音频的 JavaScript 和 Python 代码。
我让它运行一个带 WebSocket 连接的 Web 服务器,连接多个监听设备,然后让它在这些设备上运行 WebAudio 麦克风,并将它们连接起来,以便通过该 WebSocket 向它们发送新的 JavaScript 代码来执行。
之后我基本上可以让 Claude 独自钻研这个问题,查询音频日志,并重新配置它的“耳朵”来帮助它解决问题。
这让我想起了几周前在 GitHub Universe 上听到的类似技巧,Martin Woodward 告诉我,他一直在调试 GitHub Universe 徽章电脑,方法是通过 USB-C 将它们连接到一台电脑上,然后用网络摄像头对准它们的屏幕,这样他的编程智能体就能判断更新是否正常工作。
想办法让编程智能体感知周围的世界是一件非常有趣的事情。
来源: Simon Willison · simonwillison.net