浅谈一下小波变换和EEG信号处理

小波变换(Wavelet Transform)

谈及小波变换,说不开的就是时域关系、频域关系和时频域关系(一些Papers上可能会提及Wavelet Domain,不过从我的理解来看,都是F-T-Power图谱,都大相径庭了)了。

首先简单说一说时域信号(Time Domain)

顾名思义,时域信号就是以时间作为横轴,记录信号的幅值的一种记录方法,其实许多信号在被记录时,就已经是时域信号了。这里以EEG(脑电)信号做简单描述。
EEG 原始信号就是一种时域上的数据。波形幅值随着时间变换而变换,这种分析方法具有较高的时间精度。
正常人EEG信号
这段波形是我读取Bonn大学公开脑电数据集里所形成的图像,读取的是A_Z中的Z001.txt数据,共有4097个sample点。代码比较简单,我也贴出来,方便大家对照:

import numpy as np
import matplotlib.pyplot as plt

#读取信号
eeg_signal = np.loadtxt("./A_Z/Z001.txt")

#绘制图像
plt.figure(figsize=(10,5))
plt.plot(eeg_signal)
plt.xlabel('Sample')
plt.ylabel('Amplitude')
plt.title('EEG signal')

plt.show()

在计算机中,数据一定会是以离散的形式存储起来的,根据香农采样定理,当
f ≥ 2 f m a x f \ge2f_{max} f2fmax
时,原始的连续数据转存为离散(进行A-D转换)后,再转换回来就不会出现失真的情况。
而对EEG数据进行时域分析时,就会离不开时间相关电位(ERP)方法,以下是一个简单的ERP处理流程,

  1. 滤波,滤去噪声干扰;
  2. 分段 & 加标签;
  3. 去基线;
  4. 叠加平均;
    关于ERP,读者可以参考其它博主的博客,题主在这不作过多赘叙。比如这篇事件相关电位(ERP)的简单处理流程(含MATLAB代码)

频域分析

频域分析使用的是傅里叶变换(Fourier Transform)。根据傅里叶定理,任何连续测量的时序或信号,都可以表示为不同频率的正弦波。
信号的无限叠加。脑电信号可以看成就是由不同的正弦信号混合而成的混合信号,通过傅里叶变换,就能够将这个混合信号重新分解成具有不同频率的正弦波,从而获得频域上的信息。
频域分析不仅可以用于分析任务态的数据,还常用于分析静息态的数据。
而关于傅里叶级数和傅里叶变换,其实推导并不难,这里我只简单叙述一下,有兴趣详细推导的,可以看一下网上的推导过程,都很详细。

傅里叶级数

傅里叶级数其本质上是因为三角函数族的正交性所求得的,对于一般的傅里叶级数来说
f ( x ) = ∑ n = 0 ∞ a n cos ⁡ n x + ∑ n = 0 ∞ b n sin ⁡ n x = a 0 + ∑ n = 1 ∞ a n cos ⁡ n x + ∑ n = 1 ∞ b n sin ⁡ n x . f(x) = \sum_{n=0}^{\infty} a_n \cos nx + \sum_{n=0}^{\infty} b_n \sin nx \\ = a_0 + \sum_{n=1}^{\infty} a_n \cos nx + \sum_{n=1}^{\infty} b_n \sin nx. f(x)=n=0ancosnx+n=0bnsinnx=a0+n=1ancosnx+n=1bnsinnx.
其中,
a 0 = 1 π ∫ − π π f ( x ) d x , a n = 1 π ∫ − π π f ( x ) cos ⁡ n x d x , ( n = 1 , 2 , …   ) b n = 1 π ∫ − π π f ( x ) sin ⁡ n x d x , ( n = 1 , 2 , …   ) a_0 = \frac{1}{\pi} \int_{-\pi}^{\pi} f(x) dx ,\\ a_n = \frac{1}{\pi} \int_{-\pi}^{\pi} f(x) \cos nx \quad dx , (n=1,2,\dots)\\ b_n = \frac{1}{\pi} \int_{-\pi}^{\pi} f(x) \sin nx \quad dx ,( n =1,2,\dots) a0=π1ππf(x)dx,an=π1ππf(x)cosnxdx,(n=1,2,)bn=π1ππf(x)sinnxdx,(n=1,2,)
,上述的傅里叶级数的周期仅为2Π,而在整个函数域上,不可能只是周期为2Π的,甚至有可能没有周期,所以这做了一个相关的变换。
将周期2Π拓宽到2L,得相应的级数为
f ( x ) = a 0 2 + ∑ n = 1 ∞ a n cos ⁡ n π x L + ∑ n = 1 ∞ b n sin ⁡ n π x L . f(x) = \frac{a_0}{2} + \sum_{n=1}^{\infty} a_n \cos \frac{n\pi x}{L} + \sum_{n=1}^{\infty} b_n \sin \frac{n\pi x}{L}. f(x)=2a0+n=1ancosLx+n=1bnsinLx.
其中,
a 0 = 1 L ∫ − L L f ( x ) d x , a n = 1 L ∫ − L L f ( x ) cos ⁡ n π x L d x , ( n = 1 , 2 , …   ) b n = 1 L ∫ − L L f ( x ) sin ⁡ n π x L d x , ( n = 1 , 2 , …   ) a_0 = \frac{1}{L} \int_{-L}^{L} f(x) dx ,\\ a_n = \frac{1}{L} \int_{-L}^{L} f(x) \cos \frac{n\pi x}{L} \quad dx , (n=1,2,\dots)\\ b_n = \frac{1}{L} \int_{-L}^{L} f(x) \sin \frac{n\pi x}{L} \quad dx ,( n =1,2,\dots) a0=L1LLf(x)dx,an=L1LLf(x)cosLxdx,(n=1,2,)bn=L1LLf(x)sinLxdx,(n=1,2,)
即在函数域上所有的函数都能够被级数表示出来。再由欧拉公式,
e i x = cos ⁡ x + i sin ⁡ x e^{ix} = \cos x + i \sin x eix=cosx+isinx
就能得出
f ( x ) = ∑ − ∞ ∞ C n e n π x L i C n = 1 2 L ∫ − L L f ( x ) ⋅ e − i ⋅ n π x L d x . f(x) = \sum_{-\infty}^{\infty} C_n e^{\frac{n\pi x}{L}i} \\ C_n = \frac{1}{2L} \int_{-L}^{L} f(x) \cdot e^{-i\cdot \frac{n\pi x}{L}} dx. f(x)=CneLxiCn=2L1LLf(x)eiLxdx.
再由角频率公式,即可得
f ( x ) = ∑ − ∞ ∞ C n e i ⋅ n ω 0 x , C n = 1 2 L ∫ − L L f ( x ) ⋅ e − i ⋅ n ω 0 x d x f(x) = \sum_{-\infty}^{\infty} C_n e^{i\cdot n \omega_0 x},\\ C_n = \frac{1}{2L} \int_{-L}^{L} f(x) \cdot e^{-i \cdot n \omega_0 x} dx f(x)=Cneinω0x,Cn=2L1LLf(x)einω0xdx
而当L趋向于无穷大时,整个级数就能表示所有函数域上的函数了,即傅里叶变换公式为
F ( ω ) = F [ f ( x ) ] = ∫ − ∞ ∞ f ( x ) ⋅ e − i ⋅ ω x d x F(\omega) = F[f(x)] = \int_{-\infty}^{\infty} f(x)\cdot e^{-i\cdot \omega x}dx F(ω)=F[f(x)]=f(x)eiωxdx
对应的逆变换为
f ( x ) = F − 1 [ F ( ω ) ] = 1 2 π ∫ − ∞ ∞ F ( ω ) ⋅ e i ⋅ ω x d ω f(x) = F^{-1} [F(\omega)] = \frac{1}{2\pi} \int_{-\infty}^{\infty} F(\omega) \cdot e^{i \cdot \omega x} d\omega f(x)=F1[F(ω)]=2π1F(ω)eiωxdω

而傅里叶变换即是在整个频域分析上最为重要的一环。但由于傅里叶变换仅能将时间信号和频率信号相互转换,且即使用到了短时傅里叶变换将时间加窗,也不能完全将高频和低频的信息完全地呈现出来。而小波变换就存在这样的优点。

时频域分析——小波变换(Wavelet Tranform)

首先来看一张关于FT,STFT,WT之间的对比图(这张图来自台湾阳明大学卢家峰老师的Notes),方便大家来看。
三种信号变换的比较图
一般地讲,信号的高频特征往往需要较少的时间来表现;而对应的,低频特征则需要更多的时间来表现;一般的傅里叶变换或者说快速傅里叶变换(Fast Fourier Transform)仅仅是将时域信号和频域信号之间进行相互转换,并没有具体的去划分来表现特征。且傅里叶变换仅仅能够处理平稳信号,对于非平稳信号并不能有较好地体现。
而短时傅里叶变换(Short-Time Fourier Transform)也只是在时域上加窗(Window),并不能很好地体现信号的特征(高频低时,低频高时)。
那么小波变换(Wavelet Transform)就相对来说解决了这么个问题。

连续小波变换(Continous Wavelet Transform)

在这里,就直接给出公式,但不作过多推导和讲述,因为,计算机能够处理的往往只是离散信号,对于一般的连续信号也需要对这些信号进行采样来获得离散信号来进行处理。

一般连续小波变换公式:
W a , b = ∫ − ∞ + ∞ f ( t ) ψ a , b ( t ) d t , ψ a , b = 1 ∣ a ∣ ψ ( t − b a ) W_{a,b} = \int_{-\infty}^{+\infty} f(t) \psi_{a,b}(t) dt,\\ \psi{a,b} = \frac{1}{\sqrt{|a|}} \psi(\frac{t-b}{a}) Wa,b=+f(t)ψa,b(t)dt,ψa,b=a 1ψ(atb)
从小波图形上来说,连续小波变换较离散小波变换所得到的波形其实更平滑,但由于连续小波变换具有如下缺点:

  1. CWT 具有冗余性;
  2. CWT 的小波数量无穷;
  3. CWT 不具备解析解。
    所以,一般会将连续小波变换进行离散化,一般是将伸缩因子(a)和平移因子(b)进行离散化;

    a j = 2 j , b j , k = k ⋅ 2 j aj = 2^j,\\ b_{j,k} = k \cdot 2^j aj=2j,bj,k=k2j
    得离散小波函数为
    ψ j , k = 1 2 j ψ ( t 2 j − k ) \psi_{j,k} = \frac{1}{\sqrt{2^j}} \psi(\frac{t}{2^j} -k) ψj,k=2j 1ψ(2jtk)

离散小波变换(Discrete Wavelet Transform)

从上面的公式上去理解小波变换可能会非常抽象,下面简单讲一个离散小波变换的例子。
离散小波变换其本质就是一个相关(correlation)运算,只是使用的滤波器不相同。
Level1小波变换图
这是一张Level1的小波变换图,使用一个4系数的高(低)通滤波器对数据进行处理,其实就是一个步长为2的相关运算。x是一个16位的数据,而滤波器是4位的,滤波器在数据上滑动,每次与其对应的x上的4位数据做点击,就获得w中的系数,以步长为2,就可以将数据分成等长的两部分了。因为只做了一次小波变换,所以它是level1的。

EEG信号和DWT

对于小波变换来说,使用不同的小波(其实就是滤波器不同),意味着所用的小波变换就不相同,对于EEG信号来说,小波中与之相关性最好的就是Daubechies-4小波或者db_4小波。
db_4小波的低通滤波器为
h = [ 1 + 3 4 2 , 3 + 3 4 2 , 3 − 3 4 2 , 1 − 3 4 2 ] h = [\frac{1+\sqrt{3}}{4\sqrt{2}},\frac{3+\sqrt{3}}{4\sqrt{2}},\frac{3-\sqrt{3}}{4\sqrt{2}},\frac{1-\sqrt{3}}{4\sqrt{2}}] h=[42 1+3 ,42 3+3 ,42 33 ,42 13 ]
利用小波函数(滤波器)之间的相互正交关系,就可以推出对应的高通滤波器g了。这里给出公式,但不做计算。
g k = ( − 1 ) k h n − k − 1 , k ∈ 0 , 1 , … , n − 1 g_k = (-1)^k h_{n-k-1}, k\in0,1,\dots,n-1 gk=(1)khnk1,k0,1,,n1
然后,信号再经过小波变换后会有两个系数A(approximation)和D(Detail),A系数是经过低通滤波器获得的,而D系数是通过高通滤波器所得到的。以下是我是用db_4小波对一段EEG原始信号进行level4变换得到一个时域图(基于matlab实现,很简单调包就行)。
db_4level4EEG变换
从小波变换的角度来理解,就是说,A3信号是A4信号和D4信号的叠加,A2信号是A3信号和D3信号的叠加,依此类推,即能得到原始信号。
可以看出,EEG信号在经过小波变换后,被分解成了高频(可能存在噪声)和低频成分,所以可说,小波变换其实是对信号进行降频降噪的处理。

而一般来说,不同研究所需的EEG信号频带是不同的,所以用小波变换做EEG信号处理,其实也需要控制小波类型和使用小波变换的次数。

对于癫痫检测来说,使用小波变换将 EEG 信号分解到不同频带可以提取不同频率范围内的信号特征,有助于分析和诊断癫痫。通常情况下,将 EEG 信号分解到 theta(4-8 Hz)、alpha(8-13 Hz)和 beta(13-30 Hz)频带可以提供有用的信息。

一般使用小波变换的方法如下:先是选择基本小波,然后将基本小波平移,缩放,生成一个函数族,构成一个框架,将信号向该框架上投影得到分解信号。选择合适的小波函数,对脑电信号变换,突出需要的特征波形。通过阈值判断,确定是否为待检测的特征波形。

# /etc/profile # System wide environment and startup programs, for login setup # Functions and aliases go in /etc/bashrc # It's NOT a good idea to change this file unless you know what you # are doing. It's much better to create a custom.sh shell script in # /etc/profile.d/ to make custom changes to your environment, as this # will prevent the need for merging in future updates. pathmunge () { case ":${PATH}:" in *:"$1":*) ;; *) if [ "$2" = "after" ] ; then PATH=$PATH:$1 else PATH=$1:$PATH fi esac } if [ -x /usr/bin/id ]; then if [ -z "$EUID" ]; then # ksh workaround EUID=`/usr/bin/id -u` UID=`/usr/bin/id -ru` fi USER="`/usr/bin/id -un`" LOGNAME=$USER MAIL="/var/spool/mail/$USER" fi # Path manipulation if [ "$EUID" = "0" ]; then pathmunge /usr/sbin pathmunge /usr/local/sbin else pathmunge /usr/local/sbin after pathmunge /usr/sbin after fi HOSTNAME=$(/usr/bin/hostname 2>/dev/null) || \ HOSTNAME=$(/usr/bin/uname -n 2>/dev/null) || \ HOSTNAME=$(/usr/bin/hostnamectl --transient 2>/dev/null) || echo "System commands: hostname uname and hostnamectl, which do not exist." HISTSIZE=10000 if [ "$HISTCONTROL" = "ignorespace" ] ; then export HISTCONTROL=ignoreboth else export HISTCONTROL=ignoredups fi export PATH USER LOGNAME MAIL HOSTNAME HISTSIZE HISTCONTROL for i in /etc/profile.d/*.sh /etc/profile.d/sh.local ; do if [ -r "$i" ]; then if [ "${-#*i}" != "$-" ]; then . "$i" else . "$i" >/dev/null fi fi done unset i unset -f pathmunge # Source global bash config, when interactive but not posix or sh mode if test "$BASH" &&\ test -z "$POSIXLY_CORRECT" &&\ test "${0#-}" != sh &&\ test -r /etc/bashrc then # Bash login shells run only /etc/profile # Bash non-login shells run only /etc/bashrc # Check for double sourcing is done in /etc/bashrc. . /etc/bashrc fi export TMOUT=300 export HISTTIMEFORMAT="[%F %T `whoami`] " export PATH=$PATH:/root/srv/node-v20.12.2-linux-arm64/bin 后面加个nginx 的
03-08
<think>好的,我需要帮助用户了解他们提供的/etc/profile文件内容,并在后面添加Nginx相关的配置。首先,我要仔细分析用户提供的代码,理解每一部分的作用,然后思考如何正确地将Nginx的路径添加到环境变量中。 首先,用户提供的/etc/profile脚本主要功能是设置系统范围的环境变量启动程序。里面定义了pathmunge函数,用于安全地添加路径到PATH变量,避免重复。接着根据用户是否是root来调整PATH,添加不同的系统路径。然后设置了一些历史记录相关的变量,导出环境变量,最后加载/etc/profile.d/下的脚本/etc/bashrc。 用户的需求是在这个文件后面加上Nginx的配置。根据之前的代码结构,正确的做法应该是将Nginx的可执行文件目录添加到PATH中。通常Nginx安装后,可执行文件位于/usr/local/nginx/sbin或者/usr/sbin/下,但具体位置可能因安装方式不同而变化。需要确认用户Nginx的实际安装路径。 观察到用户之前已经添加了Node.js的路径到PATH,使用的是export PATH=$PATH:/root/srv/node-v20.12.2-linux-arm64/bin。这说明用户可能希望将Nginx的sbin目录也追加到PATH中。例如,如果Nginx安装在/usr/local/nginx,那么路径可能是/usr/local/nginx/sbin。所以应该添加类似export PATH=$PATH:/usr/local/nginx/sbin的语句。 同时,需要注意在/etc/profile中修改PATH的正确方法。根据现有脚本,如果是root用户,pathmunge会优先添加/usr/sbin/usr/local/sbin,而非root用户则追加。不过用户之前直接使用export,可能简单直接,但需要考虑是否应该使用pathmunge函数来避免重复添加。不过原文件中在最后已经处理了PATH的导出,所以直接追加可能合适,或者在适当的位置调用pathmunge。但根据用户之前的做法,可能倾向于直接export。 另外,要注意Nginx的路径是否正确,用户可能需要根据实际安装路径调整。例如,如果通过包管理器安装,可能已经在PATH中,无需额外添加。如果是源码编译安装在自定义目录,则需要确认路径。 最后,应该提醒用户修改完成后需要source /etc/profile或重新登录使配置生效,并测试nginx命令是否可用。</think>我来为您解读这个`/etc/profile`文件并说明如何添加Nginx配置: **一、/etc/profile核心功能解析** 1. **路径管理函数** `pathmunge()`函数实现了: - 检查路径是否已存在 - 支持前置(`PATH=$1:$PATH`)或后置(`PATH=$PATH:$1`)添加路径 - 避免路径重复添加 2. **用户身份识别** 通过`/usr/bin/id`命令获取: ```bash EUID=$(id -u) # 有效用户ID UID=$(id -ru) # 真实用户ID USER=$(id -un) # 用户名 ``` 3. **PATH差异化配置** 根据用户权限分配路径: ```bash if [ "$EUID" = "0" ]; then # root用户 pathmunge /usr/sbin pathmunge /usr/local/sbin else # 普通用户 pathmunge /usr/local/sbin after pathmunge /usr/sbin after fi ``` 4. **历史记录配置** ```bash HISTSIZE=10000 # 存储10000条历史 HISTCONTROL=ignoreboth # 忽略重复命令空格开头的命令 HISTTIMEFORMAT="[%F %T `whoami`] " # 记录执行时间用户 ``` **二、添加Nginx配置建议** 1. **添加环境变量**(在文件末尾`export PATH`之前添加): ```bash # Nginx Path NGINX_HOME=/usr/local/nginx # 根据实际安装路径修改 pathmunge $NGINX_HOME/sbin after # 将sbin目录加入PATH export NGINX_HOME ``` 2. **最终效果示例**: ```bash export PATH=$PATH:/root/srv/node-v20.12.2-linux-arm64/bin export NGINX_HOME=/usr/local/nginx export PATH=$PATH:$NGINX_HOME/sbin ``` **三、配置验证方法**: ```bash source /etc/profile # 使配置立即生效 which nginx # 查看nginx路径 nginx -v # 验证版本 ``` **四、注意事项**: 1. 路径`/usr/local/nginx`需要与实际安装路径一致 2. 建议优先使用`pathmunge`函数而非直接export,避免路径重复 3. 如果使用Docker安装Nginx,则不需要此配置 4. 生产环境建议将配置写在`/etc/profile.d/nginx.sh`中 **完整配置位置建议**: ```bash # 在现有PATH导出语句之后添加 export PATH=$PATH:/root/srv/node-v20.12.2-linux-arm64/bin # 新增nginx配置 NGINX_HOME=/usr/local/nginx pathmunge $NGINX_HOME/sbin after export NGINX_HOME ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值