如何从Raspberry Pi Pico的模数转换器捕获数据计算?

描述

了解如何在Raspberry Pi Pico上以高达500 kHz的频率采样并根据捕获的数据计算快速傅立叶变换。

硬件部件:

Raspberry Pi Pico× 1个

在此项目中,我们将使用一些特殊功能以极快的速度从Raspberry Pi Pico的模数转换器(ADC)捕获数据,然后对数据进行快速傅立叶变换。这是许多项目的常见任务,例如涉及音频处理或广播的项目。

很可能您已经有了一个想要从中收集数据的传感器。就我而言,我有一个麦克风连接到Pico的A0输入。如果您只是来这里学习,则可以使模拟输入悬空而无任何连接。

您可以在GitHub上找到完整程序。

1.背景

Raspberry Pi Pico如此有用的一个主要原因是其众多的硬件功能使处理器从执行常规I / O任务中解放出来。在我们的例子中,我们将使用Pico的直接内存访问(DMA)模块。这是一项硬件功能,可以自动化任务,涉及以极快的速度将大量数据进出内存到IO。

可以将DMA模块配置为在准备好样本后立即将它们从ADC中取出。以最快的速度,您可以在高达0.5 MHz的频率下采样!

收集所有这些数据后,您可能需要对其进行一些处理。一个常见的任务是将您的信息从时域转换到频域以进行进一步处理。就我而言,我有一个麦克风,我想从该麦克风收集音频样本,然后计算样本中包含的最大频率分量。最常用的算法是快速傅立叶变换。

2. ADC采样代码

如果您还没有这样做,我强烈建议您在GitHub上克隆Raspberry Pi的pico-examples库。这是我用来开始的所有采样代码的地方。以下代码的很大一部分来自此存储库中的dma_capture示例。

我将介绍软件的一些关键要素,以解释发生了什么。您可以在“代码”部分找到完整的程序。

// set sample rate

adc_set_clkdiv(CLOCK_DIV);

这条线确定ADC收集样本的速度。“ clkdiv”是指时钟分频,它使您可以分割48 MHz基本时钟,以更低的速率进行采样。目前,一个样本需要96个循环来收集。这样得出的最大采样率是每秒48、000、000个循环/每个样本96个循环=每秒500、000个样本。

为了降低采样速度,可以增加时钟分频。将CLOCK_DIV设置为960将使每个样本的循环数增加10倍,从而每秒产生50000个样本。您猜到了,将CLOCK_DIV设置为9600可以得到每秒5 000个样本。

void sample(uint8_t *capture_buf) {

adc_fifo_drain();

adc_run(false);

dma_channel_configure(dma_chan, &cfg,

capture_buf, // dst

&adc_hw-》fifo, // src

NSAMP, // transfer count

true // start immediately

);

gpio_put(LED_PIN, 1);

adc_run(true);

dma_channel_wait_for_finish_blocking(dma_chan);

gpio_put(LED_PIN, 0);

}

该功能实际上是从ADC收集样本。处理器复位ADC,排空缓冲区,然后开始采样。它还将在采样期间打开LED,以便您查看正在发生的情况。

3. FFT代码

// get NSAMP samples at FSAMP

sample(cap_buf);

// fill fourier transform input while subtracting DC component

uint64_t sum = 0;

for (int i=0;i《NSAMP;i++) {sum+=cap_buf[i];}

float avg = (float)sum/NSAMP;

for (int i=0;i《NSAMP;i++) {fft_in[i]=(float)cap_buf[i]-avg;}

上面的这一部分用ADC的采样填充cap_buf数组,然后对其进行预处理以进行傅立叶变换库。对于许多应用程序,在对数据进行傅里叶变换之前,先从数据序列中减去平均值是有利的。否则,任何直流电平(信号偏移会超过零)将导致输出频点接近零而具有巨大的幅度。我使用的库KISS FFT期望信号具有浮点类型,因此我在减去均值的同时也转换了样本。

// compute fast fourier transform

kiss_fftr(cfg , fft_in, fft_out);

// compute power and calculate max freq component

float max_power = 0;

int max_idx = 0;

// any frequency bin over NSAMP/2 is aliased (nyquist sampling theorum)

for (int i = 0; i 《 NSAMP/2; i++) {

float power = fft_out[i].r*fft_out[i].r+fft_out[i].i*fft_out[i].i;

if (power》max_power) {

max_power=power;

max_idx = i;

}

}

float max_freq = freqs[max_idx];

printf(“Greatest Frequency Component: %0.1f Hz\n”,max_freq);

下一部分将计算FFT,然后计算输出数据中的最大频率分量。FFT的输出是复数值,因此要获得可用的功率值,可以取复结果的大小。

还要注意的是,与其循环遍历FFT的所有NSAMP输出值,我们仅对NSAMP / 2进行装箱。由于奈奎斯特采样定理,任何大于采样率1/2的频率都将被混叠在一起,因此这些bin对我们没有用。这是信号处理的基本结果,如果您不熟悉,则值得进一步研究!

就音频而言,人耳通常可以听到高达20 kHz左右的频率。我使用的CLOCK_DIV值为960,产生的采样率为50 kHz。因此,我可以捕获的最大非混叠频率为25 kHz,这应该绰绰有余!

// BE CAREFUL: anything over about 9000 here will cause things

// to silently break. The code will compile and upload, but due

// to memory issues nothing will work properly

#define NSAMP 1000

需要指出的最后一点代码是NSAMP或收集的样本数。在信号处理中,在较高和较低数量的样本之间存在一个基本的权衡。更多的样本将花费更长的时间来收集和处理,但是会产生更高分辨率的傅里叶变换。更少的样本将导致更短的采样周期和更快的处理,但是您的傅立叶变换将更加精细。

对于Pico,我发现分配过多的内存会导致难以调试的失败。如果您将NSAMP设置得太大,您的Pico将没有足够的内存来分配给保存样本的阵列。该代码仍然可以编译和上传,但是您可能会得到一些奇怪的行为。在我的示例中,将NSAMP保持在9000以下似乎很好。

3.编译和上传

如果尚未下载,请下载Raspberry Pi Pico入门。这是一个坚实的资源,可为您提供设置构建系统,编译C / C ++代码并将其上传到Pico所需的一切。

以下所有说明均适用于macOS / Linux,但我想Windows上的CMake也有类似的过程。

要编译我的代码,请先在GitHub上下载我的存储库。

导航到adc_fft目录

创建一个名为“ build”的目录

在其中导航,然后键入“ cmake 。./”

输入“ make”,如果正确安装了Pico构建系统,则所有内容均应编译

将您的Pico放入引导加载程序模式,然后将adc_fft.uf2文件拖放到出现的驱动器中

那应该是全部!您可以通过USB监视程序的输出。它将在从A0采样的数据中输出最大频率分量,并且LED应该快速闪烁。
       责任编辑:pj

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分