如何获取原函数*data值并将文件读取改为USB流实现FFT变换?
问题解答
1. 如何获取原始函数中*data的值?
data是int16_t*类型的动态数组,获取其值的方式如下:
- 单个元素访问:通过下标直接读取,例如
int16_t firstSample = data[0];即可拿到第一个采样值,下标范围是0到numSamples-1。 - 遍历所有元素:用循环逐个读取,示例代码:
for (uint32_t i = 0; i < numSamples; ++i) { int16_t currentSample = data[i]; // 对当前采样值进行处理 }
- 指针直接访问:使用
*(data + i),效果和data[i]完全等价,比如int16_t sample = *(data + 5);可以获取第6个元素的值。
2. USB流数据接入FFT变换的实现方案
核心思路
原代码是一次性读取完整的numSamples个int16_t采样点,USB流是分批传输数据,因此需要先缓存流数据,直到凑够所需的采样点数,再转换为int16_t类型接入FFT逻辑。
修改后的完整代码
#include <cstdint> #include <vector> #include <iostream> #include <fftw3.h> void usbStream2FFT() { const uint32_t numSamples = 1920018; const size_t totalBytesNeeded = numSamples * sizeof(int16_t); // 用vector做动态缓存,自动管理内存 std::vector<uint8_t> dataBuffer; dataBuffer.reserve(totalBytesNeeded); // 提前创建FFT计划和缓冲区,避免循环内重复创建浪费资源 fftw_complex* in = reinterpret_cast<fftw_complex*>(fftw_malloc(sizeof(fftw_complex) * numSamples)); fftw_plan plan = fftw_plan_dft_1d(numSamples, in, in, FFTW_FORWARD, FFTW_ESTIMATE); // 缓存足够的字节数据 while (dataBuffer.size() < totalBytesNeeded) { uint32_t rxSize = 0; if (FT4222_SPISlave_GetRxStatus(ftHandle, &rxSize) == FT_OK && rxSize > 0) { uint8_t* pRead_data = reinterpret_cast<uint8_t*>(malloc(rxSize)); if (!pRead_data) continue; // 补充实际读数据的API调用,替换为FT4222_SPISlave_Read的真实逻辑 uint32_t actualReadSize = rxSize; // FT4222_SPISlave_Read(ftHandle, pRead_data, rxSize, &actualReadSize); // 将读取的字节加入缓存 dataBuffer.insert(dataBuffer.end(), pRead_data, pRead_data + actualReadSize); free(pRead_data); } } // 将缓存的字节转换为int16_t数组(注意字节序,若设备与主机字节序不同需做转换) int16_t* data = reinterpret_cast<int16_t*>(dataBuffer.data()); // 填充FFT输入缓冲区 for (uint32_t i = 0; i < numSamples; ++i) { in[i][0] = static_cast<double>(data[i]); in[i][1] = 0.0; // 实信号虚部设为0 } // 执行FFT变换 fftw_execute(plan); // 输出FFT结果 for (uint32_t i = 0; i < numSamples / 2; ++i) { double realPart = in[i][0]; double imagPart = in[i][1]; double magnitude = sqrt(realPart * realPart + imagPart * imagPart); std::cout << "Frequency bin " << i << ": Magnitude=" << magnitude << std::endl; } // 清理资源 fftw_destroy_plan(plan); fftw_free(in); }
关键注意事项
- 字节序处理:如果USB设备传输的
int16_t数据字节序与主机端不一致(比如设备是大端、主机是小端),需要手动转换字节序,示例转换函数:
int16_t swapByteOrder(uint8_t highByte, uint8_t lowByte) { return static_cast<int16_t>((highByte << 8) | lowByte); } // 使用时替换data[i]的赋值: data[i] = swapByteOrder(dataBuffer[2*i], dataBuffer[2*i+1]);
- 内存管理:
fftw_plan和fftw_complex缓冲区创建开销大,必须提前初始化,避免在循环内重复创建。 - 实际读数据逻辑:代码中
actualReadSize为占位,需替换为FT4222_SPISlave_Read返回的真实读取字节数。
内容的提问来源于stack exchange,提问作者JennyC
相关产品推荐
相关产品推荐

