如何从零开始实现TDOA技术的 UWB 精确定位系统(2)

这是一个系列文章《如何从零开始实现TDOA技术的 UWB 精确定位系统》第2部分。

重要提示(劝退说明):

Q:做这个定位系统需要基础么?

A:文章不是写给小白看的,需要有电子技术和软件编程的基础

Q:你的这些硬件/软件是开源的吗?

A:不是开源的。这一系列文章是授人以"渔",而不是授人以"鱼"。文章中我会介绍怎么实现UWB定位系统,告诉你如何克服难点,但不会直接把PCB的Gerber文件给你去做板子,不会把软件的源代码给你,不会把编译好的固件给你。我不会给你任何直接的结果,我只是告诉你方法。

Q:我个人对UWB定位很兴趣,可不可以做出一个定位系统?

A:如果是有很强的硬件/软件背景,并且有大量的时间,当然可以做得出来。文章就是写给你看的!

Q:我是商业公司,我想把UWB定位系统搞成一个商业产品。

A:当然可以。这文章也是写给你看的。如果你想自己从头构建整个系统,看了我的文章后,只需要画电路打板;构思软件结构再编码。就这样,所有的难点我都会在文中提到,并介绍了解决方法。你不需要招人来做算法研究 。如果你想省事省时间,可以直接购买我们的电路图(AD工程文件),购买我们的软件源代码,然后快速进入生产环节。(网站: https://uwbhome.top

基站固件设计-时钟同步

时钟同步原理

我们在前面已经说过,对于TDOA技术来说,各个基站需要有统一的时间,这是一个难点。时钟怎么同步呢?

假设一个定位区域有A/B/C/D四个基站,我们另外再把拿一个基站CS作为时钟源,定期发送时钟同步包。这个时钟同步包的结构如下:

typedef struct ieee154_broadcast_clock_sync_frame {
    uint8_t frameCtrl[2];           // 0, 2, frame control bytes 00-01: 0x01 (Frame Type 0x01=date), 0xC8 (0xC0=src extended address 64 bits, 0x08=dest address 16 bits)
    uint8_t seq8;                   // 2, 1, sequence_number 02
    uint8_t panID[2];               // 3, 2, PAN ID 03-04
    uint8_t destAddr[2];            // 5, 2, 0xFFFF
    uint8_t sourceAddr[8];          // 7, 8, 64Bits EUI地址
    uint8_t messageType;            //15, 1, Message Type = RTLS_MSG_TYPE_CLOCK_SYNC
    uint8_t seq64[8];               //16, 8, 发出的测距消息序号, 比 seq8 有更大的最大值
    uint8_t timeStamp[8];           //24, 8, 时间戳
    uint8_t fcs[2];                 //32, 2
} BROADCAST_CLOCK_SYNC_MESSAGE;

这是一个DW1000的典型的UWB数据包。这是一个广播类型的包,其中有几个重要字段,timeStamp这是时间戳,也就是A基站发送这个包的时刻。

当,A/B/C/D四个基站收到这个同步包后,记下这个时间戳和收到这个包的时刻(本地时间戳),这样,我们就有两个时间戳了。

过一会,CS再发一个同步包。某个基站例如B基站收到后,再记录下CS基站的远程时间戳和本地收到的时候戳,又得到两个时间戳。

假设CS发出这两个包之间间隔100ms,也就是两个同步发送时间间隔100ms。那么在正常情况下,B基站收到这两个包时,本地的时间间隔应该也是100ms。实际上并不是!

因为两个基站的DWM1000使用的晶振会因为各种原因,频率并不会完全相同,总会有一些差异。

两个基站之间的时钟差异是多少呢?

deta = (ST2 - ST1) - (RT2 - RT1)。其中 deta 是差异,ST2是第二个包的发送时间,ST1是第一个包的发送时间,RT2是第二个包的接收时间,RT是第一个包的接收时间。

差异率是 Ratio = deta / (ST2-ST1)

这样,开始时间知道了,时钟的差异率也知道了。我们就可以把任意一个本地时间戳转换为以CS为准的时间戳。

当某一个标签发出UWB定位数据包时,A/B/C/D四个基站都收到这个包,A/B/C/D把收到时的本地时间戳转换为以CS的时间为基准的标准时间戳,大家都把这个时间戳送到定位引擎,定位引擎得到4个时间,根据它们的差,就可以计算出标签的坐标了。

看到这里,你心应该会有一个疑问。CS发出的同步数据包的发送时刻,是UWB数据包离开CS内的DW1000芯片的一个闸门那一刻。UWB信号然后经过了芯片内部线路,再经过发射天线发射到空中,到达B基站的天线,在B基站的天线内部传输,经过一些芯片内部线路,到达B基站中的DW1000的那个接收闸门,那个时刻是接收到的时刻。这个过程需要不少时间,这个时间怎么得到?在DW1000芯片的手册中有介绍,我们要考虑发射天线延迟/接收天线延迟。

回答是,不用管它。

我们假设,B基站的DW1000与天线之间通过一条长长的射频电缆连接,时钟同步包到达B基站的天线后,再经过长长的电缆才到DW1000芯片。当然,标签发出的定位数据包也一样,到达B基站的天线后,再经过长长的电缆才到DW1000芯片。假设电缆增加一段,导致无线电波要在电缆中多跑1ms,当然,时钟同步包和定位包都要多花1ms在路上。如果我们在计算B基站接收时钟同步包时的时间戳时把这1ms考虑进去,那么在定位引擎计算时间差的时候,要把标签的定位包多花的这1ms扣出。所以这两个包在电缆中所花的时间,在计算公式中会被抵消。

在安装基站时,我们关心"基站安装在哪个位置",其实并不真的关心基站的位置,而是关心基站天线的位置。天线的位置才是最重要的。时钟同步包到达天线,定位数据包到达天线,基站本身在哪里并不重要。

这也是TDOA的优势之一,不用关心天线延迟,不需像TOF基站和TOF标签那样,在出厂前要做天线延迟标定。

上述的分析,是在使用单独的基站作为时钟源的场景下。我们最初的系统就是使用单独的时钟源。时钟源的硬件和固件与正常的基站完全相同,根据配置作为时钟源还是作为普通基站。作为时钟源的时候,功能只有一个,就是定期发送时钟同步包,时钟源的DW1000只发射不接收;作为普通基站的时候,接收时钟源发出的时钟同步包和标签发出的定位包,普通基站的DW1000只接收不发射。后来,为了降低成本,我们把两个功能合并,普通基站既可以作为基站又可以作为时钟源,平时处于接收状态,定期切换到发射状态发送一个时钟同步包后立即又切换回接收状态。这样,可以节省一个单独的时钟源。

如果基站同时作为时钟源,那么作为时钟源的这个基站,它的天线延迟在计算时就会有影响。对于时钟同步包来说,它是发射延迟;对于定位数据包来说,它是接收延迟。DW1000内部发射延迟和接收延迟差异不大,计算时可以忽略不计。但是,如果有外接PA/LNA,发射和接收经过的路线差异比较大,就需要考虑到这个异常了。

我们最初设计整个系统时,曾经考虑整个系统使用统一的时间。大的定位区域,可以划分为多个小的定位区域。我们可以部署一个根时钟,各个区域有一个分时钟,从根时钟同步时间,逐级同步时钟就OK。

然而事情不是这么简单,最主要的问题是误差。时钟之间的误差我们是无法排除的。

例如,根时钟R的时间同步到A1/B1,然后A1同步到A2,B1同步到B2。然后我们会发现A2和B2之间的误差会比较大。因为时钟同步本身就有误差,多级同步会导致误差积累,最后的误差越来越大。

最后,我们发现整个系统统一时间意义不大,只需要某个小的定位区域内的几个基站之间统一时间就可以了。

细心的同学肯定注意到,前面定义的时钟同步包结构中,一个字段seq64。这是一个64位整数。DW1000芯片内部定义有一个8位的seq,放在帧控制字段后。我们发现,1个字节表达数据包序列号,最多只能256个,很快就会回卷。有时,我们关心更大时间尺度内的数据包,就无法分辨了。所以,我们单独设置了一个64位的数据包序列号。

另外,DW1000的时间戳的有效数据是40位,其单位约为15.6ps。

后期,精益求精的考虑,我们新定义了一个精练一些的时钟同步包。

typedef struct ieee154_broadcast_mini_clock_sync_frame {
	uint8_t frameCtrl[2];			// 0, 2: frame control bytes 00-01: 0x01 (Frame Type 0x01=date), 0xC8 (0xC0=src extended address 64 bits, 0x08=dest address 16 bits)
	uint8_t seq8;				// 2, 1: sequence_number 02
	uint8_t panID[2];			// 3, 2: PAN ID 03-04
	uint8_t destAddr[2];			// 5, 2: 0xFFFF
	uint8_t sourceAddr[8];			// 7, 8: 64 Bits EUI地址
	uint8_t	messageType;			// 15,1: Message Type = RTLS_MSG_TYPE_MINI_CLOCK_SYNC
	uint8_t	seq32_3[3];			// 16,3: 发出的测距消息序号的高 24 位,即高 3 字节
	uint8_t timeStamp[5];			// 19,5: 时间戳, 40 Bits
	uint8_t fcs[2];				// 24,2:
} BROADCAST_MINI_CLOCK_SYNC_MESSAGE;		// 以上合计 26 字节

seq没有必要搞成64位,32位足够了,前面有一个seq8,那么后面只需要3个字节就可以了,所以把seq64改为seq32_3;时间戳的有效位只有40位,所以不需要使用64位。

新的时钟同步包大小由34个字节减小到26个字节。

因为无线信号本质上是广播,同一时刻空中只能有一个声音,如果出现其它的声音,就是干扰。所以,我们要尽可能的减小信道的占用,传送的数据包越小,占用的时间越短。可以腾出时间,以容纳更多的标签;并且,数据包占用信道的时间越短,被干扰的几率也就越小。

基站共用-与多个时钟源同步时钟

因为UWB业务的定义就是近场无线通信,几乎所有国家的无线电管理部门对UWB的信号功率都有严格限制,不允许大功率发射。因为UWB占用的带宽太宽了,如果功率大了,它就变成干扰源了。

原厂DW1000最大功率发射时,以850K的速率通讯时,覆盖范围大约200米~300米范围。实际上,这个最功率是超标的。如果按照无线电管理局要求的信号强度,通讯距离大概会在20米以内。

无论如何,当我们要对一个很大的区域进行定位,经常需要把它划分为多个小的定位区域。我们假设有一个100米x100米的区域,划分为4块25米x25米的4个区域。假设每个区域使用4个基站,那么4个区域就需要4x4=16个基站。

如果基站可以共用,定位区域边缘的基站可以供相邻的区域共用,那么我们只需要有"田"字的每个顶点安装一个基站,只需要3*3=9个基站就可以了。

使用尽量少的基站,可以减少用户的投资,也减小项目施工难度。

前面我们所述的时钟同步,基站可以多记录几个时钟源的时间戳,就可以达到与多个时钟源同步时间的效果。

typedef struct tag_ClockSource_Sync_Info {
	uint8_t clockSourceId[8];
	double factor;
	double lastFactors[CLOCKSOURCE_SYNC_INFO_LAST_FACTOR_NUM];
	int64_t offset;
	int64_t localStartTime;
	int64_t lastSyncTime;
	SAMPLE_KALMAN_FILTER_PARAMETER kfp;
	SAMPLE_RC_FILTER_PARAMETER rfp;
	double ppm;
	double lastFactorAcc[CLOCKSOURCE_SYNC_INFO_LAST_FACTOR_NUM];
	double factorAcc;
} CLOCKSOURCE_SYNC_INFO;

上面这个结构是记录了某个时钟源的时钟同步数据。

#define CLOCKSOURCE_SYNC_INFO_NUM	15			// 记录 15 个时钟源的同步信息
CLOCKSOURCE_SYNC_INFO clockSourceSyncInfo[CLOCKSOURCE_SYNC_INFO_NUM];

上面这个数组记录多个时钟源的数据。

具体允许与多少个时钟源同步,这与MCU的RAM有关。在现实中,其实也不会有太多的区域共用同一个基站,15个基本上不同能了。

时钟同步的干扰因素

如果每次收到时钟同步包时,都计算时钟的差异率,那么会发现它一直在变化。我们期望得到一个稳定的,至少一段时间内变化不大的差异率。但是,这不可能!有太多"干扰"因素。

晶振的频率变化

DW1000的晶振是时钟的源头。对晶振的频率生产影响的因素很多,温度湿度变化/电压变化都会影响晶振的频率。晶振两端的pad电容的容量变化,也会对频率产生影响(有些电路就是通过调整这两个pad电容的容量来调整电路的频率),温度湿度电压的变化对这两个电容也会产生影响。

DW1000的Datasheet中建议"Crystal (38.4 MHz +/-10ppm)","TCXO (optional use in Anchor nodes. 38.4 MHz)"。DWM1000模组把DW1000芯片封装在一个铁盒子中,对晶振频率的稳定是有一定好处的,因为在铁盒子中有一定的保温效果,可以让晶振的温度不会快速受到空气流动的影响。

其实,频率不准并不可怕。频率偏差再大,我们也可以通过计算校准。我们怕的是无规律的快速变化。

无线电波传输速度的变化

无线电波在空气中传输,空气作为介质,是不稳定的。空气的温度/湿度/气压等都会影响无线电波在空气中的传输速度。

曾经有一次,我把开发板固定在三角架上,放在我办公桌旁边,我在观察时钟同步差异率的变化。刚好有一位同事从旁边路过,我马上看到曲线发生剧烈变化。这也是我在前面基站电路设计部分强调外壳很重要的原因。

保持时钟同步稳定性

因为影响时钟同步差异的因素很多,所以我们要想办法保持稳定。有几个办法:

缩短时钟同步周期。我们把时钟同步周期设定为250ms。较短的时钟同步周期,可以保持当前的时钟同步数据较新,与最新的各种影响因素匹配。

卡尔曼滤波或者其他方法滤波。总体上,频率的变化是类似正态分布的一些随机点:频率有一个总体的变化趋势,如果我们时钟的差异率画出来,它是总体上是一条逐步变化的曲线,但是每次计算出来的点,并不在正好落在曲线上,而是在曲线附近。我们可以使用滤器得到曲线上的值。

使用滤波的效果很在限,最重要的还是缩短时钟同步周期。因为通过滤波器得到的值,并不是真的实际情况,而是一个理想值。比如,因为空气温度变化导致电波从时钟到基站的传输速度变化了,我们得出一个排除这个影响的值,但实际上这个值意义不大。因为标签发出的定位包的速度也一样会受到影响,应该一道排除空气变化影响才行,如果只对时钟同步排除,而标签发出的定位包不排除,那么计算结果肯定会有较大的偏差。

原来打算基站固件设计写一篇就搞定,结果发现仅是时钟同步就写了这么多内容。看来要写的东西还是有点多。慢慢写吧。

相关推荐
Rjdeng2 个月前
【AI大模型】赋能儿童安全:楼层与室内定位实践与未来发展
人工智能·安全·ai·室内定位·楼层
BD8NCF4 个月前
如何从零开始实现TDOA技术的 UWB 精确定位系统(6)
uwb·室内定位·tdoa·rtls·超宽带
Ankie Wan4 个月前
UWB论文:Introduction to Impulse Radio UWB Seamless Access Systems(2):脉冲;超宽带;测距;定位
uwb·测距·物理层安全·到达时间·干扰·802.15.4z
源码技术栈7 个月前
【Java】UWB高精度工业定位系统项目源代码
java·人工智能·源码·高精度·定位系统·uwb·超宽带
BD8NCF8 个月前
如何从零开始实现TDOA技术的 UWB 精确定位系统(5)
uwb·室内定位·tdoa·rtls·超宽带
YRr YRr8 个月前
DWM1000 中断与STM32外部中断
stm32·单片机·嵌入式硬件·uwb·dwm1000
BD8NCF8 个月前
如何从零开始实现TDOA技术的 UWB 精确定位系统(4)
uwb·室内定位·tdoa·rtls·超宽带
简简单单做算法8 个月前
基于WIFI指纹的室内定位算法matlab仿真
算法·matlab·室内定位·wifi指纹
BD8NCF8 个月前
如何从零开始实现TDOA技术的 UWB 精确定位系统(3)
uwb·室内定位·tdoa·rtls·超宽带