基于 JY901 与 STM32 的波浪测量系统【100010576】

基于 JY901 与 STM32 的波浪测量系统

1. 实习内容概述

(在本篇报告中出现的仅是我们实习项目的一个概述,关于具体的技术报告与上课笔记请参阅本文件夹中的“技术报告.docx”与“课堂笔记.pdf”文件,技术报告由小组共同完成,但每个人的因自身负责的模块不同略有侧重。我的技术报告重点放在 STM32 读取数据并存储进 SD 卡和频域积分处理数据两部分)

在 7 月 15 日至 7 月 31 日期间,我和其他 14 名同学于浙江大学舟山海洋研究中心进行了为期 2 周半的实习。在此期间,我们被分到了两组,接到了构建基于 JY901 的波浪参数测量系统的任务。在指导老师的帮助下,经过两周多的实践与应用,我们组最终完成了一个能够较为精准测量并计算相关波浪相关数据的系统,并在指导老师搭建的硬件平台上进行了调试与改进。

我们的最终任务是通过 JY901 和 STM32 进行波浪相关数据的计算。主要包括波高、波向、周期这三个方面的波浪属性。为了得到这个结果,我们首先需要通过 JY901 获得单片机随波浪运动过程当中的三轴加速度、三个方向的旋转角度,以计算得到波浪的位移曲线;再通过位移曲线,通过概率统计,得到波浪的周期和 1/3 大波波高。然后,通过旋转角度的概率分布,计算得到波向的最大可能方向。

a) 项目架构

在项目开始之前,我们组根据老师给的实习方案,设计了一个最初的系统框架。基于基本的海浪传感器框架,整体的传感器系统应该包括传感器层、数据传输层、数据交互层以及数据可视化层。如下图

但是在真实的实习当中,由于我们并没有时间来完成所有的设计。最终,我们最终只完成了传感器层和传输层的基本结构,并跳过了交互层的数据库结构,直接将最终数据进行处理,并做了简单的可视化。

最终项目架构图如下:

b) 项目介绍

在建立了最基本的系统架构之后,我们开始了每个子系统的构造。我们在 12 个工作日内,将整个任务分为四个阶段。第一阶段为数据检测层搭建阶段,主要进行 JY901 和 STM32 之间的信息交互;第二阶段进行数据传输层,主要从 STM32 的 SD 卡中读取相关信息,第三阶段为数据传输层,即使用 Matlab 进行初步数据处理,得到我们希望得到的数据;第四阶段为数据统计阶段。

i. 数据检测层:

数据检测层使用 STM32 读取 JY901 测量得到的 6 轴加速度/角度数据(加速度 3、角度 3、磁场 3,但是在我们的实验中没有用到最后 3 轴数据),并将读取得到的数据存入到 SD 卡中。整体的思路整体的下位机(STM32)程序构建如下:

其中,有几点需要说明:

  1. 变量 count 表示采样点数。例如,count=1024,表示我们将在 SD 卡中存储 1024 个数据。
  2. 程序设定默认的采样间隔为 200ms,可通过修改采样程序的延时时间来调整采样率,但需要注意 JY901 默认回传速率为 10Hz,如果采样间隔太短会读取到异常数据。(采样频率是一个大坑。。。其导致的异常数据,让我们 debug 了很久)
  3. Count 和采样频率(fs)共同决定了整体的程序运行时间。LED1 亮表示开始采样。LED1 灭同时,LED0 闪烁,表示采样结束,可以插拔 SD 卡进行数据读取。理论程序运行总时长 = count*1/fs
  4. 读取到数据转化为物理量后保存到字符串数组中再输出到文本文件中,这里需要用一个变量来表示得到的字符串长度防止字符串数组中未存储数据的区域在写入文本时产生乱码,这里读取到的加速度数据实际上是重力加速度 g 的倍数,且 Z 轴默认初始有 1 个 g 的加速度。

5.进行文本读写前后需要打开和关闭串口来进行数据传输。这是为了防止在写入文件的时候,程序因为串口传信的原因进入中断,导致写数据错误。

ii. 数据传输层:

数据传输层其实只是使用 SD 卡存储相关的数据。但是因为 SD 卡的存储方面出了比较多的 bug,因此单独列出来进行说明。首先,先说明 JY901 的解包函数。因为我们知道,在串口通信的过程当中,为了辨别传送数据的有效性,我们需要从缓冲区中读取到数据头。

  1. 读取 JY901 数据

即 JY901 发送的数据首先存入到缓冲区中,通过判断头两个数据来分析是否读取到正确数据以及读取到的数据类型再存入到设定好的结构体。在我们的代码中,我们只需要加速度和角度数据。数据头为 0x51,即为加速度数据,数据头为 0x52,即为角度数据。具体的读取步骤如下:

读取到数据头之后,我们就可以根据 JY901 数据读取到的数据转换为实际物理量。以加速度为例,加速度输出的步骤如下:

整体步骤,即从缓冲区中一个字节一个字节读取数据,先读取到桢头 0x55,就说明接下来会传输数据。再读取到数据头,即继续向下读取具体的加速度/角度数据,最后暂存在内存当中,准备存储到 SD 卡。

2.存储到 SD 卡

我们的 SD 卡使用的是 FatFs 文件系统。Fat file system 是一种专门为小型嵌入式系统所设计的文件储存方式。我们现在在一些 U 盘中还能看到类似的文件系统(不过 U 盘用的一般都是 exFAT,比较高端)。而我们的 SD 卡也就是使用这种文件系统。SD 卡的存储系统主要包括初始化、挂载、格式化、写入几个部分。如下为 SD 卡在进入文件系统写入之前的初始化过程:

在 STM32 当中,SD 卡的读写主要通过 FatFS 的库函数来完成。在我们的 project 中,用到的几种库函数如下:

f_open Open/Create a file
F_close Close an open file
F_read Read data from the file
F_write Write data to the file
F_lseek Move read/write pointer, Expand size

我们做的,就是从 STM32 的内存区读取之前写入的和 JY901 有关的变量,然后存入 SD 卡中。在这期间,遇到了很多奇怪的问题(例如写到一半切断电源会导致数据缺失,在写程序过程当中会出现文件乱码,在创建字符串 string 中如果有空字符在写入的时候也会出现乱码等等)。这一部分在技术报告中有所体现,这里也就不赘述了。

iii. 数据处理层

我们需要做的任务主要有 2 个。一是通过测量得到的向机加速度和加速度旋转角计算得到世界坐标系下的加速度,即用于计算和地平线的绝对加速度;二是通过处理得到的绝对速度,通过数字信号处理(DSP)的频域积分方法,得到绝对位移曲线。

  1. 坐标转换

测得的加速度是以 jy901 为参考系的加速度,我们需要把三轴加速度分别变换到大地坐标系,这样在静止的时候只有 z 轴加速度为 g,x、y 轴加速度为 0,消除了倾斜带来的测量误差。如图所示为一最简单的坐标转换。

第一步通过坐标转换,将相对于 JY901 的传感器的加速度,转换为大地坐标系。首先,通过 Z、Y、X 轴的三个旋转矩阵计算相对应绝对加速度。转换矩阵定义如下左图,加速度转换计算为下右图。

上式,ax,ay,az 为 jy901 测得的加速度,∠z、∠y、∠x 为 jy901 测得的角度。

这样就可以正确得到在大地坐标系下的加速度。其理解过程为从大地坐标系经过 z,y,x 的旋转后得到 jy901 坐标系,那么从 yj901 坐标转换的大地坐标实际上是反变换过程,最后一步是 x 旋转,那么通过定义 Rx 为反旋转将 yj901 坐标反旋转过来,之后依次是 y,z,旋转后得到的值为与大地坐标系同方向,这样就得到了大地坐标系下的加速度。

2.频域滤波、频域积分计算位移曲线

在研究振动运动的过程当中,由于收到传感器和实验条件的制约,在大多数情况下我们都只能测量得到加速度信号的数据。因此,为了得到速度和位移的数据,我们需要对所测量得到的数据进行积分处理。软件积分的形式主要包括时域积分和频域积分两种。时域积分主要利用梯形公式或者是 Simpson 公式进行求和,这样的做法的好处在于形式直观。而频域积分则是先对加速度信号进行傅立叶变换,将时域信号转换为频域信号。积分在频域中内以傅立叶变换形式计算,只需要进行正余弦信号互换即可。

a) 频域积分相对时域积分的优势

在加速度精度不高或者加速度数据不经处理的状态下,积分得到的位移量会有这一个明显的偏移累积误差。如下图是直接进行时域积分得到的数据。在这张图中,上半张图为位移数据,下半部分为速度积分(因为隔壁组做的是时域积分,这张图也是他们那边借用的,感谢隔壁组 hhh)。从图中可以注意到,虽然速度基本上在零点附近波动,且幅值也基本上一致。但是在直接进行积分之后,位移会出现相较于零点中心的偏移。而频域积分就能够解决这个问题。频域积分可以很武断地将 0 频分量滤除,也即公式中 的部分。这样的做法虽然有先验结果的嫌疑,但是确实是合理的。

这时,我们就把眼光放到频域积分中。在这次的 project 中,我们参照《matlab 在振动信号处理中的应用》(王济著)中第五章频域积分的部分,使用频域积分来计算。

b) 频域积分原理

我们组主要使用的是频域积分的方法。即在得到坐标变换之后的信号后直接进行 Fourier 变换,再利用 Fourier 变换的积分性质进行计算。在时域中的积分,转换为频率之后表现为除以一个 jw 并加上零频(直流分量)。具体表达式如下:

一次积分:

二次积分:

通过这样的方法,我们就可以将时域内的积分转换为频域中的除以 jw。而除以 j 的操作,实际是将信号表达式当中的 cos 和 sin 互换,即相位旋转 90 度。而后一半部分: 实际上是信号的直流分量。对于我们的实验来说,我们的理想波形(单个频率上)实际上是一个围绕着原点的简谐运动,因此理论上不会存在直流分量。

c) 具体步骤

i. 获得加速度数组

我们将采样点数设置为 1024 个点,得到如下的加速度曲线

ii. 计算 FFT。计算 FFT 得到的加速度频谱如下,使用 4096 点的 FFT:

iii. 加速度频谱滤波

由于以下几个问题,我们需要进行加速度滤波(具体分析见技术报告)

  1. 低频、高频分量。

低频分量主要来自于两个方面,零点漂移中带来的低频分量;实验过程中人为误差引入的高频分量(如手抖。。。)

  1. 零点漂移

一是传感器校准导致实际 a=0 时,测量得到的结果并不为 0;二是由于加速度传感器温度变化导致的零点漂移。

我们采用的滤波窗函数(位移和加速度都是)是汉明窗,窗函数如下图:

经过滤波得到的加速度频谱如下:

iv. 计算 w 数组

频域积分法中 w 数组的确定是一个重要的点。在我们的傅立叶变换公式当中,w 指的是数字频率。但是在真实的实验当中,采样计算得到、滤波器的频率设置其实都是模拟频率,因此需要进行一次换算。数字频率和模拟频率之间的变换关系如下:

而我们需要的是离散域的 w 数组。该当需要得到位移数据的时候,数组由以下公式确定:

需要注意的是,当 i 在 N/2-N 之间,其对应的频率分量其实是由-pi 到 0 搬移过来的。也就是说,w 数组应该关于 N/2 对称。若进行一次积分,w 数组如下左图。若两次积分,w 数组如下右图

v. 相位变换

根据以下公式,我们就能得到所需要的每个点的位移幅频曲线。

vi. 位移滤波、去趋势

我们再进行了一次位移频谱的滤波。一开始,我们认为位移频谱滤波并不重要,但是在得到实验数据之后,我们发现,在低频处仍然存在着非常大的频率分量(分析见技术报告)。于是我们还是进行了位移滤波,得到下图:

vii. IFFT 返回时域,得到位移曲线。

iv. 数据统计

最后,我们需要根据得到的位移曲线,通过统计学的方法计算出 1/3 大波波高与有效波高、波浪周期、波向等数据。

  1. 周期与波高测算原理

a) 整体思想:利用三轴加速度传感器获得不同时刻产生的垂直加速度,经过二次积分处理就可以得到海浪波面随时间的垂直位移变化,从而得到浮标随海浪运动的垂直轨迹。

b) 周期

采用上跨 0 点法—以波面“上升”至水位 0 点为起点和终点:波面上升到与水位 0 点处,作为起点,当波浪运行到 0 点以下,然后再次上升与 0 点的相交点作为终点。周期分为平均周期、有效周期。

c) 波高

同样采用上跨零点法,上跨起点与终点之间的时间为波周期,起点和终点之间波峰和波谷之间的垂直距离为波高。波高需要测量:平均波高、累计率波高、部分大波平均波高。如果观测 1000 个波,大小排列,第 10 个最大波高 2m,则其累计概率为 1% 的波高为 2m。一系列观测波高,将其按大小排列,其中最高的 P 部分求平均,称之为 P 部分大波平均波高,常用 P=1/3,P=1/10。

2.实验结果:

持续造波 600s,最大周期 6.17s,最小周期 4.87s,平台半径 42cm,采样频率 5HZ。

1% 累计率波高:1.4604m,出现于第 85 个波。

1/3 大波平均波高:1.0541m

1/10 大波平均波高:1.2595m

平均周期:6.1206s

观测到的波的个数:131 个

600s 波形图

前 120s 波形图

  1. 就某个环节或事情进行描述

a) 项目 bug 比想象中多得多。。。

说是说印象最深,但其实由于我们很长一段时间都在进行 project 的搭建,因此影响最深的事情肯定就是我们 bug 最多的项目子阶段了。。。当然其实每个子阶段都或多或少会有一定的 bug,我把这些 bug 基本上都记录在了技术报告里。这一部分只挑问题最多的讲。个人印象最深,或者说最让我心态大崩的部分,就是在做信号处理频域积分的时候。

从理论上来讲,频域积分做的事情其实就是将加速度做一个二次积分,以积分得到位移曲线。但是实际在操作过程当中,这个过程远远没有我们想象的那么简单。在最后一次聚餐的过程当中,李培良老师和我们说:“虽然你们做的只是一个最简单的加速度传感器,但我可以负责任的告诉你,以当今国内的水平,基本上没有一个在这方面做的万无一失的公司。”果不其然,在我们的 project 当中,我们光这一步就遇到了大大小小的问题,以至于我们最终完成这一步,几乎花了将近三天的时间才采到了我们想要的数据,并得到了令人满意的曲线。

在这一部分遇到的主要问题以及我们最后的解决方案:

i. 组内对于 DSP 相关知识的参差不齐

数字信号处理这门课其实是我们的学院课程的选修课,也就是说,有的同学学过了这门课,有的同学没学过这门课。这影响了组内成员共同前进的步伐。不过好在,这个问题可以通过小组分工来解决。我们组让学过相关课程的同学去完成频域分析,让没有学过相关课程的同学完成了时域分析。

ii. 滤波

在我们的 project 当中,滤波的好坏直接决定了我们最终得到曲线的好坏。

  1. 滤波时的低频高频选择

在滤波的时候,如果不滤除高频分量,会导致曲线变化过于频繁。而且高频分量当中有很大一部分来源于传感器的意外抖动,因此需要滤去,如果不滤掉,曲线可能会像如下图:

低频分量可能会到来一个长周期的运动趋势,这在真实的海浪中是比较常见的, 但是对于我们的实验器材,因为我们一直都是在围绕一个点进行圆周运动,因此也就不应该存在低频分量了。如果对低频分量不做处理,则可能出现下述结果:

我们注意到,在低频分量中,接近 0 频率附近会出现一个较大的分量。这个问题在之前的报告中被提到了很多次,也是时域滤波的一大缺陷。低频部分是对整体实验影响较大的一个分量,该分量是必须被滤除的,否则可能会导致非常严重的长周期趋势。

但是滤波低频高频可以说是整个流程当中极难处理的部分之一。我们组的做法比较简单粗暴,即去找一个前验周期(真实的海波一般会有一个周期范围),比如在摇机器的时候,记录每个周期的长度,从而就能够得到相关的前验频率。(例如记录到转的最短一圈为 5.4s,最长一圈 7.8s,低频就伟 1/7.8,高频就为 1/5.4)根据这个前验频率,我们就可以预先确定滤波的高低频分量,从而得到滤波器的相关参数。

  1. 滤波时候的窗函数选择问题

滤波时,窗函数的选择一直都是技术难点之一。在我们的实验中,我们希望得到较大的阻带衰减(因为低频分量必须被尽可能低的滤除,否则会导致极大误差),过渡带的参数指标并不是特别重要(因为在中央频率附近,我们也无法确定最准确的滤波分量)。因此我们选择衰减性能较好的汉明窗,并没有选择矩形窗。不过,其实这两者的平衡在我们的实验中并没有被极大地体现出来,因为我们的滤波器阶数 N 选的很高(N=51),因此性能还算比较优秀。但要注意的是,N 也不能选的太高,当 N 选的过高的时候,我们的滤波器出现了高低峰值差距较远的问题,这个问题到现在都不知道理论上的原因。

  1. 时域卷积还是频域乘法?

这个问题是我们实验中出现的一个比较严重的问题。实际上,负责频域分析代码撰写的两位同学在一开始在这一部分的处理是有区别的。我在时域上使用了 Filter 函数,做的是时域卷积的算法。而另外一个同学直接通过 FFT 变换到频域之后,与滤波器的频域变换相乘。于是得到了以下两种不同的结果。

可以注意到,虽然两组数据的趋势大致相同,但是在某些特定的点上,其实还上左图(时域卷积)波形?(如 350 右侧),虽然在大尺度的数据测量中并没有出现特别的的缺失,但是当旋转圈数不够的时候,给我们的统计带来了比较大的误差。这种区别在理论上不该出现,但我们在实际观察中的确发现了。因此我们还是统一用了频域相乘,并增大了统计时间。

iii. 最后得到的位移曲线幅值差距很大

同样可以看上一个问题中的那幅图。我们可以发现在不同的检测时间点上的位移曲线幅值差距还是很大的。这个 bug 让我们无从下手。因为我们发现无论是加速度还是位移曲线,都会出现类似趋势的幅度变化。于是,我们的解决方案还是增大采样时间。之前老师讲的,还是比较有道理的,能尽可能地采多的样,就要尽可能采多的样。

b) 第一堂 VHDL 课

除此之外,还有一件事让我印象深刻,准确的说是一堂课。李欣教授在给我们上硬件编程语言的导论课的时候,为我们介绍了微机(microprocessor)的发展历程和 intel 的发家史。相比较于后面几堂课,这堂课的内容并没有特别的硬核,并不涉及大量的类似于数字电路、微机原理的知识,但可以说是我听的最津津有味的一堂课。

这堂课上,李老师为了让我们对于微型计算机有着一些基本的概念,为我们介绍了 intel 如何从之前的一个小公司,抓住几次机遇,逐渐发展成为一个在 CPU 开发领域有着几乎主导地位的产业。同时,在介绍 Intel 的发展过程当中,一同介绍了 intel 公司的几款代表性产品,并介绍了其相应的结构/功能改进(从四位处理器 4004 到 8 位的 8008,再到 8080),帮助我们理解了处理器的发展和各种微机上的专业术语。(可能因为我微机学的时间有点遥远。。。当时的专业术语基本上都忘光了。。。)可以说这堂课非常引人入胜,而且还特别有趣,以至于我竟然把我很久丢掉的做笔记的习惯给捡回来了 hhh

3. 收获与体会

在这个架构当中,我个人涉及的部分主要包括存储层的 stm32F103 数据解包预编码与 SD 卡存储部分和数据处理中的频域积分部分。这两部分几乎贯穿了整个项目,因此个人觉得学到的知识还是比较多的,且因为本人一开始并没有像其他组员一样接触过嵌入式系统的相关内容,因此也算是第一次接触了 STM32 这款单片机的相关内容。虽然就同组同学的反馈来看,这次的实习对于他们来说还算是比较简单,但我觉得,虽然最终形成的成果并不是特别的巨大,但也算是一段有所收获的实习。

最后,还是有一个小小的建议。其实当初我报名这个实习的目的,主要是因为看到实习报告中对与实习中后段日程规划的内容。那时,我看到的规划包括数据库设计、数据可视化层等等的内容。而又因为本人对于数据科学这一块的内容比较感兴趣,所以当时毫不犹豫地选择了这个实习。然而,最后的修改的日程,几乎没有办法涉及到这一块的内容,因而个人其实有一段时间对这个事情还是有些耿耿于怀。但是后面,也了解到了海研中心其实也有这自己的苦衷,他们也有着自己的任务,不可能将大部分的生产精力分配到我们这里。然而,个人还是觉得可能还会有更好的处理方案。因为作为一个本科生,我们的确是没有足够的学术背景能够让我们直接投入到生产的队伍中去,但是,即使是大三学生,本科生还是处在一个寻找方向的阶段。说得直白一点,其实我们大部分都是不知道自己将来会走哪个方向,会往那个地方发展。因此,如果能够提供一个接触这些知识的机会,哪怕只是最简单的做个小小的作业,相信都能够得到比较好的效果,这样的收获可能会比单纯找一两个方向的老师来带我们很长一段时间,并直接完成一个大的项目要来的更周全。

♻️ 资源

在这里插入图片描述

大小: 13.5MB
➡️ 资源下载:https://download.csdn.net/download/s1t16/87404246

猜你喜欢

转载自blog.csdn.net/s1t16/article/details/130025327