STM32单片机芯片与内部114 DSP-变换运算 实数 复数 FFT IFFT 不限制点数

目录

一、ST 官方汇编 FFT 库(64点, 256 点和 1024 点)

1、cr4_fft_xxx_stm32

2、计算幅频响应

3、计算相频响应

二、复数浮点 FFT、IFFT(支持单精度和双精度)

1、基础支持

2、单精度函数 arm_cfft_f32

3、双精度函数 arm_cfft_f64

三、实数浮点 FFT(支持单精度和双精度)

1、基础支持

2、单精度函数 arm_rfft_fast_f32

3、双精度函数 arm_rfft_fast_f64

四、不限制点数 FFT 实现

1、函数 InitTableFFT

2、函数 cfft


一、ST 官方汇编 FFT 库(64点, 256 点和 1024 点)

        这个汇编的FFT库是来自STM32F10x DSP library,由于是汇编实现的,而且是基4算法,所以实现FFT在速度上比较快。

1、cr4_fft_xxx_stm32

        其实现32位定点数的运算,其中高16位为虚部,低16位为实部。

cr4_fft_1024_stm32函数用于实现1024点数据的FFT计算
cr4_fft_256_stm32函数用于实现256点数据的FFT计算
cr4_fft_64_stm32函数用于实现64点数据的FFT计算

2、计算幅频响应

uint32_t input[1024], output[1024], Mag[1024];/* 输入,输出和幅值 */
float32_t Phase[1024]; /* 相位*/
/*
*********************************************************************************************************
* 函 数 名: PowerMag
* 功能说明: 求模值
* 形 参: _usFFTPoints FFT点数
* 返 回 值: 无
*********************************************************************************************************
*/
void PowerMag(uint16_t _usFFTPoints)
{
    int16_t lX,lY;
    uint16_t i;
    float32_t mag;
    /* 计算幅值 */
    for (i=0; i < _usFFTPoints; i++)
    {
        lX= (output[i]<<16)>>16; /* 实部*/
        lY= (output[i]>> 16); /* 虚部 */
        arm_sqrt_f32((float32_t)(lX*lX+ lY*lY), &mag); /* 求模 */
        Mag[i]= mag*2; /* 求模后乘以2才是实际模值,直流分量不需要乘2 */
    }
    /* 由于上面多乘了2,所以这里直流分量要除以2 */
    Mag[0]= Mag[0]>>1;
}

3、计算相频响应

/*
*********************************************************************************************************
* 函 数 名: Power_Phase_Radians
* 功能说明: 求相位
* 形 参: _usFFTPoints FFT点数, uiCmpValue 阀值
* 返 回 值: 无
*********************************************************************************************************
*/
void Power_Phase_Radians(uint16_t _usFFTPoints, uint32_t _uiCmpValue)
{
    int16_t lX, lY;
    uint16_t i;
    float32_t phase;
    float32_t mag;
    for (i=0; i <_usFFTPoints; i++)
    {
        lX= (output[i]<<16)>>16; /* 实部 */
        lY= (output[i] >> 16); /* 虚部 */
        phase = atan2(lY, lX); /* atan2求解的结果范围是(-pi, pi], 弧度制 */
        arm_sqrt_f32((float32_t)(lX*lX+ lY*lY), &mag); /* 求模 */
        if(_uiCmpValue > mag)
        {
            Phase[i] = 0;
        }
        else
        {
            Phase[i] = phase* 180.0f/3.1415926f; /* 将求解的结果由弧度转换为角度 */
        }
}

二、复数浮点 FFT、IFFT(支持单精度和双精度)

        新版 DSP 库浮点 FFT 推荐使用混合基函数 arm_cfft_f32,而基 2 函数 arm_cfft_radix2_f32 和基 4函数 arm_cfft_radix4_f32 将废弃。 ARM 说明如下:

        DSP 库的早期发行版提供了单独的 radix-2 和 radix-4 对浮点数据进行运算的算法。 这些功能仍然提供,但已弃用。 相比新版函数,老版的功能较慢且通用性较低

1、基础支持

        当前复数 FFT 函数支持三种数据类型,分别是浮点,定点 Q31 和 Q15。这些 FFT 函数有一个共同的特点,就是用于输入信号的缓冲,在转化结束后用来存储输出结果。这样做的好处是节省了 RAM 空间,不需要为输入和输出结果分别设置缓存。由于是复数 FFT,所以输入和输出缓存要存储实部和虚部。存储顺序如下: {real[0], imag[0], real[1], imag[1],………………} ,在使用中切记不要搞错。

2、单精度函数 arm_cfft_f32

        支持16、32、64、128、256、512、1024、2048、4096点单精度复数FFT、IFFT。

3、双精度函数 arm_cfft_f64

        支持16、32、64、128、256、512、1024、2048、4096点双精度复数FFT、IFFT

三、实数浮点 FFT(支持单精度和双精度)

        CMSIS DSP 库里面包含一个专门用于计算实数序列的 FFT 库,很多情况下,用户只需要计算实数序列即可。计算同样点数 FFT 的实数序列要比计算同样点数的虚数序列有速度上的优势。

        快速的 rfft 算法是基于混合基 cfft 算法实现的。

1、基础支持

        一个 N 点的实数序列 FFT 正变换采用下面的步骤实现:

        由上面的框图可以看出,实数序列的 FFT 是先计算 N/2 个实数的 CFFT,然后再重塑数据进行处理从而获得半个 FFT 频谱即可(利用了 FFT 变换后频谱的对称性)。

        一个 N 点的实数序列 FFT 逆变换采用下面的步骤实现:

        实数 FFT 支持浮点, Q31 和 Q15 三种数据类型。

2、单精度函数 arm_rfft_fast_f32

        支持32、64、128、256、512、1024、2048、4096点单精度实数FFT、IFFT。

3、双精度函数 arm_rfft_fast_f64

        支持32、64、128、256、512、1024、2048、4096点双精度实数FFT、IFFT

四、不限制点数 FFT 实现

        可以看到前面的由于 ARM DSP 库限制最大只能 4096 点,有点不够用,所以整理了个更大点数的。不限制点数,满足 2^n 即可, n 最小值 4, 即 16 个点的 FFT,而最大值不限。

        此 FFT 算法没有再使用 ARM DSP 库,重新实现了一个。

1、函数 InitTableFFT

        这个函数用于 FFT 计算过程中需要用到的正弦和余弦表。 对于 8192 点和 16384 点已经专门制作了数值表,存到内部 Flash,其它点数继续使用的 RAM 空间。

/*
*********************************************************************************************************
* 函 数 名: Int_FFT_TAB
* 功能说明: 正弦和余弦表
* 形 参: 点数
* 返 回 值: 无
*********************************************************************************************************
*/
#if (MAX_FFT_N != 8192) && (MAX_FFT_N != 16384)
float32_t costab[MAX_FFT_N/2];
float32_t sintab[MAX_FFT_N/2];
void InitTableFFT(uint32_t n)
{
    uint32_t i;
    /* 正常使用下面获取 cos 和 sin 值 */
    #if 1
    for (i = 0; i < n; i ++ )
    {
        sintab[ i ]= sin( 2 * PI * i / MAX_FFT_N );
        costab[ i ]= cos( 2 * PI * i / MAX_FFT_N );
    }
    /* 打印出来是方便整理 cos 值和 sin 值数组,将其放到内部 Flash,从而节省 RAM */
    #else
    printf("const float32_t sintab[%d] = {\r\n", n);
    for (i = 0; i < n; i ++ )
    {
        sintab[ i ]= sin( 2 * PI * i / MAX_FFT_N );
        printf("%.11ff,\r\n", sintab[ i ]);
    }
    printf("};\r\n");
    printf("const float32_t costab[%d] = {\r\n", n);
    for (i = 0; i < n; i ++ )
    {
        sintab[ i ]= cos( 2 * PI * i / MAX_FFT_N );
        printf("%.11ff,\r\n", sintab[ i ]);
    }
    printf("};\r\n");
    #endif
}
#endif

2、函数 cfft

        这个函数用于复数 FFT 变换,如果需要实数则直接把虚部设置为0即可。

void cfft(struct compx *_ptr, uint32_t FFT_N )
/*
*********************************************************************************************************
* 函 数 名: cfft
* 功能说明: 对输入的复数组进行快速傅里叶变换(FFT)
* 形 参: *_ptr 复数结构体组的首地址指针 struct 型
* FFT_N 表示点数
* 返 回 值: 无
*********************************************************************************************************
*/
void cfft(struct compx *_ptr, uint32_t FFT_N )
{
    float32_t TempReal1, TempImag1, TempReal2, TempImag2;
    uint32_t k,i,j,z;
    uint32_t Butterfly_NoPerColumn; /* 每级蝶形的蝶形组数 */
    uint32_t Butterfly_NoOfGroup; /* 蝶形组的第几组 */
    uint32_t Butterfly_NoPerGroup; /* 蝶形组的第几个蝶形 */
    uint32_t ButterflyIndex1,ButterflyIndex2,P,J;
    uint32_t L;
    uint32_t M;
    z=FFT_N/2; /* 变址运算,即把自然顺序变成倒位序,采用雷德算法 */
    for(i=0,j=0;i<FFT_N-1;i++)
    {
    /*
    如果 i<j,即进行变址 i=j 说明是它本身, i>j 说明前面已经变换过了,不许再变化,注意这里一般是实数有虚数部分 设置成结合体
    */
        if(i<j)
        {
            TempReal1 = _ptr[j].real;
            _ptr[j].real= _ptr[i].real;
            _ptr[i].real= TempReal1;
        }
        k=z; /*求 j 的下一个倒位序 */
        while(k<=j) /* 如果 k<=j,表示 j 的最高位为 1 */
        {
            j=j-k; /* 把最高位变成 0 */
            k=k/2; /* k/2,比较次高位,依次类推,逐个比较,直到某个位为 0,通过下面那句 j=j+k 使其变为 1 */
        }
        j=j+k; /* 求下一个反序号,如果是 0,则把 0 改为 1 */
    }
    /* 第 L 级蝶形(M)第 Butterfly_NoOfGroup 组(Butterfly_NoPerColumn)第 J 个蝶形(Butterfly_NoPerGroup)****** */
/* 蝶形的组数以 2 的倍数递减 Butterfly_NoPerColumn,每组中蝶形的个数以 2 的倍数递增 Butterfly_NoPerGroup */
/* 在计算蝶形时,每 L 列的蝶形组数,一共有 M 列,每组蝶形中蝶形的个数,蝶形的阶数(0,1,2.....M-1) */
    Butterfly_NoPerColumn = FFT_N;
    Butterfly_NoPerGroup = 1;
    M = log2(FFT_N);
    for ( L = 0;L < M; L++ )
    {
        Butterfly_NoPerColumn >>= 1; /* 蝶形组数 假如 N=8,则(4,2,1) */
    //第 L 级蝶形 第 Butterfly_NoOfGroup 组(0,1, ....Butterfly_NoOfGroup-1)
        for ( Butterfly_NoOfGroup = 0;Butterfly_NoOfGroup < Butterfly_NoPerColumn;Butterfly_NoOfGroup++ )
        {
/* 第 Butterfly_NoOfGroup 组中的第 J 个 */
        for ( J = 0;J < Butterfly_NoPerGroup;J ++ )
        { /* 第 ButterflyIndex1 和第 ButterflyIndex2 个元素作蝶形运算,WNC */
/* (0,2,4,6)(0,1,4,5)(0,1,2,3) */
/* 两个要做蝶形运算的数相距 Butterfly_NoPerGroup, ge=1,2,4 */
/* 这里相当于 P=J*2^(M-L),做了一个换算下标都是 N (0,0,0,0)(0,2,0,2)(0,1,2,3) */
            ButterflyIndex1 = ( ( Butterfly_NoOfGroup * Butterfly_NoPerGroup ) << 1 ) + J;
            ButterflyIndex2 = ButterflyIndex1 + Butterfly_NoPerGroup;
            P = J * Butterfly_NoPerColumn;
/* 计算和转换因子乘积 */
            TempReal2 = _ptr[ButterflyIndex2].real * costab[ P ] + _ptr[ButterflyIndex2].imag *
sintab[ P ];
            TempImag2 = _ptr[ButterflyIndex2].imag * costab[ P ] - _ptr[ButterflyIndex2].real *
sintab[ P ] ;
            TempReal1 = _ptr[ButterflyIndex1].real;
            TempImag1 = _ptr[ButterflyIndex1].imag;
/* 蝶形运算 */
            _ptr[ButterflyIndex1].real = TempReal1 + TempReal2;
            _ptr[ButterflyIndex1].imag = TempImag1 + TempImag2;
            _ptr[ButterflyIndex2].real = TempReal1 - TempReal2;
            _ptr[ButterflyIndex2].imag = TempImag1 - TempImag2;
        }
    }
    Butterfly_NoPerGroup<<=1; /* 一组中蝶形的个数(1,2,4) */
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/981817.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

在IDEA中进行git回滚操作:Reset current branch to here‌或Reset HEAD

问题描述 1&#xff09;在本地修改好的代码&#xff0c;commit到本地仓库&#xff0c;突然发觉有问题不想push推到远程仓库了&#xff0c;但它一直在push的列表中存在&#xff0c;那该怎么去掉push列表中的内容呢&#xff1f; 2&#xff09;合并别的分支到当前分支&#xff0…

【五.LangChain技术与应用】【14.LangChain与MoonShot、通义千问:多模型融合的实战】

兄弟们,今天咱们来唠点硬核的——当国产大模型双雄(MoonShot和通义千问)碰上LangChain这个万能胶水,会擦出什么火花?这可不是简单的API调用教程,而是实打实的多模型组合拳打法,保准看完你也能搞出个企业级AI系统!(全程大白话,放心食用) 一、为什么非得搞多模型? 先…

33.C++二叉树进阶1(二叉搜索树两种模型及其应用)

⭐上篇文章&#xff1a;32.C二叉树进阶1&#xff08;二叉搜索树&#xff09;-CSDN博客 ⭐本篇代码&#xff1a;c学习/18.二叉树进阶-二叉搜索树 橘子真甜/c-learning-of-yzc - 码云 - 开源中国 (gitee.com) ⭐标⭐是比较重要的部分 在上篇文章中&#xff0c;实现了一个简单的二…

CSS—属性继承与预处理器:2分钟掌握预处理器

个人博客&#xff1a;haichenyi.com。感谢关注 1. 目录 1–目录2–属性继承3–预处理器 2. 属性继承 像Android里面继承extends&#xff0c;类继承&#xff0c;子类可以使用父类的public和protected的属性和方法。子类可以直接用。   在CSS里面也是类似的。CSS里面是布局里面…

Ansys Zemax | 使用衍射光学器件模拟增强现实 (AR) 系统的出瞳扩展器 (EPE):第 4 部分

附件下载 联系工作人员获取附件 在 OpticStudio 中使用 RCWA 工具为增强现实&#xff08;AR&#xff09;系统设置出瞳扩展器&#xff08;EPE&#xff09;的示例中&#xff0c;首先解释了k空间中光栅的规划&#xff0c;并详细讨论了设置每个光栅的步骤。 介绍 本文是该四篇文…

【数据结构】堆和priority_queue

堆的定义 堆是什么&#xff1f;实际上堆是一种特殊的&#xff08;受限制的&#xff09;完全二叉树&#xff0c;它在完全二叉树的基础上要求每一个节点都要大于等于或者小于等于它的子树的所有节点。这个大于小于体现在节点的值或者权重。 如图所示&#xff1a; 根节点大于等于…

大语言模型学习--本地部署DeepSeek

本地部署一个DeepSeek大语言模型 研究学习一下。 本地快速部署大模型的一个工具 先根据操作系统版本下载Ollama客户端 1.Ollama安装 ollama是一个开源的大型语言模型&#xff08;LLM&#xff09;本地化部署与管理工具&#xff0c;旨在简化在本地计算机上运行和管理大语言模型…

1.Big-endian/ little endian大端对齐、小端对齐

一、大端模式、小端模式的介绍 Little endian&#xff1a;是低位字节排放在内存的低地址端、高位字节排放在内存的高地址端。 Big-endian&#xff1a;是高位字节排放在内存的低地址端、低位字节排放在内存的高地址端。 西门子是大端模式&#xff0c;因为比如 MW100 MB100(高位…

基于Python的PDF特殊字体提取器开发实践

基于Python的PDF特殊字体提取器开发实践 一、应用背景与功能概述 在PDF文档处理场景中&#xff0c;我们常常需要针对特定格式的文本内容进行提取分析。本文介绍的"PDF特殊字体提取器"是一款基于Python开发的桌面应用程序&#xff0c;主要解决以下业务需求&#xff…

【基础4】插入排序

核心思想 插入排序是一种基于元素比较的原地排序算法&#xff0c;其核心思想是将数组分为“已排序”和“未排序”两部分&#xff0c;逐个将未排序元素插入到已排序部分的正确位置。 例如扑克牌在理牌的时候&#xff0c;一般会将大小王、2、A、花牌等按大小顺序插入到左边&…

搭建laravle 数字产品销售平台 php

一个专为单一供应商设计的数字市场平台&#xff0c;旨在为销售数字产品和服务提供一站式解决方案。无论是软件、电子书、音乐、视频还是其他类型的数字内容&#xff0c;都能帮助商家高效地管理和销售他们的数字商品。 主要特点 单一供应商模式&#xff1a;专注于单一品牌或供应…

flink集成tidb cdc

Flink TiDB CDC 详解 1. TiDB CDC 简介 1.1 TiDB CDC 的核心概念 TiDB CDC 是 TiDB 提供的变更数据捕获工具&#xff0c;能够实时捕获 TiDB 集群中的数据变更&#xff08;如 INSERT、UPDATE、DELETE 操作&#xff09;&#xff0c;并将这些变更以事件流的形式输出。TiDB CDC 的…

大模型——打造自己的AI搜索引擎

大模型系列——打造自己的AI搜索引擎 你可能听说过 Perplexity,这是一个引起轰动的 AI 搜索引擎,但它是收费的。本文介绍使用开源 AI工具创建本地 Perplexity 的替代方案。 你可能听说过 Perplexity,这是一个引起轰动的 AI 搜索引擎。与传统搜索相比,它提供简洁、综合的查…

五、并发爬虫

本节聚焦于使用协程、线程、进程实现并发爬虫任务。 Python 线程受全局解释器锁&#xff08;GIL&#xff09;制约&#xff0c;同一时刻仅能执行一个线程&#xff0c;无法充分利用多核 CPU 优势&#xff0c;且频繁切换线程会增加开销&#xff0c;影响爬虫性能。 协程是轻量级线程…

Avalonia 中文乱码

代码字体文件设置成支持中文的&#xff0c;但是编译的代码还是显示的乱码&#xff0c;原因是代码文件的文件编码格式不支持中文导致的。 如下面的2个页面一部分中文显示正常&#xff0c;一部分显示正常&#xff0c;一部分显示乱码。

Verilog学习方法—基础入门篇(一)

前言&#xff1a; 在FPGA开发中&#xff0c;Verilog HDL&#xff08;硬件描述语言&#xff09;是工程师必须掌握的一项基础技能。它不仅用于描述数字电路&#xff0c;还广泛应用于FPGA的逻辑设计与验证。对于初学者来说&#xff0c;掌握Verilog的核心概念和基本语法&#xff0…

PCB电路板基础知识与应用详解:结构与工作原理

电路板&#xff0c;简称PCB&#xff08;Printed Circuit Board&#xff09;&#xff0c;是电子设备的核心部分&#xff0c;几乎所有现代电子产品都离不开电路板的支撑。本文将带您全面了解电路板的基本结构、工作原理及其在电子工程中的重要作用。 什么是电路板&#xff1f; 电…

使用Qt调用HslCommunication(C++调用C#库)

使用C/CLI 来调用C#的dll 任务分解&#xff1a; 1、实现C#封装一个调用hsl的dll&#xff1b; 2、实现C控制台调用C#的dll库&#xff1b; 3、把调用C#的dll用C再封装为一个dll&#xff1b; 4、最后再用Qt调用c的dll&#xff1b; 填坑&#xff1a; 1、开发时VS需要安装CLI项目库…

标签的ref属性 vue中为什么不用id标记标签

标签的ref属性 vue中为什么不用id标记标签 假设有一对父子组件&#xff0c;如果父组件和子组件中存在id相同的标签&#xff0c;会产生冲突。通过id获取标签会获取到先加载那个标签。 标签的ref属性的用法 在父组件App中&#xff0c;引入了子组件Person。 并使用ref标记了Pe…

嵌入式硬件发展历程

微型计算机架构&#xff1a;CPURAM存储设备 以前常把CPU称为MPU,但现在随着发展&#xff0c;分为两条道路&#xff1a; 一、发展历程 1、集成 然后把CPURAMFlash其他模块集成在一起&#xff0c;就称为MCU也称单片机&#xff0c;他们Flash和RAM比较小&#xff0c;运行裸机程…