mirror of
https://github.com/YuTaoV5/YuEEG.git
synced 2025-09-26 23:09:24 +08:00
update new plot program
This commit is contained in:
parent
ba095322e1
commit
fc7f542f3b
@ -2,7 +2,7 @@
|
||||
#include "esp_timer.h"
|
||||
|
||||
// 定义宏,简化寄存器配置
|
||||
#define CONFIG_1 0xC5
|
||||
#define CONFIG_1 0xD5
|
||||
#define CONFIG_2 0xC0
|
||||
#define CONFIG_3 0xEC
|
||||
#define CHnSET 0x60
|
||||
@ -81,7 +81,7 @@ void setup() {
|
||||
SPI.begin(SCLK_PIN, MISO_PIN, MOSI_PIN, CS_PIN);
|
||||
SPI.setBitOrder(MSBFIRST);
|
||||
SPI.setDataMode(SPI_MODE1);
|
||||
SPI.setClockDivider(SPI_CLOCK_DIV4); // 约 5 MHz
|
||||
SPI.setClockDivider(SPI_CLOCK_DIV8); // 约 5 MHz
|
||||
|
||||
// 初始化ADS1299
|
||||
initADS1299();
|
||||
@ -175,9 +175,9 @@ void startSelfTestMode() {
|
||||
sendCommand(RESET);
|
||||
delay(100);
|
||||
sendCommand(SDATAC);
|
||||
// 配置CONFIG2寄存器启用测试信号
|
||||
writeRegister(0x01, 0xD4);
|
||||
writeRegister(0x02, 0x10);
|
||||
// 配置CONFIG2寄存器启用测试信号 1af 2hz
|
||||
writeRegister(0x01, 0xD5);
|
||||
writeRegister(0x02, 0xD1);
|
||||
writeRegister(0x03, 0xEC);
|
||||
writeRegister(0x04, 0x00); // MISC1寄存器启用SRB1
|
||||
// 配置所有通道输入为内部测试信号
|
||||
@ -212,11 +212,12 @@ void initADS1299() {
|
||||
void readData() {
|
||||
byte data[27];
|
||||
digitalWrite(CS_PIN, LOW);
|
||||
delayMicroseconds(1); // 确保 tSDSU
|
||||
for (int i = 0; i < 27; i++) {
|
||||
data[i] = SPI.transfer(0x00);
|
||||
}
|
||||
digitalWrite(CS_PIN, HIGH);
|
||||
|
||||
delayMicroseconds(1); // 确保 tDSHD
|
||||
// 转换数据,并将结果保存在全局缓冲区
|
||||
convertData(data, channelDataBuffer);
|
||||
|
||||
@ -258,50 +259,63 @@ void measureImpedance() {
|
||||
}
|
||||
|
||||
void convertData(byte *data, double *channelData) {
|
||||
// 解析 STATUS 寄存器
|
||||
// 解析STATUS寄存器
|
||||
long statusValue = ((long)data[0] << 16) | ((long)data[1] << 8) | data[2];
|
||||
channelData[0] = (double)statusValue; // 将 STATUS 存储在第一个位置
|
||||
channelData[0] = (double)statusValue;
|
||||
|
||||
// 解析 8 个通道的数据
|
||||
// 转换通道数据
|
||||
for (int i = 0; i < 8; i++) {
|
||||
long value = ((long)data[3 * i + 3] << 16) | ((long)data[3 * i + 4] << 8) | data[3 * i + 5];
|
||||
// if (value & 0x800000) {
|
||||
// value |= 0xFF000000; // 符号扩展
|
||||
// }
|
||||
channelData[i + 1] = (double)value * 4.5 / (double)0x800000;
|
||||
long value = ((long)data[3*i+3] << 16) | ((long)data[3*i+4] << 8) | data[3*i+5];
|
||||
|
||||
// 24位符号扩展
|
||||
if (value & 0x800000) {
|
||||
value |= 0xFF000000; // 负数扩展
|
||||
}
|
||||
|
||||
// 电压计算 (考虑增益)
|
||||
double vPerLSB = 4.5 / (24 * 8388608.0); // 1 LSB对应电压
|
||||
channelData[i+1] = (double)value * vPerLSB;
|
||||
}
|
||||
}
|
||||
|
||||
void sendCommand(byte cmd) {
|
||||
digitalWrite(CS_PIN, LOW);
|
||||
delayMicroseconds(1); // 确保 tSDSU
|
||||
SPI.transfer(cmd);
|
||||
digitalWrite(CS_PIN, HIGH);
|
||||
delayMicroseconds(1); // 确保 tSDSU
|
||||
}
|
||||
|
||||
void writeRegister(byte reg, byte value) {
|
||||
digitalWrite(CS_PIN, LOW);
|
||||
delayMicroseconds(1); // 确保 tSDSU
|
||||
SPI.transfer(WREG | reg);
|
||||
SPI.transfer(0x00);
|
||||
SPI.transfer(value);
|
||||
digitalWrite(CS_PIN, HIGH);
|
||||
delayMicroseconds(1); // 确保 tSDSU
|
||||
}
|
||||
|
||||
byte readRegister(byte reg) {
|
||||
digitalWrite(CS_PIN, LOW);
|
||||
delayMicroseconds(1); // 确保 tSDSU
|
||||
SPI.transfer(RREG | reg);
|
||||
SPI.transfer(0x00);
|
||||
byte value = SPI.transfer(0x00);
|
||||
digitalWrite(CS_PIN, HIGH);
|
||||
delayMicroseconds(1); // 确保 tSDSU
|
||||
return value;
|
||||
}
|
||||
|
||||
void getDeviceID() {
|
||||
digitalWrite(CS_PIN, LOW);
|
||||
delayMicroseconds(1); // 确保 tSDSU
|
||||
SPI.transfer(SDATAC);
|
||||
SPI.transfer(RREG | 0x00);
|
||||
SPI.transfer(0x00);
|
||||
byte data = SPI.transfer(0x00);
|
||||
digitalWrite(CS_PIN, HIGH);
|
||||
delayMicroseconds(1); // 确保 tSDSU
|
||||
Serial.print("Device ID: ");
|
||||
Serial.println(data, BIN);
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -33,7 +33,10 @@
|
||||
> 【注意】请勿焊接TPS模块,直接使用USB供电,原因如下:
|
||||
> ESP的Vbus引脚直连USB电源,并没有引脚二极管处理供电冲突所以请不要同时使用两种供电
|
||||
|
||||
> [!NOTE]
|
||||
> [!NOTE] 更新日志 2025/6/10
|
||||
> 更新波形显示界面`FIFO_Plot.py`,添加去基线等滤波功能。修改部分驱动寄存器配置。
|
||||
|
||||
> [!NOTE] 更新日志 2024/12/7
|
||||
> 项目已更新【SSVEP 范式】,后续还会添加APP以及网页波形显示,建议 Star 或者Fork后,作者会添加更多内容。
|
||||
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
import sys
|
||||
import time
|
||||
from collections import deque
|
||||
|
||||
import numpy as np
|
||||
import re
|
||||
from PyQt5 import QtWidgets, QtCore, QtGui
|
||||
@ -17,12 +19,13 @@ FFT_LENGTH = 500 # FFT分析长度
|
||||
UPDATE_INTERVAL = 60 # 界面刷新间隔(ms)
|
||||
SAMPLE_RATE = 500 # 采样率
|
||||
|
||||
# 新增滤波器参数
|
||||
# 修改滤波器参数
|
||||
NOTCH_FREQ = 50.0 # 陷波频率
|
||||
QUALITY_FACTOR = 10 # 品质因数(决定带宽)
|
||||
FILTER_CUTOFF = 45 # 低通滤波截止频率
|
||||
BUTTER_ORDER = 4 # 巴特沃兹滤波器阶数
|
||||
BUTTER_CUTOFF = 45 # 巴特沃兹截止频率
|
||||
QUALITY_FACTOR = 10 # 品质因数
|
||||
LOW_CUTOFF = 2.0 # 带通滤波低频截止
|
||||
HIGH_CUTOFF = 40.0 # 带通滤波高频截止
|
||||
FIR_ORDER = 101 # FIR滤波器阶数
|
||||
MEDIAN_WINDOW = 800 # 中值滤波窗口大小
|
||||
|
||||
class SerialThread(QtCore.QThread):
|
||||
data_received = QtCore.pyqtSignal(str)
|
||||
@ -33,26 +36,29 @@ class SerialThread(QtCore.QThread):
|
||||
self.filter_flag = True
|
||||
self.serial_port = None
|
||||
self.running = False
|
||||
self.data_buffer = [[] for _ in range(9)] # 动态数据池
|
||||
self.timestamps = [] # 时间戳记录
|
||||
self.data_buffer = [[] for _ in range(9)]
|
||||
self.timestamps = []
|
||||
self.write_index = 0
|
||||
self.max_data_length = 1_000_000 # 最大数据量限制
|
||||
self.max_data_length = 1_000_000
|
||||
|
||||
# 初始化滤波器参数
|
||||
self.b_notch = [1] * 9 # 滤波器分子系数
|
||||
self.a_notch = [1] * 9 # 滤波器分母系数
|
||||
self.zi_notch = [np.zeros(2) for _ in range(9)] # 滤波器状态
|
||||
# 初始化滤波器
|
||||
self._init_filters()
|
||||
|
||||
def _init_filters(self):
|
||||
# 设计50Hz陷波滤波器
|
||||
nyquist = 0.5 * SAMPLE_RATE
|
||||
freq = NOTCH_FREQ / nyquist
|
||||
self.b_notch, self.a_notch = iirnotch(freq, QUALITY_FACTOR)
|
||||
self.zi_notch = [lfilter_zi(self.b_notch, self.a_notch) for _ in range(9)]
|
||||
|
||||
# 巴特沃兹滤波器初始化
|
||||
butter_cutoff = BUTTER_CUTOFF / nyquist
|
||||
self.b_butter, self.a_butter = butter(BUTTER_ORDER, butter_cutoff, btype='low')
|
||||
self.zi_butter = [lfilter_zi(self.b_butter, self.a_butter) for _ in range(9)]
|
||||
# 设计FIR带通滤波器
|
||||
from scipy.signal import firwin
|
||||
self.fir_coeff = firwin(FIR_ORDER,
|
||||
[LOW_CUTOFF/nyquist, HIGH_CUTOFF/nyquist],
|
||||
pass_zero=False)
|
||||
self.zi_fir = [np.zeros(FIR_ORDER - 1) for _ in range(9)]
|
||||
# 中值滤波缓冲区
|
||||
self.median_buffers = [deque(maxlen=MEDIAN_WINDOW) for _ in range(9)]
|
||||
|
||||
def run(self):
|
||||
self.running = True
|
||||
@ -75,27 +81,34 @@ class SerialThread(QtCore.QThread):
|
||||
self.serial_port.close()
|
||||
|
||||
def _update_buffer(self, values):
|
||||
# 应用50Hz陷波滤波
|
||||
filtered_values = []
|
||||
for i in range(9):
|
||||
# 使用lfilter进行实时滤波处理
|
||||
filtered_value, self.zi_notch[i] = lfilter(
|
||||
# 1. 50Hz陷波滤波
|
||||
notch_filtered, self.zi_notch[i] = lfilter(
|
||||
self.b_notch,
|
||||
self.a_notch,
|
||||
[values[i]],
|
||||
zi=self.zi_notch[i]
|
||||
)
|
||||
filtered_values.append(filtered_value[0])
|
||||
# 第二级:4阶巴特沃兹低通滤波
|
||||
for i in range(9):
|
||||
filtered, self.zi_butter[i] = lfilter(
|
||||
self.b_butter,
|
||||
self.a_butter,
|
||||
[filtered_values[i]],
|
||||
zi=self.zi_butter[i]
|
||||
|
||||
# 2. FIR带通滤波
|
||||
fir_filtered, self.zi_fir[i] = lfilter(
|
||||
self.fir_coeff,
|
||||
[1.0],
|
||||
notch_filtered,
|
||||
zi=self.zi_fir[i]
|
||||
)
|
||||
filtered_values[i] = filtered[0]
|
||||
# 将滤波后的数据存入缓冲区(替代原始数据)
|
||||
|
||||
# 3. 中值滤波去基线
|
||||
self.median_buffers[i].append(fir_filtered[0])
|
||||
# 当缓冲区满时计算中值
|
||||
if len(self.median_buffers[i]) >= MEDIAN_WINDOW:
|
||||
median = np.median(self.median_buffers[i])
|
||||
filtered_values.append(fir_filtered[0] - median)
|
||||
else:
|
||||
filtered_values.append(fir_filtered[0])
|
||||
|
||||
# 更新数据缓冲区
|
||||
while len(self.timestamps) >= self.max_data_length:
|
||||
for ch in self.data_buffer:
|
||||
ch.pop(0)
|
||||
|
Loading…
Reference in New Issue
Block a user