
OpenBCI-特征提取技术:频域分析与时频分析
文章目录
- OpenBCI-特征提取技术:频域分析与时频分析
-
- 一、引言:特征提取的重要性
- 二、特征提取流程
- 三、频域特征分析
-
- [3.1 功率谱密度(PSD)](#3.1 功率谱密度(PSD))
- [3.2 频段能量特征](#3.2 频段能量特征)
- [3.3 谱熵](#3.3 谱熵)
- 四、时频分析
-
- [4.1 短时傅里叶变换(STFT)](#4.1 短时傅里叶变换(STFT))
- [4.2 小波变换](#4.2 小波变换)
- [4.3 希尔伯特-黄变换](#4.3 希尔伯特-黄变换)
- 五、时域特征分析
-
- [5.1 统计特征](#5.1 统计特征)
- [5.2 Hjorth参数](#5.2 Hjorth参数)
- [5.3 自相关特征](#5.3 自相关特征)
- 六、空间特征分析
-
- [6.1 空间滤波(Common Spatial Pattern)](#6.1 空间滤波(Common Spatial Pattern))
- [6.2 协方差矩阵特征](#6.2 协方差矩阵特征)
- 七、特征选择
-
- [7.1 方差分析(ANOVA)](#7.1 方差分析(ANOVA))
- [7.2 互信息](#7.2 互信息)
- [7.3 递归特征消除](#7.3 递归特征消除)
- 八、完整特征提取管道
- 九、实战:BCI特征提取完整流程
- 十、特征可视化
-
- [10.1 特征重要性可视化](#10.1 特征重要性可视化)
- [10.2 特征分布可视化](#10.2 特征分布可视化)
- 十一、常见问题与解决方案
-
- [11.1 特征维度爆炸](#11.1 特征维度爆炸)
- [11.2 特征尺度不一致](#11.2 特征尺度不一致)
- [11.3 实时特征提取优化](#11.3 实时特征提取优化)
- 十二、总结
-
- [12.1 核心技术总结](#12.1 核心技术总结)
- [12.2 下一步计划](#12.2 下一步计划)
一、引言:特征提取的重要性
特征提取是脑机接口系统中的关键步骤,它从预处理后的脑电信号中提取能够反映用户意图或状态的有效信息。好的特征可以显著提高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 核心技术总结
- ✅ 频域特征(PSD、频段能量、谱熵)
- ✅ 时频特征(STFT、小波变换、HHT)
- ✅ 时域特征(统计量、Hjorth参数、自相关)
- ✅ 空间特征(CSP、协方差矩阵)
- ✅ 特征选择(ANOVA、MI、RFE)
12.2 下一步计划
在下一篇文章中,我们将学习机器学习在BCI中的应用,包括分类算法和模型训练。
**继续探索特征提取技术!**下一篇我们将学习机器学习在BCI中的应用。
本文是《OpenBCI从入门到精通》系列的第9篇。
关键字:特征提取、频域分析、时频分析、时域特征、空间滤波、CSP
