超声波风速风向测量仪的设计与实践

简介

超声波风速风向测量仪是青站中最有趣的传感器之一。然而,对于我来说也是一个非常具有挑战性的任务,因为我在模拟电路设计方面几乎没有经验,而风速风向测量仪需要同时涉及模拟放大和大量的数据处理(起初我甚至不知道如何使用运放)。

Anemometer by Hardy Lau是一篇我学习了一次又一次的博客。这篇博客非常详细,并已经涵盖了构建自己的超声波风速风向测量仪所需的大部分知识。

工作原理简述:当超声波波(脉冲)在流动介质(空气)中传播时,波到达目标的时间会有所不同。正向和反向传播之间的时间差反映了介质流动的速度,即风速。通过在垂直方向上使用两对传感器,可以使用简单的三角法计算出风向。

与其他类型的风速风向传感器相比,超声波风速风向测量仪具有以下优势:

  • 超声波风速风向测量仪的体积小于旋转式传感器(如杯式风速风向计)。
  • DIY(自己动手制作)的难度适中,成本较低,而且Hardy的博客提供了很好的指导。
  • 它没有移动部件!移动部件不太容易DIY,特别是在防水方面。

方法

基础原理

ultrasonic_anemometer_principle

原理非常简单,声波在介质(空气)中的传播受到介质运动的影响。通过已知的传播路径和传播时间,我们可以计算介质的速度。

在上面的图中,我们可以看到风的运动BC与声波传播AB相加,形成了传播路径AC。

Lau
在其发布的所有相关方程式中提供了详细说明(使用了不同的符号表示)。

In C language:

1
2
3
alpha = atan(2*H/D);
v = H/sin(alpha)*cos(alpha)*(1/t1 - 1/t2);// wind speed
c = H/sin(alpha)*(1/t1 + 1/t2); alpha = atan(2*H/D);
v = H/sin(alpha)*cos(alpha)*(1/t1 - 1/t2);// wind speed
c = H/sin(alpha)*(1/t1 + 1/t2); // sound speed

为了测量风向,可以使用arctan2函数对两个垂直的方向进行计算。

1
beta = atan2(NS, EW);  // north->beta = atan2(NS, EW);  // north->south, east->west

实际问题,解决方案和折中方案

在现实中,事情通常不会按照我们的期望进行,特别是在涉及模拟电路的情况下。

机械设计

设计

我使用 Fusion 360 来设计硬件,并使用我的旧3D打印机来制造它们。

超声波探头位于顶部并向下方放置。
反射板是一个平整的表面。
电子元件和其他传感器位于探头上方的一个屏蔽盒内。

我甚至使用Simscale来做了一个气流模拟实验。
空气流速设置为30m/s,相当于~58节,空气流速相当于一场风暴的中心。

QingStation-CDF

如你所视,顶部和反射面之间的空气流动实际上快了约3m/s。我不确定我们是否需要在后续处理中考虑这一点。
由于我无法接触到风洞,所以无法在完美的实验环境中进行测试。

声程

正如简介中所示,理想情况下声波会沿着注明的路径传播。但实际情况则不同。

  • 有直接从发射换能器传播到接收换能器的声波。
  • 这些声波会混合在一起。
  • 3D打印的塑料是坚硬而轻巧的,非常适合放大声音。反射板也可能充当扬声器。

这在Lau的作品中并不是问题,因为他的风速风向仪是基于金属框架的。

anemometer_multiple_sound_path

这些声波可以在接收信号中看到。添加一些硬币作为配重可能有助于减小其他声波的幅度。

超声波换能器, 驱动

下图是第二版原理图(PCB v1.1), 将在下面的章节阐述一些细节问题。

使用一个低电压的4052模拟开关控制选择哪个通道作为输出,哪个通道用来监听回波。激励信号由定时器的PWM通道产生,而回波输出则经过运放放大并由ADC测量。

换能器

我从淘宝购买了几种不同的部件进行测试,它们分别是:

  • 一个 40kHz 10mm 的防水换能器(P/N: EU10AIF40H07T/R)
  • 一个 200kHz 10mm 的防水换能器(P/N: EU10PIF200H07T/R)
  • 一个 40kHz 16mm 的防水换能器 (P/N: NU40A16TR-1)
  • 几个HC-SR04类型的非防水换能器

带有零件号的前三个换能器具有以下类似的参数。

  • 声压 10V(0dB=0.02mPa) ≥106dB
  • 接收灵敏度 40KHz(0dB=V/μbar):≥-75dB
  • 电容值都在几个 nF 左右,取决于它们的直径。

我没有测试HC-SR04,因为它们比 10mm 的换能器要大得多。

最终选择了第一个,即 40kHz 10mm 的防水换能器(P/N: EU10AIF40H07T/R)。
因为它的尺寸小,有助于减小整体组装的大小。
与 200kHz 版本相比,它的价格便宜(价格只有后者的四分之一)。
高频率可以带来更短的脉冲,但 40kHz 的频率已经足够了。
它具有广泛的传播指向性(less than -3dB @ 30degree),这意味着我不需要像Lau调整换换能器的固定角度。
所有东西都可以平放简化了机械设计和组装过程。

关于频率选择:

理想情况下,脉冲应尽可能短。
我们通常发送 3~4 个脉冲。
f=40k, λ=8.4mm 脉冲宽度为 33mm
f=200k, λ=1.68mm 脉冲宽度为 6.72mm
两者都小于高度(5cm)。
波长越短越好,但信号也会在传播过程中更快地衰减。
此外,更高的频率对反射板材料也有不同的要求。

唯一剩下的问题是信号脉冲是否足够短,
以避免直接传播的信号(我们不需要)和反射传播的信号(我们需要)混合在一起的问题。

我没有考虑Lau博客中使用的muRata MA40E8-2,因为它已停产,而且价格也更高。

驱动设计

驱动设计是一个棘手的部分,有很多困难需要克服。

为了考虑尺寸和低功耗,我没有使用传统的MOSFET驱动器和变压器来驱动换能器。相反,就像旧款HC-SR04一样,我决定使用RS-232接口驱动器(例如MAX3232)生成RS-232电平(-5.5V表示1,+5.5V表示0)的方波信号。它应该能够提供至少10Vpp的信号来驱动换能器。这些3V的变化都在3V电源上运行,因此所有的集成电路和传感器都可以在单一电源轨上运行。

这些RS-232芯片有很多替代品,它们的驱动能力对于换能器来说已经足够好了(几千欧姆和几纳法的并联)。这里使用的是MAX3222,它提供了一个关断引脚,可以节省功耗,相比较常用的MAX3232来说。这些芯片价格低廉,封装紧凑,采用小型的MSOP封装。

然而,这些芯片引入了一个来自驱动器方面的干扰问题。

MAX3222通过一个1uF电容器从其中一个输出通道驱动换能器。在接收器(换能器)一侧,通过一组钳位二极管到地和电阻,来确保信号不会传回到驱动器一侧。此外,另一组串联在驱动器电容器上的钳位二极管应该阻止来自MAX3232的任何噪声。但事实并非如此。

因为MAX3232/3222是基于电荷泵方法产生负向和正向驱动电压的,所以无法获得平滑的输出电压,只能通过增加电容器来降低开关频率。

驱动电容器上的信号如下图所示:

尽管经过钳位二极管后,噪声已经“微不足道”了,甚至我的示波器也无法检测到,但仍然有一些噪声信号通过。这导致接收波形的失真。

这里是没有连接传感器时的波形,当连接传感器时,噪音会降低但仍然存在。同一通道表示驱动器(MAX3232)直接连接到接收器。交叉通道表示来自其他MAX3232或电源等未知源的噪声。

下图显示了由于驱动器一侧的噪声引起失真的实际信号。交叉通道的扰动可以忽略不计,但相同通道的扰动确实会影响回波波束的形状。请注意,这里显示的信号是在我将换能器粘贴到框架上之前采集的,因此信号振幅较大。当换能器粘贴到框架上时,失真效应增加,而信号幅度减小。这将导致在测量到达时间时遇到一些问题。

我尝试了多种方法,包括给MAX3232的电荷泵电容增加容量。这有助于将纹波频率从6.6kHz降低到约3kHz,但对于降低纹波的幅度影响很小。

后来我发现电荷泵的触发非常简单,一旦电压达到再充电阈值,它就会切换。非常类似于PDM模式的DC/DC转换器,低功耗,但噪声较高。这种噪声无法消除。

在第一版PCB(v1.0)中,我无法通过MAX3232消除这种噪声,因为两个MAX3232的电源由单个P-MOS控制。我无法在一个电源关闭的同时保持另一个电源以驱动换能器。因此,我设计了第二版PCB(v1.1),使用了MAX3222,当前通道在监听回波时,它可以进入关闭模式以停止电荷泵工作。希望这可以解决这些问题。

回波信号和放大器

(我很久以来很少接触模拟电路,这对于设计和调试肯定没有帮助)

当换能器接收到回波时,它在两个电极之间产生一个电压信号。
信号首先经过一个4.7k电阻,然后通过一个100nF电容器来阻隔直流信号。
接下来,信号经过一个模拟开关(4052,低电压版本),最后到达放大器。

由于我们使用单电源供电,4052不允许负电压信号通过。
作为替代,我们将每个通道的100nF电容器充电至虚地(1/2 Vreff),
然后开始发送脉冲并进行测量。
当通道切换时,需要等待一小段时间(5ms)使100nF电容器的充电至稳定电压。

放大器

对于放大器,我使用了最常见的LMV358双运算放大器。

在PCB v1.0中,只使用了一个级联放大器来放大回波信号,而另一个用于生成低阻抗的虚地。

放大器的增益仅设置为10倍,以至于我在ADC数据中无法看到信号。我高估了信号强度。我尝试将增益调整为约200倍以获得更清晰的信号。然而,信号读取范围仍然太小(在12位4096的ADC中约为100digits/pp)。

后来,直到我偶然在YouTube上看到了一个关于运算放大器增益、带宽乘积和转换效率限制基础的教程,我才意识到问题出在哪里。LMV358(以及其他所有运算放大器)在数据手册中列出的带宽是”单位增益”,也就是”增益-带宽乘积”,它并不能覆盖全频率范围。无论我设置多少,LMV358最大只能达到大约1MHz/40kHz = 25倍的增益。
更糟糕的是,我在反馈回路中加了一个22pF电容器用于RC滤波器,这也降低了增益。在40kHz时,22pF相当于180k欧姆。现在我知道为什么一开始看不到信号了,因为最后的带宽太小,过滤掉了所有信号。

不幸的是,当我学习到GBP参数时,PCB v1.1的制造和组装已经完成并正在漫漫长路中向我走来。在PCB v1.1中,两个运算放大器都用于放大回波信号。第一级被设置为低输入阻抗,以帮助信号在通道切换时更快地稳定(向电容器充电)。两级运算放大器还允许更高的总增益,同时仍然让40kHz的信号通过。22pF电容器被放置在第二级运算放大器上,在收到板子后需要拆焊。
虚地现在由电压分压器和一个大电容提供。新的电路在仿真中看起来很好。然而,在这个电路中,我们仍然无法测试200kHz的换能器,除非我更换为高带宽的运算放大器并放弃我之前购买的大量LMV358。

来自驱动的噪声

我认为钳位二极管中的小电容器导致驱动端的噪声到达了接收端。这一点在使用EasyEDA构建的模拟电路中也得到了验证。即使在干净的电源下,仍然可以观察到小幅度的噪声传输到接收端。1N4148二极管无法完全阻止来自驱动端的噪声。希望在PCB v1.1中能够解决这个问题,我已经将MAX3232更换为MAX3222以停止充电泵的工作。

PCB v1.1 Updates

对于PCB v1.1,通过关闭接收端驱动器,上述问题被消除。在采样过程中,测量值保持在几个位数内的稳定范围。

信号处理

信号处理的代码可以在专用的固件存储库中找到。

ADC setting

STM32L476的ADC非常强大,可以达到5Msps的采样率。在这里,我将采样率设置为1MHz,因为没必要设置得更高:

  • LMV358只有1MHz的GBP。
  • 即使达到5Msps,对分辨率的改进也不显著。
  • 通过线性插值可以实现亚分辨率的准确度(在信号处理部分有详细说明)。

在每个脉冲中,ADC采样1毫秒,收集正好1000个样本。使用DMA来减少CPU占用,同时确保采样的时候不受其他任务的影响。这对于高度在4cm10cm范围内足够了。

第一个回波到达的时间以及ADC需要采样的时间是多少?

假设高度(H)=5cm,间距(D)=4cm,声速(C)=336m/s

声音传播的距离是S = sqrt((D/2)^2 + H^2) * 2 = 10.7cm

在无风时,第一个脉冲大约发送后318us(t = 0.107 / 336)到达。
即使在H=10cm时,t=588us1000个样本也是完全足够的。

ADC的分辨率设置为12bit,这是没有进行任何硬件过采样的最大原始分辨率。

为了确保脉冲发送和ADC开始之间的时间是恒定的,在开始激励和开始ADC采样之间,使用RT-Thread的API暂停所有CPU中断。

信号处理

在放大器层输出的信号输出已经加了1/2 Vreff的偏置,其中Vreff等于MCU的Vdd 3.3V。因此,在没有信号时,信号输出应该在4095/2 = 2047.5左右。

在预处理阶段,

  • ADC采样值处理到零点附近并转换为浮点数。
  • 使用带通滤波器。
  • 最后归一化到最大值为1
    后来我发现数字带通滤波器可以有效降低环境引起的干扰信号。所以我回过头来添加了数字滤波器来平滑信号。这有助于减少检测到的错误峰值的数量。
    这里使用了一个带通Butterworth滤波器,带宽为40kHz载波频率周围的2kHz10kHz

下面的图像显示了10kHz带宽滤波器的通带。
对于信号精度浮点数计算,任何阶数超过4都已经不稳定了。(系数已转换为float32)
这里使用了110kHz带宽以获得最大的稳定性。

目前的滤波器是IIR类型的,但我不太喜欢在这里使用它,因为相位延迟在风速计算中扮演着非常重要的角色。
我们来看看是否需要将其替换为FIR滤波器,它在所有频率上具有恒定的相位延迟。

回波脉冲

在非编码激励中,回波脉冲的长度比激励脉冲要长得多。

这是我示波器记录的第一个回波。激励脉冲的长度为4个脉冲。

你可以看到回波中有很多脉冲,而不仅仅是我们发送的4个。回波的包络呈现出一个非常漂亮的菱形形状。我们可以利用这个形状来粗略测量传播时间。或者,如果信号没有像驱动器部分提到的那样失真,我们也可以简单地利用最大幅值来测量。

在实际应用中,我尝试了几种不同的激励方式,包括Lau建议的巴克码(barker-codes)。

// 单倍速率(40k)
//uint16_t pulse[] = {50, 50, 50, 50};

// 双倍速率(80k),用于控制+1或-1相位
// 这有点棘手--这是使其工作的唯一方法。
// STM32的定时器似乎要求第一个周期不是100%宽度。
// 因此,在每个脉冲中有一个虚拟的'L',如果末尾不是'L',则每个末尾还有一个虚拟的'L'。
// +1是'H, L'。-1是'L, H'
//uint16_t pulse[] = {L, H, L, H, L, H, L, H, L}; // 普通 -> ++++
//uint16_t pulse[] = {L, H, L, H, L, H, L, L, H, L, H, L}; // 普通抑制 -> +++--
uint16_t pulse[] = {L, H, L, H, L, H, L, L, H, L, H, L, H, L}; // 扩展抑制 -> +++---
//uint16_t pulse[] = {L, H, L, H, L, H, L, H, L, L, H, L, H, L}; // 普通抑制2 -> ++++--
//uint16_t pulse[] = {L, H, L, H, L, L, H, H, L}; // 巴克码4.1 -> ++-+
//uint16_t pulse[] = {L, H, L, H, L, H, L, H, L, L, H, L, H, H, L, H, L}; // 长巴克码4.1 -> ++++--++
//uint16_t pulse[] = {L, H, L, H, L, H, L, L, H, L}; // 巴克码4.2 -> +++-
//uint16_t pulse[] = {L, H, L, H, L, H, L, L, H, L, H,  H, L, L, H, L}; // 巴克码7 -> +++--+-
uint32_t pulse_len = sizeof(pulse) / sizeof(uint16_t);

在上述列表中,我能够得到最好结果的扩展抑制,它发送了3个正脉冲后跟3个负脉冲。这也是调制频率为13.3kHz的巴克码2。其他方法使信号平坦外,没有任何帮助。

原因可能是驱动器和换能器的限制,不允许更高的调制频率。

Update: 2021-05-13

之前提到的激励振幅太低了。
在风速超过30mph的测试中,它在大多数情况下无法捕捉到回波信号。
这里使用了一种新的激励方式:

#define H 98
#define L 0
#define P H,L
#define N L,H
const uint16_t cpulse[] = {P,P,P,P,P,P,N,N,N,N,P,P,N};

这个模式有6个正相位,将振幅由原来的原来的1950~2150200)增加到了1830~2270440)。
随后是一些负相位(起到阻尼作用)。

定位回波 - 峰值匹配

我们需要测量声束在路径中传播的时间。因此,我们需要以某种方式识别声束,并测量其传播时间dt

在这里,dt通过两个步骤来测量。

  • 峰值匹配 - 粗略测量声束的位置,精确度为半个周期,即12.5us
  • 零交叉 - 将准确度提高到亚数级 1us

我第一步使用方法被称为峰值匹配
首先,我们找到最大值作为声束的主峰值。
然后,我们检测主峰值之前和之后的一些峰值的转折点。
我们存储正峰和负峰(谷)的索引和值。

在搜索阶段,我们使用先前收集的参考信号峰(校准值)在新测量的信号峰上进行滑动,并根据每个峰值之间的差异计算出一组均方根误差(MSE)。
然后,我们可以使用最小的MSE来匹配偏移量(如果有的话)。
搜索范围为9±4;由于我们还统计了波谷值,因此实际范围为最大值之前的2个峰值和最大值之后的2个峰值。

正如您可能注意到的,我们只捕获了主峰值周围的几个峰值,其中主峰值是最大值。
但有时由于环境噪声或湍流等原因,最大值可能不是主峰值。因此,仅仅通过捕获最大峰值来定位声束是行不通的。

匹配信号的精度可以达到ADC采样周期时间的分辨率,即~1us @ 1Msps

这目前是最不稳定的部分,因为来自驱动器的干扰会影响对回波的检测。
有时这种方法会失败,并导致检测偏移一个周期,即25us

这里显示了一些(50个)’fault’的信号;这些ADC测量值是在无风时记录的,但无法计算(它们看起来很好)。
信号的最大峰值已标记。
您可以看到即使在完全无风的状态下,峰值也会出现错位。

实际应用中,在我安静、无风起居室中,大约50次测量中会出现1次不对齐的峰值测量,而在电视旁边则大约每5次测量中的就有1次不对齐的峰值测量。经过均方误差(MSE)峰值匹配后,大多数测量结果可以得到纠正,并仍然能提供良好的风速数据。在12小时的测量中,43200次测量中仅有340次测量出现误差,误差率为0.7%

但这未结束,进一步的纠正方法是使用从dt计算得到的声速。如果计算得到的声速与从温度估算得到的声速相差较大,则说明dt测量可能存在错误。一旦检测到错误,立即进行另一次测量。

Zero-Crossing detection and interpolation

为了进一步提高 ADC 采样周期的亚位分辨率,即 <1us,我们可以利用插值零交叉点来同时利用采样时刻和 ADC 测量值。

这种方法也是由 Lau 的博客 建议的。

零交叉的分辨率可以非常高。下面是几百个ADC原始测量值。你可以看到在接近零点的区域,信号呈现线性函数的形状,斜率约为30。这意味着在这种特定情况下,经过插值后,我们可以产生比原来1us30倍的分辨率,即33ns

斜率越陡,分辨率越高,但精度也取决于信号的分布。

这种方法需要对原始信号进行稳定的零位校准,该过程在第一步的预处理中进行。每个通道的零偏差在上电时,通过测量和平均没有发送激励的时信号进行校准,大约需要约 1 秒的时间。零位校准也可以在操作过程中进行,例如每小时或每发生 1℃ 温度变化时进行校准,以最大化准确性。

因为所有 4 个通道共享同一个放大器,所以它们也共享微小的偏置(如果有的话),这将被抵消掉。每个通道的实际零偏差都在 2046~2047 附近,非常稳定和准确。但偶尔会出现某个或所有通道存在一些偏差,如下图所示。东和西通道的偏移向上漂移。这个测量结果被故障检测所丢弃(西通道也有相当大的形变)。

在启动时,我们可以采集一组零交叉点,用于无风状态的校准。在后续的测量中,为了避免上述的偏差问题,我们采用动态归零方法。在每次测量开始之前,我们进行一次不发送激励信号的ADC测量,以获得实时零点,消除来自电源或其他因素的偏差。

对于每个通道,我们在每个回波的最大幅值周围插值6个零交叉点。因为峰值周围的波形是最相似的。这些零交叉点取平均并产生一个数值,代表这些交叉点的位置。我们发现它们的平均值非常稳定,因此不需要比较所有的零交叉时刻。

这样可以实现相当稳定的亚位级精度,至少在无风状态下是如此。一个简单的测试结果显示,原始测量值的标准误差为0.037us,已经非常接近我们计算的理论分辨率(相当于0.051m/s)。通过对几次测量进行平均,可以获得更好的精度。与其他参数一样,测量速率和过采样率可以通过配置文件进行设置。这种简单处理可以提供的精度水平已经非常令人期待!

下图显示了北-南方向的第一个风速测量结果。

Update: 2021-05-13

现在不需要启动时进行 ADC 零校准了。相反,我在每次采样之前添加了没有激励的 ADC 采样。这样我们可以在实际测量阶段之前进行动态零校准。因此,通过温度或电源引起的偏移可以被最小化。

脉冲压缩

脉冲压缩在雷达系统中非常常见,Lau的工作也使用了脉冲压缩技术,但我不确定他是如何使用的。如果峰值匹配方法的稳定性不够,我将尝试使用巴克码(barker-code)实现编码激励。

执行匹配滤波器(脉冲压缩)是相当简单,但它需要更多的CPU时间,因为它基本上是信号相关运算(类似于机器学习中的卷积)。如果需要,可以进行8/16bit定点数的量化,然后使用神经网络加速核来提高速度。

在初步测试中,对于巴克码4.1 +++-,MCU花费了46ms来计算所有4个通道(100 x 1000相关)。负载还可以接受,但与只需要6ms的峰值匹配方法相比,仍然花费了太多时间。我没有测试两个通道之间的全相关,例如北方与南方,这将导致最多1000 x 1000相关,比这个实验复杂10倍。当然,并不需要进行全相关,我测试了300 x 300的两个信号。每对通道需要大约40ms。

我不确定为什么在相关性之后,旁瓣仍然相当大,不如原始信号好。反转的信号(-)只被稍微降低了峰值,理论上应该被抑制或反转。

可能存在以下问题:

  • 调制频率过高,超出了换能器的处理能力。我尝试了40kHz20kHz,没有太大差别。
  • 或者我的处理方式有误。

Lau的换能器与我的换能器之间的主要区别在于封装材料。我使用的是铝制的,而他使用的是塑料制的。另一个潜在问题是驱动电压,我的电压只有10.5Vpp,而Lau通过一个变压器(未知)使用更高的电压。

也许现在先放一放这个问题。

Update: 2020-05-13

在查阅了许多文献后,我发现在高频率下调制激励信号非常困难。换能器的惯性会导致相位漂移至少4个或更多周期,具体取决于振幅。我只成功地在10kHz(即40kHz载波频率中的每4个周期)编码了相位。但是这种信号在强风中太微弱无法稳定。

尝试并失败的过程非常令人沮丧。在这段时间里,我与Lau进行了几次电子邮件的交流。感谢他的回复,进一步解释了他的设置,我终于明白了问题所在。他的风速仪比我建造的仪器具有更强的驱动能力,而且他的换能器是塑料外壳,惯性小于我使用的铝制外壳换能器。

提取风速和声速

最终,我们获取了4个通道时间差(dt)的可靠测量结果,结合机械参数(高度和倾角),我们可以使用Lau提供的方程计算风速。

风向也可以通过垂直的通道推断得出。

此外,我们还可以直接提取当前声速,而不是通过大气压力和温度来估算。

以下是C语言中的示例代码:

// 风速计算
ns_v = height / (sin_a * cos_a) * (1.0f/dt[NORTH] - 1.0f/dt[SOUTH]);
ew_v = height / (sin_a * cos_a) * (1.0f/dt[EAST] - 1.0f/dt[WEST]);
v = sqrtf(ns_v * ns_v + ew_v * ew_v);

// 声速计算
ns_c = height / sin_a * (1.0f/dt[NORTH] + 1.0f/dt[SOUTH]);
ew_c = height / sin_a * (1.0f/dt[EAST] + 1.0f/dt[WEST]);
c = (ns_c + ew_c) / 2;

// 航向角计算
course = atan2f(-ew_v, -ns_v) / 3.1415926 * 180 + 180;

一次夜间的静风测量显示,测量得到的声速与由温度估算的声速相当匹配。下面的测量温度范围为20.4℃25.6℃

故障检测和修正

来自环境噪声或其他板载电子器件的干扰源很多,有时会导致信号变形,正如我之前提到的那样。确实还有其他我无法发现的隐藏干扰源。

由于对低功耗的要求,我没有实现任何滤波器来检测基于先前测量的最终结果。因为如果设备需要休眠长达30秒,风速的差异可能非常大。

波束不对齐

在检测波束不对齐的情况下,如我在峰值匹配中提到的,
我还计算了MSE误差的历史记录,并且在每次MSE计算时以较低的速率进行更新。
为历史MSE添加了一个硬阈值,以设置最终的MSE阈值。
这种方法可以有效地过滤掉大约9/10的波束不对齐情况,这些情况不能通过简单的最小MSE恢复。
下面是一个演示,展示了动态MSE和最终阈值。

声速保护

还有一种最终的保护措施可用于检测错误,即从dt计算得出的声速。
声速测量非常稳定,可以通过其他传感器测量的温度进行估计。
通过温度估算的风速与通过dt估算的风速之间的差异通常小于2<m/s
差异阈值设定为5m/s

如果在任何通道中检测到上述任何错误,则当前测量将被丢弃,并立即进行新的测量。

调试

为了帮助调试,一旦检测到故障,4个通道的ADC测量结果将被记录到SD卡中。
实际上,上述部分显示的大多数故障数据都是从这些记录数据中绘制出来的。

我还编写了一些Python脚本来对数据进行后处理,以及一些Processing3脚本来实时显示数据。
它们非常有帮助。以下是Processing3脚本绘制4个通道的实时数据的屏幕录制。

Overall, I would like to repeat what Lau has said in his blog “building the anemometer is definitely not as easy as I thought.”

时间控制

对于每个通道,测量会在开始时切换模拟信号路径并使能专用的驱动器。
然后我们等待4ms,让信号路径稳定,并让驱动器充能至其补充电势(小于150us)。

我们进行一次空闲测量(无激励)以获取ADC测量的零点,这需要1ms

然后,通过DMA通道将编码脉冲发送到定时器,以产生超声波。同时,定时器还触发ADC开始采样。另一个DMA通道负责收集所有测量数据。这需要额外的1ms来完成。

总体而言,采样所有通道需要约25ms的时间。

一旦所有4个通道的数据采样完成,那么就会执行上述部分提到的所有数据处理操作。
整个处理过程需要19ms的时间。因此,每次测量需要19+25=44ms

测量和处理时间比我预期的要短。这要归功于峰值匹配方法,相对于其他相关方法而言,它的计算开销较小。

总体而言,我对处理时间非常满意,小于50ms的处理时间允许MCU和模拟电路休眠更长时间以节省功耗。
一旦检测到故障,我们仍然有足够的时间来进行更多的采样,以获得正确的测量结果。或者,在功耗不是问题的情况下,可以每秒进行高达20倍的过采样,以获得更高的精度。

处理方法总结

通过使用上述的处理方法,风速测量仪现在能够产生相当稳定的测量结果。上述的1小时测量是在一个有风、晴朗下午进行的,没有出现任何不可恢复的故障。

主要的困难包括:

  • 选择和生成合适的脉冲信号。
  • 在校准和实时测量中定位波束都很困难。
  • 故障检测。决定何时修正信号以及何时重新进行测量。

这些部分是我付出了大部分努力的地方。

但处理方法一旦确定下来,单一的固件在我构建的4个不同硬件上都能轻松运行。

Keep out zone(禁飞区)

在开发过程中,我发现任何存在于该区域内的物体都会影响声波束的形状,从而影响或导致风速测量失败。

  • 在1号区域存在的物体会导致所有测量失败。
  • 在2号区域存在的物体会导致校准失败,但上述算法仍然能够产生稳定的测量结果。

当一只鸟停在反射板上时,很有可能造成测量完全失败。

实验

车载测试

我使用一个直径为88mm的磁性车顶安装支架将QingStation安装在汽车车顶上。我使用了一些3D打印的零件和一个38 x 2.2cm的PVC管将其抬高了一点,这样车辆产生的压缩气流就不会对其产生太大影响。从车顶到QingStation顶部的实际高度为55cm。汽车的高度为1410mm,所以总高度略小于2m

第一次测试:

第二次测试:

GNSS速度和风速测量的比较。

风速测量结果高于GNSS速度。

  • 这可能是因为位置仍处于车辆压缩气泡内,空气速度被压缩和增加。
  • 或者可能是计算有问题。
  • 或者可能是前方车辆的气流。
  • 或者是风。

下面是风速测量和30秒平均值的图表。30秒平均值更有意义。

大部分时间,我们停在道路中间等待5或6辆过往的列车。幸运的是,我们是队列中的第一辆车,所以我享受了观看它们的时间。

anemometer_car_experiment3

高速公路测试

我打印了一个较短的支杆以降低重心。计划是在高风速下测试风速计,因为这从未尝试过。

我只安装了雨量传感器镜头,将其安装在通风孔上。然后…很快就遇到了大雨。

不幸的是,SD卡在刚开始遇到降雨时就出现故障。在大雨中,QingStation继续发送MQTT消息,直到我们到达目的地(Durdle Door)为止。

  • 风速计在雨中大约运行了30分钟后,出现了故障。
  • 在电路板打湿后,所有的数字传感器都停止工作。
  • 气压计在几分钟内发生故障,然后恢复正常。
  • 电池电压在连接器打湿后几分钟内急剧下降至3.1V。
  • RTC时钟停止工作(晶振元件潮湿)。
    不确定是否发生了电化学反应或ADC引脚被润湿(也许这也是风速计失败的原因)。
  • SD卡上有一些随机的文件/文件夹被写入。数据文件都没问题,但日志文件出错。
  • 日志记录失败,MQTT消息未保存,所以我不知道出了什么问题。

一切干燥后,它们都恢复正常工作。

anemometer_motorway_rain

日志显示在小于72km/h20m/s)的风速下,测量结果呈现完美的跟随性,但在108km/h30m/s)时开始出现故障。
这也可以从错误代码(未列出)中看出。风速计在高速(30m/s)时开始有些挣扎,几乎每3s报告一次错误。但它仍然可以在1s的记录周期内提供良好的测量结果。但是有3次测量失败,报告的风速甚至达到200km/h。

我认为这个结果是可以接受的,因为大于20m/s的风速并不是始终存在的。

由于安装点较低,风速计受到的空气加速效应比之前的低速测试更大。我认为这在正常范围内。但由于我无法使用到风洞来校准传感器,所以我无法进一步进行标定工作。


超声波风速风向测量仪的设计与实践
http://clomg.github.io/2023/06/15/ultrasonic-anemometer-design-and-practice/
作者
CLoMg
发布于
2023年6月15日
更新于
2023年6月16日
许可协议