什么叫信纳比与信噪比的区别比

 for循下面那句是怎么算的还有在丅面一句为什么要除以7

}

     树莓派是最近流行嵌入式平台其自由的开源特性以及低廉的价格,吸引了来 自全球的大量极客和计算机大咖的关注来自各大树莓派社区的幕后英雄,无私地在这个开源硬件平台上做了大量的工作将其打造成了世界上通用性最好,也最自由的计算机学习平台之一我本人感兴趣的学习主题是Linux操作系统囷Python编程,在流连于各大树莓派社区向各位大神学习的过程中感觉获益良多结合自己擅长的实时信号处理工作,也做了一些小小的尝试鈈能说做了什么独创性工作,但愿意分享给各位后来者以下原创内容欢迎网友转载,但请注明出处:cnblogs.com/helesheng

一、树莓派Raspbian系统的实时性

   Raspbian是树莓派朂常用的Debian Linux操作系统也是树莓派官方推荐的系统。这个系统集成了Debian系统的良好看操作性和易用性具有非常成熟的开源支持。但Linux系统内核並非实时操作系统在对系统硬件进行操作时很难保证系统的实时性。

用以下shell命令安装Python GPIO对其实时性进行测试。

测试仪器是逻辑分析仪簡单连接BCM模式下的#17号引脚如下图所示。

图1 用逻辑分析仪分析Raspbian的实时性

注:如果不清楚树莓派GPIO的引脚位置可以通过在Linux终端输入指令:gpio readall 来查询BCM囷wirePi模式下引脚的位置

编辑以下简单Python测试脚本:

用逻辑分析仪测试#17引脚输出的波形如左下图所示。

   由上图可知实际的延迟时间为1.08ms(紫色標签M1和黄色标签M2之间的时间差),实时误差约为80us

   将上面代码中的延迟时间DLY_TM改为0.0001(100us),测试结果如下图可见实际的延迟时间为180us,实时误差仍为约为80us

   这个80us的延时误差应该是由Linux内核调度器和Python解释器共同造成的,很难进一步降低且上述测试是在树莓派空载情况下进行的——當Linux内核调度更多线程时这个延迟时间不但将进一步增加,而且可能变成一个随机时间

   80us数量级的实时误差,对于控制自动小车、3D打印机这類应用已经绰绰有余但对于需要精确控制时间的任务显然是不够的。

   由于Python具有非常强大的数字信号处理能力但树莓派不含有A/D转换器,峩决定为树莓派添加一个强实时性的高速A/DD/A转换装置,在树莓派上实现Python实时数字信号处理

Jitter)抖动理论两次采样间时间间隔的随机变化,將造成A/D和D/A转换信纳比与信噪比的区别比(SNR)和有效分辨率(ENOB)的降低这种采样间隔之间的随机变化称为孔径抖动。这里计划为树莓派设计一個转换率为1MSPS,包含和A/D和D/A转换功能辨率为12bits的模拟前端。根据孔径抖动和信纳比与信噪比的区别比之间的计算公式[1]: 

    其中tj是孔径抖动时间根據上式得到采样频率、信纳比与信噪比的区别比和要求的孔径抖动之间的关系图[2]

图3 采样频率、信纳比与信噪比的区别比和孔径抖动的关系 

     由上图可知为达到1MSPS下10~12bits的有效分辨率ENOB(或60Db以上的信纳比与信噪比的区别比)应将孔径抖动时间控制在100ps以下,远远小于树莓派(运行Linux系统條件下)能够提供的80us的时间分辨率为此必须采用实时性更强的模拟前端控制器。

 常见的实时控制方案有MCU和FPGA两种FPGA实时性最好,但开发难喥较大成本也高,与树莓派的开源和低成本精神不完全吻合比较合理的方案是用MCU实现。但如果采用传统的MCU定时器软件中断法来实现转換定时控制则定时精度受中断服务程序入口的影响,孔径抖动在MCU指令周期数量级以72MHz的STM32F103系列为例,定时器中断法产生的孔径抖动在1/72MHz≈13.9ns数量级远高于12bits@1MSPS的A/D和D/A转换要求。但STM32为它的ADC模块提供了强有力的DMA支持DMA对转换结果的转存不受指令影响,可以实现极佳的采样定时控制将孔徑抖动降低到1ns以下。

 采用STM32作为实时模拟前端的控制器还要实现树莓派和STM32之间的数据交互——树莓派发送数据给STM32来进行D/A转换;接收STM32进行A/D转換的结果。树莓派扩展接口提供了GPIO、SPI、I2C(SMBUS)等几种接口为降低传输延迟我采用了速度最快的SPI接口来连接STM32实时前端。传输过程中树莓派作为SPI主機用户通过用户界面驱动SPI口发起通信;STM32作为SPI从机被动进行通信,以上传A/D转换结果和接受D/A转换数据

 当树莓派不发起通信的时候,STM32通过DMA1通噵1不停地将转换结果写入其内部RAM中的A/D转换循环缓冲区中同时不断地将D/A循环缓冲区中的数据从D/A转换器中输出。当树莓派接收到用户命令进荇通信时首先通过GPIO通知STM32。STM32在收到命令后找到A/D缓冲区最后放入循环队列中的数据,并将整个队列中的数据按时间顺序搬运到发送缓冲区再通过GPIO告诉树莓派“可以开始通信了”。树莓派在收到STM32发来的确认信息后发起连续的SPI通信一方面通过MOSI引脚将希望D/A转换器转换的数据队列发送给STM32,另一方面从MISO口接收STM32发送缓冲区中的A/D转换数据其结构框图如下图所示。

图4 树莓派和实时性前端功的能框图

    根据上述思路,我设计叻下图左侧所示的PCB:模拟信号从最左侧的单排针接插件进入;STM32的SPI和GPIO接口则通过下图中部的标准的树莓派扩展接口连接到树莓派上其中STM32使鼡了集成A/D和D/A转换器的Cortex-M3系列芯片STM32F103RC。

图5 树莓派和实时性前端功的实物图

   NumPy和Matplotlib是Python上著名的数值计算和图形扩展库提供了丰富而强大的信号处理和顯示功能。其使用方法类似常用的Matlab但幸运的是在开源的Linux和Python世界里,它们都是免费的!在树莓派上没有安装它们的小伙伴们可以用以下指囹安装 

   树莓派上安装matplotlib很可能由于缺少Cario图形库无法运行,如果出现这种情况请执行以下指令

   在Python脚本中如下方式导入上述两个模块,就可鉯在树莓派上开心的玩耍数字信号处理了

1、产生D/A输出所需的信号

利用NumPy产生正弦信号的Python脚本如下:

熟悉Matlab的小伙伴看起来是不是非常亲切。還可以为D/A产生的信号增加几个高次谐波将第二句改为:

最后为方便Python和实时信号前端的数据传输,将s强制类型转换为16位无符号整型:

2、对A/D采集到的数据进行简单处理

为了演示NumPy和Matplotlib的信号处理和绘图功能我对A/D采集得到的数据进行了简单的处理。

1)绘制采集到数据的波形Python脚本代碼如下。

    其中Sample_rate是A/D转换的采样率;t_scale是一个NumPy数组,内容是显示的X轴数值;res_float也是一个数组内容是折算为电压值的A/D转换结果。subplot()方法将打开一个2荇1列的绘图窗口这个时域波形被绘制在第1行第1列的波形图中。

2)计算和绘制FFT产生的幅频特性

   为减少数据时域截断造成的能量泄露先对数據进行加窗处理,再将其显示在上面开启的绘图窗口的第2行的波形图中代码如下:

    其中sw是经过加窗,且去除直流分量后的信号;D_LEN是以字節为单位的数据传输的长度每个采样点对应两个字节,因此信号的长度为D_LEN/2;f_scale是绘图后X轴也就是频率轴的数值;NumPy中的fft()方法输出快速傅里葉变换的结果,是个复数数组sfa_lg是频率折算为dB后的数值。

四、STM32构成的实时性前端

   如图4所示由STM32构成的实现前端控制器主要完成以下工作:

  • 通过DMA1的通道1(CH1)控制ADC完成固定采样率的A/D采集,并将数据存入到循环缓冲区ADC_DMA_BUF
  • 通过DMA1的通道4(CH4)和5(CH5)控制SPI口和树莓派通信:接收树莓派发送嘚D/A数据到缓冲区SPI_RX_DMA_BUF;向树莓派发送缓冲区SPI_TX_DMA_BUF中的A/D转换数据。

    另外为了在树莓派人机交互界面的同步下,有序的完成:采集、数据搬运和传输笁作实时前端要在两对GPIO连接:SHK_IN(树莓派输入/STM32输出)和SHK_OUT(树莓派输出/STM32输入)的同步下工作。

   A/D采集在STM32复位后不断的循环进行DMA1的CH1被配置为循環模式,数据将采用循环队列的数据结构存储到宽度为半字(HalfWord16bits)的ADC_DMA_BUF中。配置代码如下所示:

 上述代码配置STM32的ADC的采样时间为1.5个ADC时钟周期加上一次完整的逐次逼近过程所需的12.5个周期,共14个时钟周期ADC时钟为外设时钟56MHz的四分之一,刚好14MHz这样进行一次完整A/D转换的时间刚好为1us,即实现了1MSPS的采样率ADC模块被配置为连续扫描通道1,并在转换完成后直接触发一次DMA1的数据传输这样整个采集和存储工作由纯硬件来完成,無需软件干预严格的控制了A/D转换的孔径抖动时间,有效的提升了A/D转换的实时性

   DMA2的CH3也被配置为循环模式,程序运行过程中会不断的将SPI_RX_DMA_BUF中嘚数据发送到D/A转换器中从而形成连续的波形。而DMA2 CH3向DAC发送数据的时间间隔就是两次D/A转换的间隔所以DMA2的CH3需由额外的定时器(TMR)来触发传输。DMA2 CH3的配置代码如下所示:

   TMR2的定时的溢出计数值被设置为7*8=56,在56MHz主频下将产生1MHz的溢出率即D/A转换器的刷新率也是1MSPS。如前所述如果采用在TMR2中断中甴软件来刷新DAC,将会提高造成D/A输出间隔的孔径抖动因此这里选择了通过定时器硬件触发DMA传输的方式来实现D/A数据的刷新的方式,大大提高叻D/A输出波形的信纳比与信噪比的区别比

   A/D和D/A转换由硬件控制,并自动定时进行的但与树莓派的数据交互却是由树莓派发起的,与STM32中的程序运行不同步如图4所示,双方在握手信号SHK_IN和SHK_OUT的控制下通过SPI口的双向交互数据。其中树莓派发起通信作为SPI主机;STM32作为从机。由于从机無法预知主机何时发起通信因此也通过DMA来实现自动收发数据,其中DMA1

   由于A/D转换数据在不断的刷新中树莓派发起通信的时A/D转换数据可能存放到了缓冲区ADC_DMA_BUF的任意位置。如果直接将ADC_DMA_BUF中的数据发送给树莓派则树莓派得到的将是一个首地址指针错误的循环队列,无法解读为正确的數据因此,我采用了图4所示的双缓冲数据结构树莓派发起通信时首先读取DMA1 CH1的当前位置,再根据这个首地址指针将ADC_DMA_BUF中的数据按顺序重新搬运到发送缓冲区SPI_TX_DMA_BUF中然后再启动DMA2 CH4和CH5的SPI通信,将数据发送给树莓派控制ADC_DMA_BUF和SPI_TX_DMA_BUF数据结构调整的代码如下所示:

虽然D/A转换也是不断循环进行的,但对于D/A数据缓冲区的刷新却没有A/D数据缓冲区的问题:树莓派可以在任何时刻整体刷新D/A缓冲区输出波形将在一个DMA周期后输出正确的新数據波形。

五、用树莓派的SPI和GPIO控制实时前端

为实现树莓派和实时前端的数据交互需要使用树莓派扩展接口中的两个GPIO口和一个SPI设备。

   GPIO的安装使用较简单如本文第一部分所述在Linux的shell命令行中安装控制GPIO模块后就可以在Python脚本中导入GPIO模块来使用。本程序只用到3个GPIO分别用于读取按键和與STM32的握手信号,它们的初始化代码如下所示:

  其中需要注意的是GPIO.setpu()方法的第三个参数:pull_up_down = GPIO.PUD_UP这个参数用于将这个GPIO配置为弱上拉模式,以保证在沒有输入信号的时候这个GPIO是高电平。接下来只需要通过GPIO.input()方法来读取GPIO状态和GPIO.output()来设置输出电平即可。这里就不再赘述了

   树莓派的SPI配置相對较麻烦,首先需要开启这个功能可以在命令行中用:

   命令来开启命令行下的树莓派配置程序,并从中开启SPI功能如果你安装了图形界媔则简单得多,Raspbian系统的开始菜单中打开Preferences菜单下的Raspberry Pi Configuration就可以在下图所示的图形界面中开启SPI功能。

  安装成功后如下图所示可以在/dev下看到spidev0.0和spidev0.1两個设备, 这两个SPI设备拥有同样的时钟和数据传输引脚,只是片选引脚不同

spidev模块在Python下的使用并不复杂,首先导入模块:

其次初始化SPI口Python代码洳下:

 其中open()方法的两个参数分别是SPI口的编号和片选引脚的编号。max_speed_hz是以Hz为单位的SPI同步时钟频率这里使用了10MHz的通信频率。而mode属性只有两个位第一个位CPOL表示通信空闲时SCK的电平——0为低电平,1为高电平;第二个位CPHA表示在时钟SCK的第几个边沿读取SPI数据线上的数据——0为在空闲状态恢複的第一个边沿读取SPI数据而1表示在空闲恢复后的第二个边沿读取数据。这里将这两个位都设置为0表示SCK在空闲状态处于低电平,而进入通信后在SCK的第一个边沿也就是上升沿开始读取数据。

其中tx_data是由待发送数据构成的Python列表长度不限。返回rx_data是和tx_data长度相同的列表存放了SPI收箌的数据。

与实时前端进行通信的树莓派Python主程序负责完成:发送D/A转换数据包接收A/D转换数据包,以及和用户实时交互的工作其代码如下所示: 

   整个程序的最外层是一个异常检测、处理程序:当终端收到“CTL+C”时终止程序,否则不断循环交互数据和显示结果

   第二层是一个无條件循环,用于检测和树莓派25号GPIO相连的按键并消除按键上的抖动:如果有按键就开始一轮新的数据交互和显示,如果没有就继续循环和等待

 第三层代码在检测到按键后启动,用于和STM32交互数据然后显示结果:首先通过RP_SHK_OUT拉低来启动STM32的数据交互待STM32准备好后通过将RP_SHK_IN拉低来通知樹莓派,树莓派接到消息后通过xfer()方法来启动SPI数据传输数据交互完成后存放在返回列表中的是以高低字节存放的8位数据,程序首先将它们拼接在一起再将数据转换为0-3.3V的实际电压信号,并保存为CSV格式的数据文件随后程序对这些数据进行前述的数据处理,随机显示数据和处悝结果最后,程序将等待本次按键释放然后退回上一层代码等待按键来启动下一次数据交互和结果显示。

用函数信号发生器分别产生20KHz、50KHz、100KHz和200KHz的正弦信号并利用上述实时前端,以1MSPS采样率进行500次采样树莓派中运行的Python程序调用NumPy模块进行FFT变换后得到的信号的频谱后,再调用matplotlib模块绘图结果如下图8-图11所示。其中上部的红色波形是时域数据下部的蓝色波形是红色数据的频谱图。

图8 对10KHz正弦信号采样和FFT变换的结果

圖9 对50KHz正弦信号采样和FFT变换的结果

图10 对100KHz正弦信号采样和FFT变换的结果

图11 对200KHz正弦信号采样的结果

    对20KHz的三角波进行采样结果如下图所示。可以明顯的看到作为一种对称的周期函数,三角波的存在能量较大的奇次谐波

图12 对20KHz三角波信号采样的结果

   文献[3]指出,FFT频谱的理论噪底(噪声岼面)等于:

   其中SNR为理论信纳比与信噪比的区别比,M是进行FFT的数据点数理论信纳比与信噪比的区别比SNR的计算公式为[4]

   N为转换器位数,STM32嘚A/D转换器为12bits对于图8-图11所示的500点的FFT,SNR的理论值为74dB噪声平面为-94dB。显然图8-图11所示的对正弦信号的测试结果噪声平面有效值在-60dB左右——远高於理论值。

   进一步尝试计算信纳比(SINAD)来评估采样结果。信纳比定义为:实际输入信号的均方根值与奈奎斯特频率以下包括谐波但直流除外的所有其它频谱成分的均方根和之比[4]在树莓派上用Python和NumPy模块实现信纳比的计算,代码如下 

   编程的基本思路是找到能量最高的频点,並将其附近的两个w内的能量值都作为信号的能量用信号能量与其他所有点的噪声能量相除从而得到信纳比。在主程序中的调用方式如下

   经计算得到图8-图11所示信号的信纳比在44-46dB左右,低于理论值74dB(在理想情况下理论信纳比SINAD等于理论信纳比与信噪比的区别比SNR)。造成信纳比低于信纳比与信噪比的区别比的原因可能有:

  1)从实物图5中可以看到函数信号发生器和实时性前端的模拟输入采用了鳄鱼夹和单股導线连接,很可能造成了信号的失真周期性的失真将造成谐波干扰,而这一点可以在图8-图11的频谱图中都可以观测到——信号的二次谐波頻率点上都有明显的能量突出

  2)STM32的A/D转换模块本身属于SoC的一部分,由于模数隔离等原因其模拟性能可能不如单独的ADC芯片,距离SINAD的理論值更是存在一定差距

  3)STM32布线时没有严格区分模拟电源、模拟地和数字电源、数字地,并分别对模拟电源——模拟地以及数字电源——数字地去耦。

  4)STM32锁相环所产生的系统时钟可能存在较大孔径抖动从而造成信纳比降低。

   在每次数据交互前需要将D/A输出的数據存入列表tx_data中,可用numpy模块产生一个单频的正弦信号其中,计算产生的正弦值被增加了211的直流偏置以将所有数值转换为正数。由于SPI通信嘚基本单位是1个字节因此数据最后要分解为高低两个字节。 

   用spi.xfer()方法启动一次双向通信后用示波器观察D/A输出的信号如下图所示,其中栲上的绿色部分是D/A输出的时域波形,靠下的红色部分是示波器对时域波形进行FFT得到的频谱图

图12 示波器观测D/A产生的单频信号

用示波器观察仩面代码产生的波形及其频谱如下图所示。

图13 示波器观测D/A产生的三频信号

}

高速ADC的时钟jitter会影响高速ADC的信纳比與信噪比的区别比SNR而信纳比与信噪比的区别比决定了模拟前端输入的有效范围。所以需要先确定模拟前端的有效输入范围然后确定应該满足的SNR,然后推导出时钟jitter 

假设ADC的最大输入幅度是Vpp(单位V),分辨率位数N位有效位数ENOB位。   

有效位数ENOB是ADC的N位分辨率中实际有用的位数N位ADC理论最小分辨率满足.

然而如果ADC的噪声信号大于1LSB,则ADC采样信号的N位表示中并不是每一位都能表示采样信号所以实际的分辨率位数会小于N,实际的分辨率位数我们称为有效位数ENOB因此对于ADC来说,更加有效的参数是ENOB而不是N,ADC实际的最小分辨率应该为:

二、有效位ENOB、信纳比与信噪比的区别比SNR、信纳比SINAD总谐波失真THD之间的关系

SNR的定义是信号幅度均方根与噪声幅度均方根的比值。假设信号幅度均方根是S噪声均方根是N,则

SINAD是信号幅度均方根与所有其它频谱成分(包括谐波但不含直流)的和方根的平均值之比

假设信号谐波幅度均方根是N,则

THD指的是基波信号的均方根值与其谐波(一般仅前5次谐波比较重要)的和方根的平均值之比假设2次、3次、4次以上的和谐波失真分别为HD2,HD3HDn,总谐波失真是D则THD可以用下面公式求解:

有些ADC的datasheet提供里THD的值,但是也有一些没有直接提供THD值得没有提供THD值得可以使用HD2,HD3HDn计算。

信纳比和有效位数之間满足一个确定的关系:

因此我们可以根据所需要的ENOB来推导出ADC需要满足的SINAD的值 由SINAD、THD和SNR的定义可以推导出如下公式:

THD是ADC可以通过ADC的datasheet直接查找到或者间接求出来,所以对于满足需求的SINAD我们能够推导出来SNR应该满足的条件。

ADC的SNR主要由三部分引起:量化噪声热噪声,抖动噪声

ADC對采样信号量化的时候,一定会产生一定的误差从量化上来讲实际信号和量化后的信号之间的误差最大为0.5LSB。量化误差如下图所示:

量化誤差引起的信纳比与信噪比的区别比计算公式:

热噪声是芯片固有的一个噪声由采样缓存器噪声,采样切换阻抗等引起的是一个定值,一般ADC都会给出热噪声的信纳比与信噪比的区别比如果没有给出可以使用下面公式计算:

3.3、抖动噪声 抖动噪声主要是由于时钟抖动和孔徑抖动造成的。

上面两个图分别描述了时钟抖动和孔径抖动对采样点的影响这两个抖动都会造成采样点的偏移,然而最后对数据处理的時候会默认这些点都在理想位置采样的,在频域上会造成信号频率的弥散;另外一个理解方法是每一个采样点的实际采样值和理想采样徝都有一定的偏差相当于对每一个点都叠加了一个噪声。 时钟抖动引起的噪声的信纳比与信噪比的区别比使用下面公式计算:

从上面两個公式可以得出信纳比与信噪比的区别比与采样时钟jitter成反比与输入信号频率成反比,因此对于输入信号的频率越高对时钟信号的jitter要求樾严格。

ADC总噪声是量化噪声抖动噪声之和。量化噪声很多时候并不考虑因为很多时候热噪声会远远大于量化噪声。当信号频率较低的時候主要考虑热噪声,当信号频率较高的时候才会考虑抖动噪声。

ADC总信纳比与信噪比的区别比用下面公式计算:

第二幅图是jitter、fin、ENOB之间嘚关系从上往下是不同fin对应的SNR,频率是从上依次1MHz到501MHZ,步长50MHz

从图中可以看出:fin越高,信纳比与信噪比的区别比越大ENOB越小,jitter越大信納比与信噪比的区别比越大,ENOB越小为了保证AD9680比较好的转换性能,最好使时钟jitter低于150fs能够保证10位以上的有效位数。

第二幅图是jitter、fin、ENOB之间的關系从上往下是不同fin对应的SNR,频率是从上依次1MHz到251MHZ,步长50MHz

从两款芯片的jitter求解结果中能够发现,采样频率越高信号频率越高的ADC对时钟jitter偠求越严格。AD9680为了保证比较好的性能需要小于150fs的jitter;AD54J54为了满足较好性能,需要小于300fs的jitter

在翻阅不同ADC的datasheet,发现一个参数的规律越是采样速喥高的ADC,孔径抖动越小这个参数是ADC本身固有的,是与芯片设计相关的孔径抖动和时钟抖动同样的原理影响着ADC性能。为了更高的采样频率芯片开发商会设计更小的孔径抖动,通过这个参数我们也可以快速估算时钟抖动的大小。当时钟抖动小于孔径抖动的时候能得到非常好的ADC性能,当两者相仿的时候依然能保持很好的性能,当时钟抖动是孔径抖动的两三倍的时候性能还比较好,当这个比例更大的時候就需要参考采样信号的频率来具体分析。因此在设计ADC时钟的时候可以将抖动粗略设为孔径抖动的两倍以内。 

}

我要回帖

更多关于 信纳比与信噪比的区别 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信