AI嵌入式K210项目(17)-快速傅里叶变换加速器 (FFT)

文章目录

  • 前言
  • 一、什么是傅里叶变换?
  • 二、K210的快速傅里叶变换加速器
  • 实验过程
  • 总结


前言

K210内置了丰富的加速器,包括神经网络处理器 (KPU),AES(高级加密加速器),APU 麦克风阵列语音数据加速计算处理器,现场可编程 IO 阵列 (FPIOA),数字摄像头接口 (DVP),相对于软件可以极大的提高 AES 运算速度,快速傅里叶变换加速器 (FFT),安全散列算法加速器 (SHA256)。
本文介绍内置的快速傅里叶变换加速器 (FFT);

一、什么是傅里叶变换?

傅里叶变换(Fourier Transform)可以将一个在时间(或空间)域内的信号转换成频率域内的信号。其物理意义是将一个信号分解为不同频率的正弦波组成的谱,从而揭示了信号的频率特性。它的物理意义在于将信号从时间域转换到频率域,帮助我们理解信号的频率特性。
物理意义
傅里叶变换可以将一个信号分解为不同频率的正弦波组成的谱,从而揭示信号的频率特性。通过傅里叶变换,我们能够更好地理解声音、图像等信号的组成和特性。例如,在声音处理中,傅里叶变换可以将声音信号转换为频域信号,进而分析不同音调所对应的频率成分。这对于音频质量改善、音乐合成和语音识别等方面有着重要作用。
在这里插入图片描述
在物理学、工程和科学领域,许多信号都可以表示为不同频率的正弦波的叠加。傅里叶变换能够帮助我们理解这些信号的频率特性,并提供有效的信号处理和分析方法。例如,在图像处理中,傅里叶变换可用于图像压缩、边缘检测等处理,为数字图像处理提供重要支持。
在这里插入图片描述
傅里叶变换非常重要,在音视频处理,通讯等领域有着重要的应用,大家可以通过其他方式好好学习一下,

快速傅里叶变换(FFT)即利用计算机计算离散傅里叶变换(DFT)的高效、快速计算方法的统称,快速傅里叶变换在运算速度和适用范围方面具有优势,而傅里叶变换在精度和计算方式方面更优。

二、K210的快速傅里叶变换加速器

K210内置快速傅立叶变换加速器FFT Accelerater。该模块可以支持64 点、128 点、256 点以及512 点的FFT 以及IFFT。在FFT 内部有两块大小为512*32bit 的SRAM,在配置完成后FFT 会向DMA 发送TX 请求,将DMA 送来的送据放到其中的一块SRAM 中去,直到满足当前FFT 运算所需要的数据量并开始FFT 运算,蝶形运算单元从包含有有效数据的SRAM 中读出数据,运算结束后将数据写到另外一块SRAM 中去,下次蝶形运算再从刚写入的SRAM 中读出数据,运算结束后并写入另外一块SRAM,如此反复交替进行直到完成整个FFT 运算。

FFT 加速器是用硬件的方式来实现FFT 的基2 时分运算。

• 支持多种运算长度,即支持64 点、128 点、256 点以及512 点运算

• 支持两种运算模式,即FFT 以及IFFT 运算

• 支持可配的输入数据位宽,即支持32 位及64 位输入

• 支持可配的输入数据排列方式,即支持虚部、实部交替,纯实部以及实部、虚部分离三种数据排

列方式

• 支持DMA 传输

对应的头文件 aes.h

为用户提供以下接口:

• fft_complex_uint16_dma:FFT运算。

实验过程

本实验使用K210自带的FFT加速器和开源软FFT做对比,看一下加速效果。使用的fft开源库,大家可以网上下载,或者到我gitee上下载,这里只贴man.c部分内容了;

#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include "encoding.h"
#include "dmac.h"
#include "fft.h"
#include "encoding.h"
#include "sysctl.h"
#include "fft_soft.h"

#define FFT_N               512U
#define FFT_FORWARD_SHIFT   0x0U
#define FFT_BACKWARD_SHIFT  0x1ffU
#define PI                  3.14159265358979323846

typedef enum _complex_mode
{
    FFT_HARD = 0,
    FFT_SOFT = 1,
    FFT_COMPLEX_MAX,
} complex_mode_t;

int16_t real[FFT_N];
int16_t imag[FFT_N];
float hard_power[FFT_N];
float soft_power[FFT_N];
float hard_angel[FFT_N];
float soft_angel[FFT_N];
uint64_t fft_out_data[FFT_N / 2];
uint64_t buffer_input[FFT_N];
uint64_t buffer_output[FFT_N];
uint64_t cycle[FFT_COMPLEX_MAX][FFT_DIR_MAX];

uint16_t get_bit1_num(uint32_t data)
{
    uint16_t num;
    for (num = 0; data; num++)
        data &= data - 1;
    return num;
}

int main(void)
{
    int32_t i;
    float tempf1[3];
    fft_data_t *output_data;
    fft_data_t *input_data;
    uint16_t bit1_num = get_bit1_num(FFT_FORWARD_SHIFT);
    complex_hard_t data_hard[FFT_N] = {0};
    complex data_soft[FFT_N] = {0};
    /* 取得一组复数 */
    for (i = 0; i < FFT_N; i++)
    {
        tempf1[0] = 0.3 * cosf(2 * PI * i / FFT_N + PI / 3) * 256;
        tempf1[1] = 0.1 * cosf(16 * 2 * PI * i / FFT_N - PI / 9) * 256;
        tempf1[2] = 0.5 * cosf((19 * 2 * PI * i / FFT_N) + PI / 6) * 256;
        data_hard[i].real = (int16_t)(tempf1[0] + tempf1[1] + tempf1[2] + 10);
        data_hard[i].imag = (int16_t)0;
        data_soft[i].real = data_hard[i].real;
        data_soft[i].imag = data_hard[i].imag;
    }

    /* 复数转化成傅里叶数据结构RIRI */
    for (int i = 0; i < FFT_N / 2; ++i)
    {
        input_data = (fft_data_t *)&buffer_input[i];
        input_data->R1 = data_hard[2 * i].real;
        input_data->I1 = data_hard[2 * i].imag;
        input_data->R2 = data_hard[2 * i + 1].real;
        input_data->I2 = data_hard[2 * i + 1].imag;
    }
    
    /* 硬件处理FFT数据,并记录时间 */
    cycle[FFT_HARD][FFT_DIR_FORWARD] = read_cycle();
    fft_complex_uint16_dma(DMAC_CHANNEL0, DMAC_CHANNEL1, FFT_FORWARD_SHIFT, FFT_DIR_FORWARD, buffer_input, FFT_N, buffer_output);
    cycle[FFT_HARD][FFT_DIR_FORWARD] = read_cycle() - cycle[FFT_HARD][FFT_DIR_FORWARD];

    /* 软件处理FFT数据,并记录时间 */
    cycle[FFT_SOFT][FFT_DIR_FORWARD] = read_cycle();
    fft_soft(data_soft, FFT_N);
    cycle[FFT_SOFT][FFT_DIR_FORWARD] = read_cycle() - cycle[FFT_SOFT][FFT_DIR_FORWARD];
    
    /* 解析计算输出的数据 */
    for (i = 0; i < FFT_N / 2; i++)
    {
        output_data = (fft_data_t*)&buffer_output[i];
        data_hard[2 * i].imag = output_data->I1 ;
        data_hard[2 * i].real = output_data->R1 ;
        data_hard[2 * i + 1].imag = output_data->I2 ;
        data_hard[2 * i + 1].real = output_data->R2 ;
    }

    /* 复数取模 */
    for (i = 0; i < FFT_N; i++)
    {
        hard_power[i] = sqrt(data_hard[i].real * data_hard[i].real + data_hard[i].imag * data_hard[i].imag) * 2;
        soft_power[i] = sqrt(data_soft[i].real * data_soft[i].real + data_soft[i].imag * data_soft[i].imag) * 2;
    }

    /* 打印软件和硬件复数的实部和虚部 */
    printf("\n[hard fft real][soft fft real][hard fft imag][soft fft imag]\n");
    for (i = 0; i < FFT_N / 2; i++)
        printf("%3d:%7d %7d %7d %7d\n",
                i, data_hard[i].real, (int32_t)data_soft[i].real, data_hard[i].imag, (int32_t)data_soft[i].imag);

    printf("\nhard power  soft power:\n");
    printf("%3d : %f  %f\n", 0, hard_power[0] / 2 / FFT_N * (1 << bit1_num), soft_power[0] / 2 / FFT_N);
    for (i = 1; i < FFT_N / 2; i++)
        printf("%3d : %f  %f\n", i, hard_power[i] / FFT_N * (1 << bit1_num), soft_power[i] / FFT_N);

    /* 打印相位 */
    printf("\nhard phase  soft phase:\n");
    for (i = 0; i < FFT_N / 2; i++)
    {
        hard_angel[i] = atan2(data_hard[i].imag, data_hard[i].real);
        soft_angel[i] = atan2(data_soft[i].imag, data_soft[i].real);
        printf("%3d : %f  %f\n", i, hard_angel[i] * 180 / PI, soft_angel[i] * 180 / PI);
    }

    /* 快速傅里叶变换逆运算 */
    for (int i = 0; i < FFT_N / 2; ++i)
    {
        input_data = (fft_data_t *)&buffer_input[i];
        input_data->R1 = data_hard[2 * i].real;
        input_data->I1 = data_hard[2 * i].imag;
        input_data->R2 = data_hard[2 * i + 1].real;
        input_data->I2 = data_hard[2 * i + 1].imag;
    }

    /* 硬件和软件快速傅里叶变换运算 */
    cycle[FFT_HARD][FFT_DIR_BACKWARD] = read_cycle();
    fft_complex_uint16_dma(DMAC_CHANNEL0, DMAC_CHANNEL1, FFT_BACKWARD_SHIFT, FFT_DIR_BACKWARD, buffer_input, FFT_N, buffer_output);
    cycle[FFT_HARD][FFT_DIR_BACKWARD] = read_cycle() - cycle[FFT_HARD][FFT_DIR_BACKWARD];
    cycle[FFT_SOFT][FFT_DIR_BACKWARD] = read_cycle();
    ifft_soft(data_soft, FFT_N);
    cycle[FFT_SOFT][FFT_DIR_BACKWARD] = read_cycle() - cycle[FFT_SOFT][FFT_DIR_BACKWARD];
    
    for (i = 0; i < FFT_N / 2; i++)
    {
        output_data = (fft_data_t*)&buffer_output[i];
        data_hard[2 * i].imag = output_data->I1 ;
        data_hard[2 * i].real = output_data->R1 ;
        data_hard[2 * i + 1].imag = output_data->I2 ;
        data_hard[2 * i + 1].real = output_data->R2 ;
    }

    printf("\n[hard ifft real][soft ifft real][hard ifft imag][soft ifft imag]\n");
    for (i = 0; i < FFT_N / 2; i++)
        printf("%3d:%7d  %7d %7d %7d\n",
                i, data_hard[i].real, (int32_t)data_soft[i].real, data_hard[i].imag, (int32_t)data_soft[i].imag);

    printf("[hard fft test] [%d bytes] forward time = %ld us, backward time = %ld us\n",
            FFT_N,
            cycle[FFT_HARD][FFT_DIR_FORWARD]/(sysctl_clock_get_freq(SYSCTL_CLOCK_CPU)/1000000),
            cycle[FFT_HARD][FFT_DIR_BACKWARD]/(sysctl_clock_get_freq(SYSCTL_CLOCK_CPU)/1000000));

    printf("[soft fft test] [%d bytes] forward time = %ld us, backward time = %ld us\n",
            FFT_N,
            cycle[FFT_SOFT][FFT_DIR_FORWARD]/(sysctl_clock_get_freq(SYSCTL_CLOCK_CPU)/1000000),
            cycle[FFT_SOFT][FFT_DIR_BACKWARD]/(sysctl_clock_get_freq(SYSCTL_CLOCK_CPU)/1000000));
    while (1)
        ;
    return 0;
}

代码完成后,进行编译

cd build

cmake .. -DPROJ=fft -G "MinGW Makefiles"

make

编译完成后,在build文件夹下会生成fft.bin文件。

使用type-C数据线连接电脑与K210开发板,打开kflash,选择对应的设备,再将程序固件烧录到K210开发板上。
在这里插入图片描述
烧录后重启开发板,实验结果如下:
该处使用的url网络请求的数据。


总结

从实验结果来看内置的快速傅里叶变换加速器 (FFT)速度是软FFT的300多倍,加速效果非常明显。

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

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

相关文章

Netty-Netty源码分析流程图

netty服务端流程图 补充 完善客户端

AttributeError: module ‘numpy‘ has no attribute ‘float‘解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

《WebKit 技术内幕》之六(2): CSS解释器和样式布局

2 CSS解释器和规则匹配 在了解了CSS的基本概念之后&#xff0c;下面来理解WebKit如何来解释CSS代码并选择相应的规则。通过介绍WebKit的主要设施帮助理解WebKit的内部工作原理和机制。 2.1 样式的WebKit表示类 在DOM树中&#xff0c;CSS样式可以包含在“style”元素中或者使…

java数据类型

基本数据类型&#xff1a;(8种) 整型&#xff1a;byte、short、int、long 浮点型&#xff1a;float、double 字符型&#xff1a;char 布尔类型&#xff1a;boolean 1、整数类型&#xff08;整型&#xff09; 2、浮点类型 细节&#xff1a;如果是直接查询得到的小数或者直接赋值…

C++入门学习(十)如何显示浮点数的完整形态

在C中&#xff0c;如果你想要显示浮点数的完整数字&#xff08;包括小数部分和指数部分&#xff09;&#xff0c;可以使用 std::setprecision 和 std::fixed 来设置精度和固定小数点表示&#xff1a; #include <iostream> #include <iomanip> // 必须包含这个头…

Python实现离散选择Logit模型(Logit算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 Logit模型&#xff08;Logit model&#xff0c;也译作“评定模型”&#xff0c;“分类评定模型”&…

小程序使用echarts图表-雷达图

本文介绍下小程序中如何使用echarts 如果是通过npm安装&#xff0c;这样是全部安装的&#xff0c;体积有点大 我这边是使用echarts中的一个组件来实现的&#xff0c;下边是具体流程&#xff0c;实际效果是没有外边的红色边框的&#xff0c;加红色边框的效果是这篇说明 1.echa…

测试覆盖与矩阵

4. Coverage - 衡量测试的覆盖率 我们已经掌握了如何进行单元测试。接下来&#xff0c;一个很自然的问题浮现出来&#xff0c;我们如何知道单元测试的质量呢&#xff1f;这就提出了测试覆盖率的概念。覆盖率测量通常用于衡量测试的有效性。它可以显示您的代码的哪些部分已被测…

【SpringBoot技术专题】「开发实战系列」Undertow web容器的入门实战及调优方案精讲

Undertow web容器的入门实战及调优方案精讲 Undertow web容器Undertow 介绍官网API给出一句话概述Undertow&#xff1a;官网API总结特点&#xff1a;Lightweight&#xff08;轻量级&#xff09;HTTP Upgrade Support&#xff08;支持http升级&#xff09;、HTTP/2 Support支持H…

【Linux 内核源码分析】堆内存管理

堆 堆是一种动态分配内存的数据结构&#xff0c;用于存储和管理动态分配的对象。它是一块连续的内存空间&#xff0c;用于存储程序运行时动态申请的内存。 堆可以被看作是一个由各个内存块组成的堆栈&#xff0c;其中每个内存块都有一个地址指针&#xff0c;指向下一个内存块…

学生公寓智能控电系统的重要性

学生公寓智能控电系统石家庄光大远通电气有限公司学生宿舍内漏电&#xff0c;超负荷用电&#xff0c;违规用电等现象一直是困扰后勤管理的普遍问题。随着学生日常生活方式以及生活用品的改变&#xff0c;电脑以及各种电器逐渐的普及&#xff0c;导致用电量与日俱增&#xff0c;…

竞赛保研 机器视觉人体跌倒检测系统 - opencv python

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 机器视觉人体跌倒检测系统 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&…

翻译: Anaconda 与 miniconda的区别

Anaconda 和 miniconda 是广泛用于数据科学的软件发行版&#xff0c;用于简化包管理和部署。 1. 主要有两个区别&#xff1a; packages包数量&#xff1a; Anaconda 附带了 150 多个数据科学包&#xff0c;而 miniconda 只有少数几个。Interface接口&#xff1a;Anaconda 有…

mfc110.dll丢失是什么意思?全面解析mfc110.dll丢失的解决方法

在使用计算机的过程中&#xff0c;用户可能会遭遇一个常见的困扰&#xff0c;即系统提示无法找到mfc110.dll文件。这个动态链接库文件&#xff08;DLL&#xff09;是Microsoft Foundation Classes&#xff08;MFC&#xff09;库的重要组成部分&#xff0c;对于许多基于Windows的…

node.js项目express的初始化

目录 1.初始化项目2.配置跨域3.开始编写API3.1准备3.2路由处理函数router_make下的user.js3.3路由模块router下的user.js3.4入口文件app.js里面去新增这段代码3.5启动项目进行测试 &#x1f44d; 点赞&#xff0c;你的认可是我创作的动力&#xff01; ⭐️ 收藏&#xff0c;你…

设备管理——WinCC 给你神助功

要实现“设备高效”&#xff0c;就必须“管之有道”&#xff0c;来自设备层的数据支撑将是必不可少的&#xff0c;提高设备效能的2个关键在于降低平时停机时间 (MDT) 和提高平均无故障时间 (MTBF)。通常来说&#xff0c;设备维护可大致可分为三个层次&#xff1a;纠正性维护&am…

[Tool] python项目中集成使用Firebase推送功能

背景介绍 目前&#xff0c;App推送功能已经非常普遍&#xff0c;几乎所有App都有推送功能。推送功能可以自己实现&#xff0c;也可以使用第三方提供的推送服务&#xff08;免费的收费的都有&#xff09;。本文主要介绍使用Firebase提供的推送服务Firebase Cloud Messaging&…

matlab appdesigner系列-常用13-标签

标签&#xff0c;用来显示各类文本 此示例&#xff0c;就是在标签之外的画布上单击鼠标左键&#xff0c;显示王勃的《滕王阁诗》 操作如下&#xff1a; 1&#xff09;将2个标签拖拽到画布上&#xff0c;并修改相应文字。将第二个标签的右侧文本信息中的Wordwrap打开&#xf…

[自动化分布式] Zabbix自动发现与自动注册

abbix 自动发现&#xff08;对于 agent2 是被动模式&#xff09; zabbix server 主动的去发现所有的客户端&#xff0c;然后将客户端的信息登记在服务端上。 缺点是如果定义的网段中的主机数量多&#xff0c;zabbix server 登记耗时较久&#xff0c;且压力会较大 部署 添加zabb…

六、标准对话框、多应用窗体

一、标准对话框 Qt提供了一些常用的标准对话框&#xff0c;如打开文件对话框、选择颜色对话框、信息提示和确认选择对话框、标准输入对话框等。1、预定义标准对话框 &#xff08;1&#xff09;QFileDialog 文件对话框 QString getOpenFileName() 打开一个文件QstringList ge…
最新文章