WIFI信号状态信息 CSI 特征提取篇之活动片段提取上(五)

在之前的数据处理环节中,用CSI Tool收集到的原始数据信号,经历了数据解析、降噪、插值的处理步骤,变成了干净、完整的信号片段,这是后续做更进一步分析的基础。

在开始阅读本篇博客前,需要说明两个重要的点:

  • 在先前的代码中,为了能够一次性提取出所有重要的信息,振幅和相位数据都进行了计算,被存储到result_matrix这个数组中,但是从本篇博客开始,将仅围绕着振幅值进行分析。具体提以什么值进行分析,请结合自己的研究对象以及相关文献。
  • 后续的特征提取以及研究思路都是基于人类活动识别,CSI感知所涵盖的领域较多,而特征的提取与识别对象本身息息相关,因此需要对比自己所研究的领域,同本博客的是否有相似性。

本环节是特征提取环节,起承上启下的作用:对上,应着数据处理完毕的信号,但是还不能直接进行分析,因为此时信号片段过长,对于活动识别而言,存在非许多目标片段(例如失败不规范的动作、休息间歇等);对下,具体采取何种活动片段提取策略,需要配合后续采取的活动识别算法进行(深度学习/机器学习,CNN/RNN/LSTM等等),不同的算法适配不同的数据形式,例如CNN一般用于识图,不需要关注时间顺序,LSTM则要求保留时间关系等等,所以本博客后续仅介绍几种分类思路。

以CNN识图这种非常简单粗暴的一种识别方法为例,由于最后是需要图像形式的数据集,因此本环节,经历了以下几个步骤:
①标记活动点→②切割信号片段→③筛选活动片段→④转化为图像帧

具体怎么实现上述步骤呢,这里参考了下面这一博客的做法。这个github是我做CSI识别时候的救星,虽然是LSTM算法,但是里面的代码很全,只要提供信号数据文件和标注文件,就可以自动去进行一系列后续的操作。本环节后续许多处理代码都是参考这个博客,在其代码基础上作了一定的修改。
GitHub - ermongroup/Wifi_Activity_Recognition: Code for IEEE Communication Magazine (A Survey on Behaviour Recognition Using WiFi Channle State Information)

在上面这个博客中,一共有三个重要的Python文件,其顺序和作用是:
cross_vali_data_convert_merge.py:从指定路径中的CSV文件中导入数据,并根据一定的条件将数据处理成滑动窗口的形式,然后将处理后的数据保存到新的CSV文件中。
cross_vali_input_data.py:读取前述代码处理好的CSV文件,对数据进行降采样、预处理,根据活动阈值进行筛选,并将处理后的数据存储到字典中。
cross_vali_recurrent_network_wifi_activity.py:LSTM算法部分。

下面将按照代码,详细介绍每一步需要准备的文件和处理流程,实验细节以之前博客所设定的参数为例。

① 标记活动点

在之前的环节中,得到的是一段信号片段result_matrix,由于只需要振幅数值,那么现在result_matrix这个数组的维度是(N,91),N为数据包的个数。图像化展示一段信号的振幅图像如下:

可以看到圈起来的片段波动较大,对应着志愿者实际发生活动,而在活动的间歇间,振幅波动则很小,因此振幅的方差可以作为是否发生活动的一种判定方式,有相关文献是根据此进行自动化的活动片段提取。但是并不是所有的活动数据都能采用这个思路,不怕麻烦的话,人工对照视频监控对数据文件进行标注是最准确的方法,可以手动淘汰不标准的动作。不过改方式要求在先前做实验的时候,记录每次采集数据开始的时间,因为CSI信号数据本身并未存储现实生活中的时间,只有相对时间信息。举例,一段长度为10000的CSI信号,采样频率是1000Hz,可知该段信号记录了10s的活动,如果采集开始时刻已知,即可知道这段信号对应的真实时间段。

首先,将数据处理环节得到的振幅值以csv格式进行存储,每个实验样本的CSI振幅为一个csv文件,期内有90*N个数据,90表示子载波数量,N为该段实验样本的数据包个数,命名为input系列文件。与之相对的,每个实验样本还需要有一个标注文件,命名为annotation系列文件,其内数据维度为1*N,每行的内容即是对应信号数据文件的标注内容。强烈建议从一开始就对所有文件进行规范命名,如下图所示(input/annotation_志愿者代号_活动类型代号_数字编号):

   

② 切割信号片段

如代码所示,整理好的input系列文件和annotation系列文件被放在filepath1和filepath2中,然后依次被送进dataimport函数处理。先统一用滑动窗口的方式把一段长的实验样本切割为若干个等长的小样本,代码中设置的小样本长度为0.5s。同时为了便于管理,每种分类的类别都以数字编码。统计每一样本内部各个类别出现的频次,若有类别频次大于设定的活动阈值,则标记该样本为相应类别。输出的文件为xx和yy的csv文件,前者是重整后的信号数据,维度是(M,90*500),90*500即一个样本的所有振幅数据,M是切割后的样本数量;后者是标记文件,维度是(M,10),在这个矩阵中,发生活动的时间点,对应列数会被标记为“1”,否则第一列为“2”。

需要注意的是,由于CNN算法不关注时间顺序,所以这里对实验样本的顺序并没有做出严格管理,只是简单粗暴的按照类别把实验样本放在一起。

import numpy as np,numpy
import csv
import glob
import oswindow_size = 500  # 滑动窗口大小
threshold = 80  # 活动阈值
slide_size = 400 # 滑动窗口每次滑动长度,建议设置大小不超过window_size# 定义数据导入函数dataimport
# 三个输入参数:filepath1 表示输入文件路径模式,filepath2 表示注释文件路径模式,slide_size 表示滑动窗口的大小。
def dataimport(filepath1, filepath2, slide_size):xx = np.empty([0,window_size,90], dtype=np.float16)yy = np.empty([0,10],float) # 10=分类数量(9)+1###Input data####data import from csvinput_csv_files = sorted(glob.glob(filepath1))for f in input_csv_files:print("input_file_name=",f)data = [[ float(elm) for elm in v] for v in csv.reader(open(f, "r"))]tmp1 = np.array(data, dtype=np.float16)x2 = np.empty([0, window_size, 90], dtype=np.float16)#data import by slide windowk = 0while k <= (len(tmp1) + 1 - 2 * window_size):x = np.dstack(np.array(tmp1[k:k+window_size, 0:90]).T)x2 = np.concatenate((x2, x),axis=0)k += slide_sizexx = np.concatenate((xx,x2),axis=0)xx = xx.reshape(len(xx),-1)xx = xx.astype(np.float16)###Annotation data####data import from csvannotation_csv_files = sorted(glob.glob(filepath2))for ff in annotation_csv_files:print("annotation_file_name=",ff)ano_data = [[ str(elm) for elm in v] for v in csv.reader(open(ff,"r"))]tmp2 = np.array(ano_data)#data import by slide windowy = np.zeros(((len(tmp2) + 1 - 2 * window_size)//slide_size+1,10))k = 0while k <= (len(tmp2) + 1 - 2 * window_size):y_pre = np.stack(np.array(tmp2[k:k+window_size]))# 所非分类的系列活动liedown = 0write = 0read = 0walk = 0clean = 0armtrain = 0squat = 0run = 0jump = 0noactivity = 0for j in range(window_size):if y_pre[j] == "LieDown":liedown += 1elif y_pre[j] == "Write":write += 1elif y_pre[j] == "Read":read += 1elif y_pre[j] == "Walk":walk += 1elif y_pre[j] == "Clean":clean += 1elif y_pre[j] == "ArmTrain":armtrain += 1elif y_pre[j] == "Squat":squat += 1elif y_pre[j] == "Run":run += 1elif y_pre[j] == "Jump":jump += 1else:noactivity += 1# 根据活动时间点占该滑动窗口片段的比例,判定是否为活动片段if liedown > window_size * threshold / 100:y[int(k/slide_size),:] = np.array([0,1,0,0,0,0,0,0,0,0])elif write > window_size * threshold / 100:y[int(k/slide_size),:] = np.array([0,0,1,0,0,0,0,0,0,0])elif read > window_size * threshold / 100:y[int(k/slide_size),:] = np.array([0,0,0,1,0,0,0,0,0,0])elif walk > window_size * threshold / 100:y[int(k/slide_size),:] = np.array([0,0,0,0,1,0,0,0,0,0])elif clean > window_size * threshold / 100:y[int(k/slide_size),:] = np.array([0,0,0,0,0,1,0,0,0,0])elif armtrain > window_size * threshold / 100:y[int(k/slide_size),:] = np.array([0,0,0,0,0,0,1,0,0,0])elif squat > window_size * threshold / 100:y[int(k/slide_size),:] = np.array([0,0,0,0,0,0,0,1,0,0])elif run > window_size * threshold / 100:y[int(k/slide_size),:] = np.array([0,0,0,0,0,0,0,0,1,0])elif jump > window_size * threshold / 100:y[int(k/slide_size),:] = np.array([0,0,0,0,0,0,0,0,0,1])else:y[int(k/slide_size),:] = np.array([2,0,0,0,0,0,0,0,0,0])k += slide_sizeyy = np.concatenate((yy, y),axis=0)print(xx.shape,yy.shape)return (xx, yy)#### Main ####
if not os.path.exists(r"...\input_files"):os.makedirs(r"...\input_files")clients = ['A', 'B', 'C', ..., 'Z'] # 实验志愿者代号
activities = ["LieDown", "Write", "Read", "Walk", "Clean", "ArmTrain", "Squat", "Run", "Jump"] # 活动类别代号for client in clients:for activity in activities:# 导入信号数据文件和标注文件filepath1 = fr"...\INPUT\input_{client}_*{activity}*.csv"filepath2 = fr"...\ANNOTATION\annotation_{client}_*{activity}*.csv"if glob.glob(filepath1) and glob.glob(filepath2):# 输出切割重整后的样本文件至指定地址outputfilename1 = fr"...\input_files\xx_{client}_{window_size}_{threshold}_{slide_size}_{activity}.csv"outputfilename2 = fr"...\input_files\yy_{client}_{window_size}_{threshold}_{slide_size}_{activity}.csv"x, y = dataimport(filepath1, filepath2, slide_size)with open(outputfilename1, "w") as f:writer = csv.writer(f, lineterminator="\n")writer.writerows(x)with open(outputfilename2, "w") as f:writer = csv.writer(f, lineterminator="\n")writer.writerows(y)print(f"{client}_{activity} finish!")else:print(f"No files found for {client}_{activity}, skipping.")

Jupyter中运行如下图所示:

友情提示,如果采样频率很高,中间文件的大小会很大,注意内存管理。 

输出得到的文件如下图所示。这份代码的作用简单来说,就是把长的信号段切割为小的样本,并根据标记频次,判定小样本属于哪一类活动。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2982113.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

使用ClickHouse、Grafana和WarpStream规模化的解决可预测成本的日志留存

本文字数&#xff1a;13234&#xff1b;估计阅读时间&#xff1a;34 分钟 作者&#xff1a;Dale McDiarmid & Ryadh Dahimene 审校&#xff1a;庄晓东&#xff08;魏庄&#xff09; 本文在公众号【ClickHouseInc】首发 简介 在生产环境中操作任何复杂的技术堆栈而没有适当…

2024年低碳技术与污染控制技术国际学术会议(ICLCTPCT 2024)

2024年低碳技术与污染控制技术国际学术会议(ICLCTPCT 2024) 2024 International Conference on Low carbon technology and pollution control technology 一、【会议简介】 2024年低碳技术与污染控制技术国际学术会议&#xff0c;是交流科研成果的绝佳平台。 这次会议将汇集世…

如何利用美国站群服务器实现有效的SEO优化策略?

如何利用美国站群服务器实现有效的SEO优化策略? 在当今数字化时代&#xff0c;SEO优化对于网站的可见性和吸引力至关重要。站群服务器作为一种有效的SEO策略&#xff0c;可以通过多个相关联的网站在不同服务器上的部署&#xff0c;增强网站的权威性和链接多样性。尤其是在利用…

vector的使用(部分接口)

1.vector的使用 1.1vector的定义 (constructor)构造函数声明接口说明vector()无参构造vector (const vector& x)拷贝构造 1.2vector iterator 的使用 iterator的使用接口说明begin end获取第一个数据位置的iterator/const_iterator&#xff0c; 获取最后一个数据的下一个位…

【做算法学数据结构】二叉树的层序遍历【二叉树】

文章目录 题目二叉树二叉树描述二叉树的java描述和前序遍历、后序遍历、中序遍历 题解总结以及二叉树应用场景 题目 给你二叉树的根节点 root &#xff0c;返回其节点值 自底向上的层序遍历 。 &#xff08;即按从叶子节点所在层到根节点所在的层&#xff0c;逐层从左向右遍历…

力扣HOT100 - 98. 验证二叉搜索树

解题思路&#xff1a; class Solution {public boolean isValidBST(TreeNode root) {return recur(root,Long.MIN_VALUE,Long.MAX_VALUE);}public boolean recur(TreeNode root,long lower,long upper){if(rootnull) return true;if(root.val<lower||root.val>upper) re…

python爬虫之爬取携程景点评价(5)

一、景点部分评价爬取 【携程攻略】携程旅游攻略,自助游,自驾游,出游,自由行攻略指南 (ctrip.com) import requests from bs4 import BeautifulSoupif __name__ __main__:url https://m.ctrip.com/webapp/you/commentWeb/commentList?seo0&businessId22176&busines…

爬虫零基础学习,第一天,安装环境,requests库常用命令的讲解

Python爬虫 爬虫学习思路 URL内容获取&#xff0c;requests的基本常用语法 import requests # 先向目标网站发送请求 url "http://www.baidu.com" r requests.get(url) # 可以用看一下访问码返回值是不是200&#xff0c;若是200则表示访问成功 print(r.status_…

Web3与物联网:探索区块链如何驱动智能设备的未来

引言 在数字化快速发展的时代&#xff0c;Web3技术和物联网&#xff08;IoT&#xff09;都成为了前沿技术的代表。两者的结合正逐渐展现出无限的可能性&#xff0c;尤其是在智能设备和数据安全方面。本文将深入探讨Web3如何与物联网相结合&#xff0c;以及这种结合对未来智能设…

现货白银价格走势分析别走弯路!

参与现货白银投资离不开对其价格走势的分析&#xff0c;虽然相关的分析方法有很多种&#xff0c;但说到直观高效的方法&#xff0c;技术分析就是很多专业投资者所钟爱的选择。投资者可以通过平台交易软件所自带的技术指标和画线工具&#xff0c;来辅助自己的分析&#xff0c;实…

UltraScale+的10G/25G Ethernet Subsystem IP核使用

文章目录 前言一、设计框图1.1、xxv_ethernet_01.2、xxv_ethernet_0_sharedlogic_wrapper1.3、xxv_ethernet_0_clocking_wrapper1.4、xxv_ethernet_0_common_wrapper 二、IP核配置三、仿真四、上板测速五、总结 前言 前面我们学习了很多基于XILINX 7系列的高速接口使用&#x…

【SpringBoot整合系列】SpringBoot配置多数据源

目录 背景技术选型配置多数据源思路(以两个为例)代码实现1.导入依赖2.各自的配置 3.各自的dataSourcenews数据库的smbms数据库的注意&#xff1a;Primary注解 4.各自的SqlSessionFactory等news数据库的smbms数据库的 5.去掉启动类头上的MapperScan6.各自的mapper接口7.各自的ma…

力扣HOT100 - 230. 二叉搜索树中第K小的元素

解题思路&#xff1a; class Solution {List<Integer> list new ArrayList<>();public int kthSmallest(TreeNode root, int k) {dfs(root);return list.get(k - 1);}public void dfs(TreeNode root) {if (root null) return;dfs(root.left);list.add(root.val)…

【Netty框架问题总结】

文章目录 Netty初步认识Netty简单介绍为什么jdk已经实现了NIO还要用netty框架&#xff1a; Reactor 线程模型Reactor 单线程模型Netty线程模型 Netty 简单实现EchoClient端实现&#xff1a;ClientHandler实现EchoServer实现ServerHandler实现&#xff1a; Netty初步认识 Netty…

【VSCode调试技巧】Pytorch分布式训练调试

最近遇到个头疼的问题&#xff0c;对于单机多卡的训练脚本&#xff0c;不知道如何使用VSCode进行Debug。 解决方案&#xff1a; 1、找到控制分布式训练的启动脚本&#xff0c;在自己的虚拟环境的/lib/python3.9/site-packages/torch/distributed/launch.py中 2、配置launch.…

检查*.bib参考文献是否重复

安装bibtexparser pip install bibtexparser 代码 import bibtexparser from difflib import SequenceMatcherdef parse_bib_file(filename):with open(filename, r, encodingutf-8) as bibfile:bib_database bibtexparser.load(bibfile)return bib_database.entriesdef fi…

Python构建学生信息管理系统:构建RESTful API - 学生信息管理系统的后端逻辑

在之前的博客里&#xff0c;我们已经完成了项目初始化&#xff0c;在本篇博客中&#xff0c;我们将深入探讨如何使用Flask框架实现学生信息管理系统的后端逻辑&#xff0c;特别是通过RESTful API来实现学生信息的增删改查&#xff08;CRUD&#xff09;操作。 Flask RESTful AP…

【Java】HOT100 回溯

目录 理论基础 一、组合问题 LeetCode77&#xff1a;组合 LeetCode17&#xff1a;电话号码的字母组合 LeetCode39&#xff1a;组合总和 LeetCode216&#xff1a;组合总和ii LeetCode216&#xff1a;组合总和iii 二、分割问题 LeetCode131&#xff1a;分割回文串 Leet…

单片机通讯协议

参考&#xff1a;江科大单片机教程 STM32入门教程-2023版 细致讲解 中文字幕_哔哩哔哩_bilibili IIC通讯协议SPI通信协议UARTCANUSB速度100k-400khz4Mhz-线数2 CLK,DATA4CLK,ENB,IO,OI额外设备一主多从一主多从 一般不用自己写&#xff0c;都有相应的库或官方提供相应的&#…

element中file-upload组件的提示‘按delete键可删除’,怎么去掉?

问题描述 element中file-upload组件会出现这种提示‘按delete键可删除’ 解决方案&#xff1a; 这是因为使用file-upload组件时自带的提示会盖住上传的文件名&#xff0c;修改一下自带的样式即可 ::v-deep .el-upload-list__item.is-success.focusing .el-icon-close-tip {d…