OpenBCI-特征提取技术:频域分析与时频分析

OpenBCI-特征提取技术:频域分析与时频分析

文章目录

一、引言:特征提取的重要性

特征提取是脑机接口系统中的关键步骤,它从预处理后的脑电信号中提取能够反映用户意图或状态的有效信息。好的特征可以显著提高BCI系统的性能和稳定性。

二、特征提取流程

#mermaid-svg-JBZCJMUpxDgfsKHe{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-JBZCJMUpxDgfsKHe .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-JBZCJMUpxDgfsKHe .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-JBZCJMUpxDgfsKHe .error-icon{fill:#552222;}#mermaid-svg-JBZCJMUpxDgfsKHe .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-JBZCJMUpxDgfsKHe .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-JBZCJMUpxDgfsKHe .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-JBZCJMUpxDgfsKHe .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-JBZCJMUpxDgfsKHe .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-JBZCJMUpxDgfsKHe .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-JBZCJMUpxDgfsKHe .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-JBZCJMUpxDgfsKHe .marker{fill:#333333;stroke:#333333;}#mermaid-svg-JBZCJMUpxDgfsKHe .marker.cross{stroke:#333333;}#mermaid-svg-JBZCJMUpxDgfsKHe svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-JBZCJMUpxDgfsKHe p{margin:0;}#mermaid-svg-JBZCJMUpxDgfsKHe .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-JBZCJMUpxDgfsKHe .cluster-label text{fill:#333;}#mermaid-svg-JBZCJMUpxDgfsKHe .cluster-label span{color:#333;}#mermaid-svg-JBZCJMUpxDgfsKHe .cluster-label span p{background-color:transparent;}#mermaid-svg-JBZCJMUpxDgfsKHe .label text,#mermaid-svg-JBZCJMUpxDgfsKHe span{fill:#333;color:#333;}#mermaid-svg-JBZCJMUpxDgfsKHe .node rect,#mermaid-svg-JBZCJMUpxDgfsKHe .node circle,#mermaid-svg-JBZCJMUpxDgfsKHe .node ellipse,#mermaid-svg-JBZCJMUpxDgfsKHe .node polygon,#mermaid-svg-JBZCJMUpxDgfsKHe .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-JBZCJMUpxDgfsKHe .rough-node .label text,#mermaid-svg-JBZCJMUpxDgfsKHe .node .label text,#mermaid-svg-JBZCJMUpxDgfsKHe .image-shape .label,#mermaid-svg-JBZCJMUpxDgfsKHe .icon-shape .label{text-anchor:middle;}#mermaid-svg-JBZCJMUpxDgfsKHe .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-JBZCJMUpxDgfsKHe .rough-node .label,#mermaid-svg-JBZCJMUpxDgfsKHe .node .label,#mermaid-svg-JBZCJMUpxDgfsKHe .image-shape .label,#mermaid-svg-JBZCJMUpxDgfsKHe .icon-shape .label{text-align:center;}#mermaid-svg-JBZCJMUpxDgfsKHe .node.clickable{cursor:pointer;}#mermaid-svg-JBZCJMUpxDgfsKHe .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-JBZCJMUpxDgfsKHe .arrowheadPath{fill:#333333;}#mermaid-svg-JBZCJMUpxDgfsKHe .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-JBZCJMUpxDgfsKHe .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-JBZCJMUpxDgfsKHe .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-JBZCJMUpxDgfsKHe .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-JBZCJMUpxDgfsKHe .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-JBZCJMUpxDgfsKHe .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-JBZCJMUpxDgfsKHe .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-JBZCJMUpxDgfsKHe .cluster text{fill:#333;}#mermaid-svg-JBZCJMUpxDgfsKHe .cluster span{color:#333;}#mermaid-svg-JBZCJMUpxDgfsKHe div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-JBZCJMUpxDgfsKHe .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-JBZCJMUpxDgfsKHe rect.text{fill:none;stroke-width:0;}#mermaid-svg-JBZCJMUpxDgfsKHe .icon-shape,#mermaid-svg-JBZCJMUpxDgfsKHe .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-JBZCJMUpxDgfsKHe .icon-shape p,#mermaid-svg-JBZCJMUpxDgfsKHe .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-JBZCJMUpxDgfsKHe .icon-shape .label rect,#mermaid-svg-JBZCJMUpxDgfsKHe .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-JBZCJMUpxDgfsKHe .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-JBZCJMUpxDgfsKHe .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-JBZCJMUpxDgfsKHe :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 预处理后信号
特征提取
时域特征
频域特征
时频特征
空间特征
统计特征
波形特征
功率谱密度
频段能量
短时傅里叶变换
小波变换
空间滤波
协方差矩阵

三、频域特征分析

3.1 功率谱密度(PSD)

python 复制代码
from scipy.signal import welch
import numpy as np

def compute_psd(data, fs=250, nperseg=256):
    """计算功率谱密度"""
    freqs, psd = welch(data, fs=fs, nperseg=nperseg)
    return freqs, psd

# 使用示例
fs = 250
freqs, psd = compute_psd(eeg_data[0], fs=fs)

# 绘制功率谱
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 6))
plt.semilogy(freqs, psd)
plt.xlabel('Frequency (Hz)')
plt.ylabel('Power Spectral Density (μV²/Hz)')
plt.title('EEG Power Spectrum')
plt.xlim(0, 50)
plt.grid(True)
plt.show()

3.2 频段能量特征

python 复制代码
def extract_band_features(psd, freqs):
    """提取各频段能量特征"""
    bands = {
        'delta': (1, 4),
        'theta': (4, 8),
        'alpha': (8, 13),
        'beta': (13, 30),
        'gamma': (30, 50)
    }
    
    features = {}
    for band, (low, high) in bands.items():
        mask = (freqs >= low) & (freqs <= high)
        features[band] = np.mean(psd[mask])
    
    # 计算比值特征
    features['alpha/beta'] = features['alpha'] / (features['beta'] + 1e-10)
    features['theta/alpha'] = features['theta'] / (features['alpha'] + 1e-10)
    features['delta/theta'] = features['delta'] / (features['theta'] + 1e-10)
    
    return features

# 使用示例
freqs, psd = compute_psd(eeg_data[0], fs=250)
band_features = extract_band_features(psd, freqs)
print("频段特征:", band_features)

3.3 谱熵

python 复制代码
def spectral_entropy(psd):
    """计算谱熵"""
    psd_normalized = psd / np.sum(psd)
    entropy = -np.sum(psd_normalized * np.log2(psd_normalized + 1e-10))
    return entropy

# 使用示例
entropy = spectral_entropy(psd)
print(f"谱熵: {entropy:.4f}")

四、时频分析

4.1 短时傅里叶变换(STFT)

python 复制代码
from scipy.signal import stft
import matplotlib.pyplot as plt

def compute_stft(data, fs=250, nperseg=128, noverlap=64):
    """计算短时傅里叶变换"""
    f, t, Zxx = stft(data, fs=fs, nperseg=nperseg, noverlap=noverlap)
    return f, t, np.abs(Zxx)

# 使用示例
f, t, spectrogram = compute_stft(eeg_data[0], fs=250)

# 绘制时频谱图
plt.figure(figsize=(12, 6))
plt.pcolormesh(t, f, 10 * np.log10(spectrogram), shading='gouraud')
plt.ylabel('Frequency (Hz)')
plt.xlabel('Time (s)')
plt.title('STFT Spectrogram')
plt.colorbar(label='Power (dB)')
plt.ylim(0, 50)
plt.show()

4.2 小波变换

python 复制代码
import pywt

def compute_wavelet_transform(data, wavelet='db4', level=5):
    """计算小波变换"""
    coeffs = pywt.wavedec(data, wavelet, level=level)
    
    # 重构各尺度信号
    reconstructed = []
    for i in range(len(coeffs)):
        zeros = [np.zeros_like(c) for c in coeffs]
        zeros[i] = coeffs[i]
        rec = pywt.waverec(zeros, wavelet)
        reconstructed.append(rec[:len(data)])
    
    return reconstructed

# 使用示例
wavelet_features = compute_wavelet_transform(eeg_data[0])

# 绘制各尺度分量
plt.figure(figsize=(12, 8))
for i, feat in enumerate(wavelet_features):
    plt.subplot(len(wavelet_features), 1, i+1)
    plt.plot(feat[:500])
    plt.title(f'Wavelet Level {i}')
plt.tight_layout()
plt.show()

4.3 希尔伯特-黄变换

python 复制代码
import numpy as np
from PyEMD import EMD

def hilbert_huang_transform(data):
    """希尔伯特-黄变换"""
    emd = EMD()
    imfs = emd.emd(data)
    
    # 计算希尔伯特谱
    from scipy.signal import hilbert
    hilbert_spectrum = []
    for imf in imfs:
        analytic_signal = hilbert(imf)
        amplitude = np.abs(analytic_signal)
        phase = np.unwrap(np.angle(analytic_signal))
        instantaneous_freq = np.diff(phase) / (2 * np.pi)
        hilbert_spectrum.append({
            'amplitude': amplitude[:-1],
            'frequency': instantaneous_freq
        })
    
    return imfs, hilbert_spectrum

# 使用示例
imfs, spectrum = hilbert_huang_transform(eeg_data[0][:1000])
print(f"分解出 {len(imfs)} 个固有模态函数")

五、时域特征分析

5.1 统计特征

python 复制代码
def extract_time_domain_features(data):
    """提取时域统计特征"""
    features = {}
    
    # 基本统计量
    features['mean'] = np.mean(data)
    features['std'] = np.std(data)
    features['var'] = np.var(data)
    features['median'] = np.median(data)
    
    # 高阶统计量
    features['skewness'] = np.mean((data - features['mean']) ** 3) / (features['std'] ** 3 + 1e-10)
    features['kurtosis'] = np.mean((data - features['mean']) ** 4) / (features['std'] ** 4 + 1e-10)
    
    # 能量相关
    features['rms'] = np.sqrt(np.mean(data ** 2))
    features['energy'] = np.sum(data ** 2)
    
    # 过零率
    features['zero_crossing_rate'] = np.sum(np.diff(np.sign(data)) != 0) / len(data)
    
    # 峰值特征
    features['max'] = np.max(data)
    features['min'] = np.min(data)
    features['peak_to_peak'] = features['max'] - features['min']
    
    return features

# 使用示例
time_features = extract_time_domain_features(eeg_data[0])
print("时域特征:", time_features)

5.2 Hjorth参数

python 复制代码
def hjorth_parameters(data):
    """计算Hjorth参数"""
    # 活动度(Activity)
    activity = np.var(data)
    
    # 移动度(Mobility)
    first_derivative = np.diff(data)
    mobility = np.sqrt(np.var(first_derivative) / activity)
    
    # 复杂度(Complexity)
    second_derivative = np.diff(first_derivative)
    complexity = np.sqrt(np.var(second_derivative) / np.var(first_derivative)) / mobility
    
    return {
        'activity': activity,
        'mobility': mobility,
        'complexity': complexity
    }

# 使用示例
hjorth = hjorth_parameters(eeg_data[0])
print("Hjorth参数:", hjorth)

5.3 自相关特征

python 复制代码
def autocorrelation_features(data, max_lag=100):
    """计算自相关特征"""
    n = len(data)
    mean = np.mean(data)
    variance = np.var(data)
    
    autocorr = []
    for lag in range(1, max_lag+1):
        if lag >= n:
            break
        corr = np.sum((data[:-lag] - mean) * (data[lag:] - mean)) / ((n - lag) * variance)
        autocorr.append(corr)
    
    features = {
        'autocorr_first': autocorr[0] if len(autocorr) > 0 else 0,
        'autocorr_max': np.max(autocorr) if len(autocorr) > 0 else 0,
        'autocorr_sum': np.sum(autocorr) if len(autocorr) > 0 else 0,
        'autocorr_decay': np.mean(autocorr[:10]) if len(autocorr) >= 10 else 0
    }
    
    return features

# 使用示例
autocorr_feat = autocorrelation_features(eeg_data[0])
print("自相关特征:", autocorr_feat)

六、空间特征分析

6.1 空间滤波(Common Spatial Pattern)

python 复制代码
from sklearn.cross_decomposition import CSP

def csp_features(eeg_data, labels):
    """使用CSP提取空间特征"""
    csp = CSP(n_components=4, reg=None, log=True, norm_trace=False)
    features = csp.fit_transform(eeg_data, labels)
    return features, csp

# 使用示例(假设有两类标签)
# eeg_data: (trials, channels, samples)
# labels: (trials,)
features, csp = csp_features(eeg_data, labels)
print(f"CSP特征形状: {features.shape}")

6.2 协方差矩阵特征

python 复制代码
def covariance_features(eeg_data):
    """计算协方差矩阵特征"""
    # 计算协方差矩阵
    cov_matrix = np.cov(eeg_data)
    
    # 提取特征值
    eigenvalues = np.linalg.eigvalsh(cov_matrix)
    
    features = {
        'trace': np.trace(cov_matrix),
        'det': np.linalg.det(cov_matrix),
        'cond': np.linalg.cond(cov_matrix),
        'eigen_sum': np.sum(eigenvalues),
        'eigen_max': np.max(eigenvalues),
        'eigen_min': np.min(eigenvalues),
        'eigen_ratio': np.max(eigenvalues) / (np.min(eigenvalues) + 1e-10)
    }
    
    return features

# 使用示例
cov_feat = covariance_features(eeg_data)
print("协方差特征:", cov_feat)

七、特征选择

7.1 方差分析(ANOVA)

python 复制代码
from sklearn.feature_selection import f_classif

def select_features_anova(X, y, n_features=10):
    """使用ANOVA选择特征"""
    f_values, p_values = f_classif(X, y)
    
    # 选择p值最小的特征
    selected_indices = np.argsort(p_values)[:n_features]
    
    return selected_indices, p_values[selected_indices]

# 使用示例
# X: (samples, features)
# y: (samples,)
selected_idx, p_vals = select_features_anova(X, y, n_features=10)
print(f"选择的特征索引: {selected_idx}")

7.2 互信息

python 复制代码
from sklearn.feature_selection import mutual_info_classif

def select_features_mi(X, y, n_features=10):
    """使用互信息选择特征"""
    mi_scores = mutual_info_classif(X, y)
    
    # 选择互信息最大的特征
    selected_indices = np.argsort(mi_scores)[::-1][:n_features]
    
    return selected_indices, mi_scores[selected_indices]

# 使用示例
selected_idx, mi_scores = select_features_mi(X, y, n_features=10)
print(f"选择的特征索引: {selected_idx}")

7.3 递归特征消除

python 复制代码
from sklearn.feature_selection import RFE
from sklearn.svm import SVC

def select_features_rfe(X, y, n_features=10):
    """使用递归特征消除选择特征"""
    estimator = SVC(kernel='linear')
    rfe = RFE(estimator, n_features_to_select=n_features)
    rfe.fit(X, y)
    
    selected_indices = np.where(rfe.support_)[0]
    
    return selected_indices, rfe.ranking_

# 使用示例
selected_idx, ranking = select_features_rfe(X, y, n_features=10)
print(f"选择的特征索引: {selected_idx}")

八、完整特征提取管道

python 复制代码
class FeatureExtractor:
    def __init__(self, fs=250):
        self.fs = fs
    
    def extract(self, eeg_data):
        """提取所有特征"""
        features = []
        
        for channel in eeg_data:
            # 频域特征
            freqs, psd = compute_psd(channel, fs=self.fs)
            band_feat = extract_band_features(psd, freqs)
            entropy = spectral_entropy(psd)
            
            # 时域特征
            time_feat = extract_time_domain_features(channel)
            hjorth_feat = hjorth_parameters(channel)
            autocorr_feat = autocorrelation_features(channel)
            
            # 组合特征
            channel_features = []
            channel_features.extend(list(band_feat.values()))
            channel_features.append(entropy)
            channel_features.extend(list(time_feat.values()))
            channel_features.extend(list(hjorth_feat.values()))
            channel_features.extend(list(autocorr_feat.values()))
            
            features.extend(channel_features)
        
        return np.array(features)

# 使用示例
extractor = FeatureExtractor(fs=250)
features = extractor.extract(eeg_data)
print(f"特征向量长度: {len(features)}")

九、实战:BCI特征提取完整流程

python 复制代码
import numpy as np
from brainflow.board_shim import BoardShim, BrainFlowInputParams, BoardIds

# 1. 采集数据
params = BrainFlowInputParams()
params.serial_port = "COM3"
board = BoardShim(BoardIds.CYTON_BOARD.value, params)
board.prepare_session()
board.start_stream()

import time
time.sleep(10)
data = board.get_board_data()
board.stop_stream()
board.release_session()

# 2. 获取EEG数据
eeg_channels = BoardShim.get_eeg_channels(BoardIds.CYTON_BOARD.value)
eeg_data = data[eeg_channels, :]

# 3. 预处理
from EEGPreprocessor import EEGPreprocessor
preprocessor = EEGPreprocessor(fs=250)
cleaned_data = np.array([preprocessor.process(ch) for ch in eeg_data])

# 4. 特征提取
extractor = FeatureExtractor(fs=250)
features = extractor.extract(cleaned_data)

print(f"提取的特征数: {len(features)}")
print("特征向量:", features[:10])

十、特征可视化

10.1 特征重要性可视化

python 复制代码
import matplotlib.pyplot as plt
import numpy as np

def plot_feature_importance(importances, feature_names, top_n=20):
    """绘制特征重要性"""
    # 获取重要性排序
    indices = np.argsort(importances)[::-1][:top_n]
    top_importances = importances[indices]
    top_names = [feature_names[i] for i in indices]
    
    plt.figure(figsize=(12, 6))
    plt.barh(range(top_n), top_importances[::-1], align='center')
    plt.yticks(range(top_n), top_names[::-1])
    plt.xlabel('Importance')
    plt.title('Feature Importance')
    plt.tight_layout()
    plt.show()

# 使用示例
# importances = [0.1, 0.2, 0.05, ...]
# feature_names = ['delta', 'theta', 'alpha', ...]
# plot_feature_importance(importances, feature_names)

10.2 特征分布可视化

python 复制代码
import seaborn as sns

def plot_feature_distribution(X, y, feature_idx=0):
    """绘制特征分布"""
    plt.figure(figsize=(10, 6))
    sns.histplot(data=X, x=X[:, feature_idx], hue=y, kde=True)
    plt.xlabel('Feature Value')
    plt.title('Feature Distribution by Class')
    plt.show()

# 使用示例
# plot_feature_distribution(X, y, feature_idx=0)

十一、常见问题与解决方案

11.1 特征维度爆炸

python 复制代码
# 解决方案:
# 1. 特征选择(如ANOVA、RFE)
# 2. 特征降维(PCA、LDA)
# 3. 正则化(L1正则化自动选择特征)

# 示例:使用PCA降维
from sklearn.decomposition import PCA

pca = PCA(n_components=50)  # 降到50维
X_reduced = pca.fit_transform(X)
print(f"降维后特征数: {X_reduced.shape[1]}")

11.2 特征尺度不一致

python 复制代码
# 解决方案:标准化或归一化

from sklearn.preprocessing import StandardScaler, MinMaxScaler

# 标准化(均值为0,方差为1)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# 归一化(缩放到[0,1])
scaler = MinMaxScaler()
X_normalized = scaler.fit_transform(X)

11.3 实时特征提取优化

python 复制代码
# 优化建议:
# 1. 使用滑动窗口避免重复计算
# 2. 预计算滤波器系数
# 3. 使用NumPy向量化操作
# 4. 考虑使用C/C++扩展或GPU加速

# 示例:滑动窗口特征提取
class RealTimeFeatureExtractor:
    def __init__(self, fs=250, window_size=2):
        self.fs = fs
        self.window_size = window_size
        self.buffer = []
    
    def add_data(self, data):
        self.buffer.extend(data)
        if len(self.buffer) > int(self.fs * self.window_size):
            self.buffer = self.buffer[-int(self.fs * self.window_size):]
    
    def extract(self):
        if len(self.buffer) < int(self.fs * self.window_size):
            return None
        
        data = np.array(self.buffer)
        freqs, psd = compute_psd(data, fs=self.fs)
        features = extract_band_features(psd, freqs)
        
        return list(features.values())

十二、总结

特征提取是BCI系统的核心环节,选择合适的特征对系统性能至关重要。

12.1 核心技术总结

  1. ✅ 频域特征(PSD、频段能量、谱熵)
  2. ✅ 时频特征(STFT、小波变换、HHT)
  3. ✅ 时域特征(统计量、Hjorth参数、自相关)
  4. ✅ 空间特征(CSP、协方差矩阵)
  5. ✅ 特征选择(ANOVA、MI、RFE)

12.2 下一步计划

在下一篇文章中,我们将学习机器学习在BCI中的应用,包括分类算法和模型训练。


**继续探索特征提取技术!**下一篇我们将学习机器学习在BCI中的应用。

本文是《OpenBCI从入门到精通》系列的第9篇。

关键字:特征提取、频域分析、时频分析、时域特征、空间滤波、CSP


相关推荐
DreamLife☼11 小时前
OpenBCI-机器学习入门:从脑电信号到模式识别
人工智能·机器学习·开源硬件·脑机接口·eeg·openbci·神经科技
Irissgwe2 天前
一、Qt 概述
c++·qt·gui·qt creator
是馒头阿2 天前
95、仇恨与爱
深度学习·神经网络·脑机接口·神经同步采集与刺激平台·植入式脑机接口
DreamLife☼5 天前
OpenBCI-Python与OpenBCI:实时脑电信号采集实战
开发语言·python·硬件·选型·openbci·cyton·ganglion
学不懂飞行器5 天前
电赛保姆级教程】从炸管到国一:电赛电源类(DC-DC/单相逆变)硬核避坑与拓扑全指南
stm32·单片机·嵌入式硬件·电赛·fft
DreamLife☼6 天前
OpenBCI-搭建你的第一个脑电采集系统
eeg·脑电·采集·openbci·cyton
DreamLife☼7 天前
OpenBCI-硬件选型:Cyton vs Ganglion对比分析
硬件·分析·选型·对比·openbci·cyton·ganglion
灰灰老师9 天前
Python Tkinter 基础详解
python·gui·tkinter
Gigavision15 天前
SEED-VII 数据集介绍:面向七类情绪识别的 EEG 与眼动多模态数据集
人工智能·python·算法·脑机接口