本网页已闲置超过3分钟,按键盘任意键或点击空白处,即可回到网页
最热资讯


亲,“电路城”已合并升级到更全、更大、更强的「新与非网」。点击查看「新与非网」
据估计,打鼾影响了美国 57% 的男性和 40% 的女性。它甚至发生在高达 27% 的儿童身上。这些统计数据表明打鼾很普遍,但其严重程度和健康影响可能有所不同。打鼾可能是轻微的、偶尔的和无关紧要的,也可能是严重的潜在睡眠相关呼吸障碍的征兆。打鼾是由喉咙后部气道附近组织的嘎嘎声和振动引起的。在睡眠期间,肌肉松弛,使气道变窄,当我们吸气和呼气时,流动的空气会导致组织颤动并发出噪音。阻塞性睡眠呼吸暂停是一种呼吸障碍,在睡眠期间气道阻塞或塌陷,导致反复呼吸困难。打鼾是阻塞性睡眠呼吸暂停最常见的症状之一。除非有人告诉他们,否则大多数打鼾的人都没有意识到这一点,这也是睡眠呼吸暂停未被诊断出的部分原因。
在这个项目中,我将建立一个非侵入性低功率边缘设备的概念证明,它可以在你睡眠期间监测你的打鼾情况,并发出振动。
开发环境
我们使用 Edge Impulse Studio 进行特征生成以及 TensorFlow Lite 模型的创建和训练。我们需要在https://studio.edgeimpulse.com注册一个免费帐户并创建一个项目才能开始。MacOS 用于本地开发工作。
数据采集
我们使用了Audioset,一个手动注释的音频事件的大规模数据集,来下载夜间可能发生的打鼾和其他自然声音。AudioSet 由 632 个音频事件类的扩展本体和从 YouTube 视频中提取的人类标记的 10 秒声音剪辑的集合组成。音频从选定事件的 YouTube 视频中提取,并转换为波形音频文件格式 (wav),具有 16 位深度的单声道,采样率为 16KHz。下载了从Audioset Ontology中选择的以下类别。第一列是类别 ID,第二列是类别标签。
/m/01d3sd Snoring /m/07yv9 Vehicle /m/01jt3m Toilet flush /m/06mb1 Rain /m/03m9d0z Wind /m/07c52 Television /m/06bz3 Radio /m/028v0c Silence /m/03vt0 Insect /m/07qjznl Tick-tock /m/0bt9lr Dog /m/01hsr_ Sneeze /m/01b_21 Cough /m/07ppn3j Sniff /m/07pbtc8 Walk, footsteps /m/02fxyj Humming /m/07q6cd_ Squeak /m/0btp2 Traffic noise, roadway noise /m/09l8g Human Voice /m/07pggtn Chirp, tweet /t/dd00002 Baby cry, infant cry /m/04rlf Music |
数据集分为两类,打鼾和噪声。通过过滤平衡训练、不平衡训练和评估数据集 CSV 文件创建了两个 CSV 文件 snoring.csv 和 noise.csv,其中包含 YouTube 剪辑 URL 和其他元数据,可以从这里下载。
下面的 bash 脚本 (download.sh) 用于下载视频剪辑并将音频提取为 wav 文件。请在运行以下命令之前安装youtube-dl和ffmpeg 。
#!/bin/bash SAMPLE_RATE=16000 grep -E '^[^#]' | while read line |
要执行脚本,请运行以下命令。
$ cat noise.csv | ./download.sh $ cat snoring.csv | ./download.sh |
使用 Edge Impulse Uploader 将数据集上传到 Edge Impulse Studio。请按照此处的说明安装 Edge Impulse CLI 工具并执行以下命令。
$ edge-impulse-uploader --category split --label snoring snoring/*.wav $ edge-impulse-uploader --category split --label noise noise/*.wav |
上面的命令还将数据集拆分为训练和测试样本。我们可以在 Edge Impulse Studio 的数据采集页面中看到上传的数据集。
所述打鼾事件的音频剪辑有背景噪声在其中从通过分裂段夹子取出多个打鼾事件之间。该噪声类音频剪辑使用,无需任何修改。
我们可以通过选择每个样本并从下拉菜单中单击“拆分样本”来进行拆分,但这是一项耗时且乏味的工作。幸运的是,有一个 Edge Impulse SDK API 可用于自动化该过程。
import json API_KEY = "<Insert Edge Impulse API Key here from the Dashboard > Keys" if __name__ == "__main__": x = threading.Thread(target=segment, args=(i, ids)) |
训练
转到 Impulse Design > Create Impulse 页面,然后单击Add a processing block并选择Spectrogram ,这是一种表示信号强度或“响度”随时间在特定波形中存在的各种频率的可视化方式。此外,在同一页面上单击添加学习块并选择从数据中学习模式的神经网络(Keras),并将其应用于新数据。我们选择了 1000 毫秒窗口大小和 125 毫秒窗口增加。现在单击“保存冲动”按钮。
现在转到 Impulse Design > Spectrogram 页面并更改参数,如下图所示,然后单击Save parameters按钮。我们选择了 Frame Length = 0.02s,frame stride = 0.01538s 和。频带 = 128(FFT 大小),并且本底噪声 = -54 dB。本底噪声用于滤除频谱图中的背景噪声。它首先将窗口划分为多个重叠的帧。可以通过参数Frame length和Frame stride调整帧的大小和数量. 例如,窗口为 1000 毫秒,帧长为 20 毫秒,步幅为 15.38 毫秒,它将创建 65 个时间帧。然后使用 FFT(快速傅立叶变换)将每个时间帧划分为频率区间,然后我们计算其功率谱。频率区间的数量等于频段参数除以 2 加 1。频谱图块生成的特征等于生成的时间帧数乘以频率区间的数量。
单击“保存参数”按钮重定向到另一个页面,我们应该在其中单击“生成特征”按钮。完成特征生成通常需要几分钟。我们可以在 Feature Explorer 中看到生成的特征的 3D 可视化。
现在转到 Impulse Design > NN Classifier 页面并从下拉菜单中选择 Switch to Keras (expert) mode 并定义模型架构。有许多现成的音频分类模型可用,但它们具有大量参数,因此不适用于 256KB 或更少内存的微控制器。经过大量试验,我们创建了如下所示的模型架构。
sys.path.append('./resources/libraries') channels = 1 norm_layer = preprocessing.Normalization() # model architecture model.add(Conv2D(16, kernel_size=3)) model.add(Conv2D(32, kernel_size=3)) model.add(Flatten()) model.add(Dense(64)) model.add(Dense(32)) model.add(Dense(classes, activation='softmax', name='y_pred')) BATCH_SIZE = 64 lr_schedule = InverseTimeDecay( def get_optimizer(): train_dataset = train_dataset.batch(BATCH_SIZE, drop_remainder=False) # train the neural network print(model.summary()) model.fit(train_dataset, epochs=70, validation_data=validation_dataset, verbose=2, callbacks=callbacks) |
在定义模型架构时,我们已尽力针对 TinyML 用例对其进行优化。由于 64x65 单通道频谱图特征将具有大量训练参数,并且编译后的模型不适合可用的微控制器 RAM,我们将频谱图调整为 24x24 大小,这是模型大小与精度的最佳选择。此外,我们使用了受限范围激活 (ReLU6),因为 ReLU6 将输出限制为 [0, 6],并且训练后量化不会降低准确性。模型概要如下。
Model: "sequential" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= reshape (Reshape) (None, 64, 65, 1) 0 _________________________________________________________________ resizing (Resizing) (None, 24, 24, 1) 0 _________________________________________________________________ normalization (Normalization (None, 24, 24, 1) 3 _________________________________________________________________ conv2d (Conv2D) (None, 22, 22, 16) 160 _________________________________________________________________ re_lu (ReLU) (None, 22, 22, 16) 0 _________________________________________________________________ conv2d_1 (Conv2D) (None, 20, 20, 32) 4640 _________________________________________________________________ re_lu_1 (ReLU) (None, 20, 20, 32) 0 _________________________________________________________________ max_pooling2d (MaxPooling2D) (None, 10, 10, 32) 0 _________________________________________________________________ dropout (Dropout) (None, 10, 10, 32) 0 _________________________________________________________________ flatten (Flatten) (None, 3200) 0 _________________________________________________________________ dense (Dense) (None, 64) 204864 _________________________________________________________________ re_lu_2 (ReLU) (None, 64) 0 _________________________________________________________________ dense_1 (Dense) (None, 32) 2080 _________________________________________________________________ re_lu_3 (ReLU) (None, 32) 0 _________________________________________________________________ y_pred (Dense) (None, 2) 66 ================================================================= Total params: 211,813 Trainable params: 211,810 Non-trainable params: 3 |
现在单击开始训练按钮并等待大约一个小时直到训练完成。我们可以在下面看到训练输出。该模型具有 94.6% 的准确率。
测试
我们可以在测试中测试模型。数据集通过转到模型测试页面并单击分类所有按钮。该模型在测试数据集上的准确率为 88.58%。
部署
由于我们将在 Arduino Nano BLE sense 部署模型,因此在部署页面我们将选择创建库 > Arduino选项。对于Select optimization选项,我们将选择Enable EON Compiler以减少模型的内存使用。此外,我们将选择量化 (Int8) 模型。现在单击Build按钮,几秒钟后库包将下载到本地计算机。
硬件设置
我们将使用带有板载麦克风的 Arduino Nano 33 BLE Sense。由于 Arduino Nano 33 BLE Sense 上的 5V 引脚默认断开连接,要使用 5V 引脚为振动电机供电,我们需要在标记为 VUSB 的两个焊盘上制作一个焊桥(下图中的红色矩形突出显示)。
振动电机使用直接焊接在 Arduino Nano BLE 传感头引脚上的 Grove 连接器连接。原理图可以在下文原理图部分找到。
运行推理
请按照此处的说明下载并安装 Arduino IDE。安装后,打开 Arduino IDE 并通过转到工具 > 开发板 > 开发板管理器为 Arduino Nano 33 BLE Sense 安装开发板包。搜索如下图的板子包并安装。
板包安装完成后,从 Tools > Board > Arduino Mbed OS Nano Boards 菜单中选择 Arduino Nano 33 BLE。另外,从工具>端口菜单中选择连接的开发板的串口。我们需要使用库管理器(工具 > 管理库...)安装RingBuffer库。
下面是推理的代码。应用程序使用双缓冲区连续捕获音频事件。
// If your target is limited in memory remove this macro to save 10K RAM /** /* Includes ---------------------------------------------------------------- */ /** Audio buffers, pointers and selectors */ static inference_t inference; bool alert = false; RingBuf<uint8_t, 10> last_ten_predictions; void run_vibration() for (int i = 0; i < 2; i++) /** @param[in] format Variable argument list va_list args; if (r > 0) { /** // read into the sample buffer if (record_ready == true) { if (inference.buf_count >= inference.n_samples) { /** @param[in] n_samples The n samples @return { description_of_the_return_value } if (inference.buffers[0] == NULL) { inference.buffers[1] = (signed short *)malloc(n_samples * sizeof(signed short)); if (inference.buffers[0] == NULL) { sampleBuffer = (signed short *)malloc((n_samples >> 1) * sizeof(signed short)); if (sampleBuffer == NULL) { inference.buf_select = 0; // configure the data receive callback PDM.setBufferSize((n_samples >> 1) * sizeof(int16_t)); // initialize PDM with: // set the gain, defaults to 20 record_ready = true; return true; /** @return True when finished if (inference.buf_ready == 1) { while (inference.buf_ready == 0) { inference.buf_ready = 0; return ret; /** return 0; /**
pinMode(greenLED, OUTPUT); // summary of inferencing settings (from model_metadata.h) run_classifier_init(); Scheduler.startLoop(run_vibration); void loop() bool m = microphone_inference_record(); if (!m) { signal_t signal; EI_IMPULSE_ERROR r = run_classifier_continuous(&signal, &result, debug_nn); if (++print_results >= (EI_CLASSIFIER_SLICES_PER_MODEL_WINDOW)) { for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) { if (ix == 1 && !is_motor_running && result.classification[ix].value > 0.9) { last_ten_predictions.push(ix); uint8_t count = 0; for (uint8_t j = 0; j < last_ten_predictions.size(); j++) { print_results = 0;
|
要运行推理草图,请使用以下命令克隆应用程序存储库。
$ git clone https://github.com/metanav/Snoring_Guardian.git |
在 Arduino IDE 中打开 Arduino 草图 Snoring_Guardian/snoring_detection_inferencing/examples/tflite_micro_snoring_detection/tflite_micro_snoring_detection.ino。编译并上传固件到连接的开发板。我们可以使用波特率 115200 bps 的 Tools > Serial Monitor 查看推理输出。
视频演示:
套管
最终版本的设备被放置在一个带有移动电源的袋子里。小袋中有一个小开口,可以让位于开口附近的麦克风听到声音。
现场演示
原理图:
源代码:点击下载
总结
这个项目为一个现实生活中的问题提供了一个解决方案,这个问题看起来很有趣但需要仔细关注。它是一种易于使用且方便的设备,通过在边缘运行推理来尊重用户的隐私。该项目还展示了一个简单的神经网络可以通过以正确的方式进行信号处理来解决复杂的问题,并且可以在低功耗资源受限的微型设备上运行。尽管 TensorFlow Lite Micro 模型运行良好,但仍有改进的空间。随着更多的训练数据,模型可以变得更加准确和健壮。
S10 5G版对比S10+:从拆解看不一样的电路设计方案
2019-07-30
邦克仕小风扇拆解:人人都可以掌握的电路设计方案
2019-07-26
重磅!从拆解看5款5G智能手机电路设计方案的优劣
2019-08-30
骨传导智能眼镜拆解:电路设计方案竟如此简单
2019-11-25
医疗应用:DC-DC电路设计方案如何选型?
2019-08-16
拆解一个COB LED钥匙扣:三脚猫的电路设计方案
2019-08-15
DIY便宜又方便制作的PEMF磁疗仪
2021-08-26
基于树莓派的智能家居镜子
2021-08-27
杜洋来啦!单片机电路稳定性设计技巧
2021-01-06
DIY 双通道可变实验台电源 30V 10A 300W
2021-08-27
讨论