社交距离测试的本质是判断两部 Android 手机之间的物理距离是否低于某个安全阈值。手机没有配备专门的距离传感器,但蓝牙低功耗广播可以提供一个间接的测量手段:一台设备周期发送 BLE 广播包,另一台设备扫描并读取接收信号强度指示 RSSI。RSSI 的单位是 dBm,通常为负值,距离越近数值越接近 0,距离越远数值越小。利用无线信号在自由空间中的衰减规律,可以把 RSSI 换算成估算距离。

这种方案不需要摄像头,也不依赖 GPS 定位,室内外都可以工作。它的核心并不是获得厘米级精度,而是以较低成本识别两台设备是否进入设定的距离范围。由于 Android 手机普遍支持 BLE,因此用 RSSI 做社交距离测试在工程上容易实现。接下来会从测距模型、扫描实现、阈值策略和误报优化几个方面展开。
一、RSSI 测距模型与误差来源
对数路径损耗模型是蓝牙 RSSI 测距最常用的公式。它假设信号强度随距离按对数关系衰减,表达式可以写成:RSSI = A - 10 × n × log10(d)。其中 A 表示距离 1 米时的参考 RSSI 值,n 是环境衰减因子,d 是估算距离。将公式变形后可以得到 d = 10^((A - RSSI) / (10 × n))。如果 A 取 -59,n 取 2.5,当扫描到 RSSI 为 -75 dBm 时,估算距离约为 2.14 米。
这个模型看起来简单,但实际误差并不小。A 值会因手机品牌、蓝牙天线设计、芯片发射功率差异而不同。两台不同型号的手机在 1 米距离测到的 RSSI 可能相差 6 到 10 dBm,这足以让距离估算从 1 米变成 2 米以上。n 值同样不稳定,空旷环境接近 2,办公室有隔断和家具时可能升到 3 甚至更高。人体本身也会吸收和反射 2.4 GHz 信号,如果手机放在口袋里或被手掌握住,天线附近的环境发生改变,RSSI 会出现明显波动。
多径效应是另一个难以消除的误差来源。BLE 广播信号会在墙壁、地面、金属表面之间反射,扫描端可能同时收到直射信号和多个反射信号,叠加后 RSSI 值可能忽高忽低。因此,单次 RSSI 读数并不能直接作为可靠距离依据。工程上通常需要采集多次样本,再通过滤波算法得到相对稳定的距离估计值。
二、Android BLE 扫描与距离计算
在 Android 上实现社交距离测试,通常需要申请蓝牙扫描权限。Android 12 及以上版本使用 BLUETOOTH_SCAN 权限,低版本还需要 BLUETOOTH 和 BLUETOOTH_ADMIN。运行时动态申请权限后,通过 BluetoothLeScanner 开始扫描。扫描回调中每一个结果都包含 ScanRecord 和 rssi 字段,其中 rssi 就是本次扫描到的信号强度。
下面的代码展示了一个简单的 BLE 扫描与距离计算流程。为了识别特定设备,可以约定广播包中包含固定的 UUID 或厂商数据。扫描到目标设备后,取出 RSSI,代入公式计算估算距离,并交给后续的滤波模块处理。
public class DistanceScanner {
private static final int TARGET_RSSI_1M = -59;
private static final double PATH_LOSS_EXPONENT = 2.5;
private BluetoothLeScanner scanner;
public void startScan() {
ScanFilter filter = new ScanFilter.Builder()
.setServiceUuid(ParcelUuid.fromString("0000xxxx-0000-1000-8000-00805f9b34fb"))
.build();
ScanSettings settings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.build();
scanner.startScan(null, settings, scanCallback);
}
private final ScanCallback scanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
int rssi = result.getRssi();
double distance = calculateDistance(rssi);
DistanceFilter.getInstance().addSample(distance);
}
@Override
public void onScanFailed(int errorCode) {
// 可以在这里处理扫描失败,例如蓝牙未开启
}
};
private double calculateDistance(int rssi) {
double ratio = (TARGET_RSSI_1M - rssi) / (10.0 * PATH_LOSS_EXPONENT);
return Math.pow(10, ratio);
}
}
该示例中的 UUID 是占位值,实际使用时需要替换成双方约定的服务 UUID。扫描模式选择 SCAN_MODE_LOW_LATENCY 可以获得更快的回调,但功耗较高;如果距离测试需要长时间运行,可以改用 SCAN_MODE_BALANCED 或 SCAN_MODE_LOW_POWER。
代码里的 calculateDistance 方法直接把单次 RSSI 转成距离,实际工程中还需要考虑设备校准。校准方法通常是在 1 米距离处让两台手机保持静止,记录多组 RSSI 的平均值作为 A 参数。如果测试手机型号固定,可以把校准值写入配置文件;如果面向未知设备,则需要先进入校准流程,让用户将两部手机放在 1 米距离并保持几秒,系统自动更新参考值。
三、距离分级与滤波策略
社交距离测试通常不需要输出精确米数,而是输出距离等级,例如大于 2 米为安全,1 到 2 米为提醒,小于 1 米为警告。这样处理的好处是容忍较大的 RSSI 误差,同时给用户更直观的反馈。阈值设定需要结合实际场景,如果测试环境较为空旷,可以将警告阈值设为 1.5 米;如果室内隔断较多,信号衰减更快,可能需要把警告阈值调整到更严格的范围。
单次 RSSI 跳变很容易造成距离等级在安全和警告之间来回切换。为了避免频繁误报,可以在距离计算之后加入滑动窗口滤波。常见做法是保存最近 10 到 20 次距离样本,取中值或均值作为当前距离。中值滤波对偶发异常值有较好的抑制作用,均值滤波则能让距离变化更平滑。
public class DistanceFilter {
private static final int WINDOW_SIZE = 15;
private final LinkedList<Double> samples = new LinkedList<>();
public synchronized void addSample(double distance) {
samples.addLast(distance);
if (samples.size() > WINDOW_SIZE) {
samples.removeFirst();
}
}
public synchronized double getMedianDistance() {
if (samples.isEmpty()) {
return Double.MAX_VALUE;
}
List<Double> sorted = new ArrayList<>(samples);
Collections.sort(sorted);
int middle = sorted.size() / 2;
return sorted.get(middle);
}
public synchronized String getDistanceLevel() {
double distance = getMedianDistance();
if (distance < 1.0) {
return "警告";
} else if (distance < 2.0) {
return "提醒";
} else {
return "安全";
}
}
}
上面的滤波器每次取窗口中位数作为最终距离。窗口大小需要根据扫描间隔来定。如果扫描频率是每秒 1 次,窗口 15 表示大约 15 秒的平滑窗口;如果扫描频率更快,可以适当增大窗口。另一个改进思路是引入阈值滞后,当前状态为警告时,只有距离回到 1.3 米以上才切换为提醒;当前状态为安全时,只有距离降到 1.8 米以下才切换为提醒,这样可以避免在阈值附近反复跳变。
对于不同手机功率差异,单台设备的 A 参考值不能套用到所有设备上。更稳妥的方法是让两台设备都广播,并分别计算对方信号的 RSSI,再取两侧估算距离的平均值。比如 A 手机测到 B 的距离为 1.2 米,B 手机测到 A 的距离为 1.0 米,最终可输出 1.1 米。如果只有一侧扫描,就必须先对该型号手机做参考 RSSI 校准,否则同一阈值在不同设备上会得出完全不同的等级。
四、降低误报与测试优化
RSSI 本身的波动会带来两类问题:一是距离远时偶尔出现强信号,导致误报为近距离;二是距离近时信号被遮挡,导致漏报。前者可以通过中值滤波和阈值滞后解决,后者则需要提高扫描频率和增加多方向测试。实际测试时,不要把手机只放在桌面同一位置,可以分别模拟手持、放入口袋、背部相对、屏幕相对等姿态,记录不同姿态下的 RSSI 分布。这样可以更清楚看到设备天线方向对测距结果的影响。
扫描频率直接决定功耗和响应速度。BLE 扫描越低延迟,回调越密集,距离变化响应越快,但耗电也越明显。对于社交距离测试,一般 1 秒到 2 秒的扫描间隔已经足够,因为两个人靠近或远离不是一个瞬间事件。可以使用 Handler 或协程定时启动与停止扫描,而不是持续扫描,例如扫描 5 秒、休眠 3 秒,以平衡功耗和实时性。还需要处理后台限制,Android 8 以后后台应用扫描 BLE 的频率会被系统限制,如果测试页面退到后台,扫描间隔可能变长。
从方案边界看,基于 RSSI 的社交距离测试只能作为辅助提醒,不能用于医疗级别的接触追踪。它的主要价值在于快速实现、低成本验证距离判断逻辑,以及在没有专用硬件的情况下给出一个可用的距离等级。如果业务需要更高精度,可以结合超声波、UWB 或二维码扫码等方式,但额外硬件和实现复杂度都会上升。对大多数普通 Android 应用来说,先把 RSSI 采样稳定下来、做好校准和滤波,往往比追求复杂算法更能有效降低误报。
最后要注意权限和隐私合规。蓝牙扫描会涉及附近设备信息,应用需要向用户说明用途,并在不需要时及时停止扫描。测试完成后应释放 BluetoothLeScanner 相关资源,避免后台持续耗电。合理的距离测试设计,应该是在用户体验、识别准确率和资源消耗之间找到可接受的平衡点。
Android社交距离蓝牙RSSI测距距离阈值修改时间:2026-09-26 23:14:27