forked from xuos/xiuos
APP_Framework/Applications/:add k210 fft(fast Fourier transform) example.
This commit is contained in:
parent
4c0b05b752
commit
e69139c6b9
|
@ -9,5 +9,6 @@ menu "knowing app"
|
||||||
source "$APP_DIR/Applications/knowing_app/instrusion_detect/Kconfig"
|
source "$APP_DIR/Applications/knowing_app/instrusion_detect/Kconfig"
|
||||||
source "$APP_DIR/Applications/knowing_app/helmet_detect/Kconfig"
|
source "$APP_DIR/Applications/knowing_app/helmet_detect/Kconfig"
|
||||||
source "$APP_DIR/Applications/knowing_app/iris_ml_demo/Kconfig"
|
source "$APP_DIR/Applications/knowing_app/iris_ml_demo/Kconfig"
|
||||||
|
source "$APP_DIR/Applications/knowing_app/k210_fft_test/Kconfig"
|
||||||
endif
|
endif
|
||||||
endmenu
|
endmenu
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
config K210_FFT_TEST
|
||||||
|
bool "enable apps/k210 fft test"
|
||||||
|
default n
|
|
@ -0,0 +1,9 @@
|
||||||
|
from building import *
|
||||||
|
|
||||||
|
cwd = GetCurrentDir()
|
||||||
|
src = Glob('*.c') + Glob('*.cpp')
|
||||||
|
CPPPATH = [cwd]
|
||||||
|
|
||||||
|
group = DefineGroup('Applications', src, depend = ['K210_FFT_TEST'], LOCAL_CPPPATH = CPPPATH)
|
||||||
|
|
||||||
|
Return('group')
|
|
@ -0,0 +1,101 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include "fft_soft.h"
|
||||||
|
|
||||||
|
#define PI 3.14159265358979323846
|
||||||
|
complex add(complex a, complex b)
|
||||||
|
{
|
||||||
|
complex ret = {a.real + b.real, a.imag + b.imag};
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
complex sub(complex a, complex b)
|
||||||
|
{
|
||||||
|
complex ret = {a.real - b.real, a.imag - b.imag};
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
complex mul(complex a, complex b)
|
||||||
|
{
|
||||||
|
complex ret = {a.real * b.real - a.imag * b.imag, a.real * b.imag + a.imag * b.real};
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bitrev(complex *data, int n)
|
||||||
|
{
|
||||||
|
int j = 0;
|
||||||
|
int m = 0;
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
if (j > i)
|
||||||
|
SWAP(data[i], data[j]);
|
||||||
|
m = n / 2;
|
||||||
|
while (j >= m && m != 0)
|
||||||
|
{
|
||||||
|
j -= m;
|
||||||
|
m >>= 1;
|
||||||
|
}
|
||||||
|
j += m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fft_soft(complex *data, int n)
|
||||||
|
{
|
||||||
|
int M = 0;
|
||||||
|
for (int i = n; i > 1; i = i >> 1, M++);
|
||||||
|
|
||||||
|
bitrev(data, n);
|
||||||
|
|
||||||
|
for (int m = 0; m < M; m++)
|
||||||
|
{
|
||||||
|
int K = n >> (m + 1);
|
||||||
|
for (int k = 0; k < K; k++)
|
||||||
|
{
|
||||||
|
int J = 2 << m;
|
||||||
|
int base = k * J;
|
||||||
|
for (int j = 0; j < J / 2; j++)
|
||||||
|
{
|
||||||
|
int t = base + j;
|
||||||
|
complex w = {cos(-2 * PI * j * K / n), sin(-2 * PI * j * K / n)};
|
||||||
|
complex wn = mul(data[t + J / 2], w);
|
||||||
|
complex temp = data[t];
|
||||||
|
data[t] = add(data[t], wn);
|
||||||
|
data[t + J / 2] = sub(temp, wn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ifft_soft(complex *data, int n)
|
||||||
|
{
|
||||||
|
int M = 0;
|
||||||
|
for (int i = n; i > 1; i = i >> 1, M++);
|
||||||
|
|
||||||
|
bitrev(data, n);
|
||||||
|
|
||||||
|
for (int m = 0; m < M; m++)
|
||||||
|
{
|
||||||
|
int K = n >> (m + 1);
|
||||||
|
for (int k = 0; k < K; k++)
|
||||||
|
{
|
||||||
|
int J = 2 << m;
|
||||||
|
int base = k * J;
|
||||||
|
for (int j = 0; j < J / 2; j++)
|
||||||
|
{
|
||||||
|
int t = base + j;
|
||||||
|
complex w = {cos(2 * PI * j * K / n), sin(2 * PI * j * K / n)};
|
||||||
|
complex wn = mul(data[t + J / 2], w);
|
||||||
|
complex temp = data[t];
|
||||||
|
data[t] = add(data[t], wn);
|
||||||
|
data[t + J / 2] = sub(temp, wn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
data[i].real /= n;
|
||||||
|
data[i].imag /= n;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
#ifndef _FFT_SOFT_H
|
||||||
|
#define _FFT_SOFT_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define SWAP(a, b) do {complex t = (a); (a) = (b); (b) = t;} while(0)
|
||||||
|
|
||||||
|
typedef struct{double real, imag;} complex;
|
||||||
|
|
||||||
|
void fft_soft(complex *data, int n);
|
||||||
|
void ifft_soft(complex *data, int n);
|
||||||
|
void show(complex *data, int n);
|
||||||
|
|
||||||
|
#endif /* _FFT_SOFT_H */
|
|
@ -0,0 +1,159 @@
|
||||||
|
/* Copyright 2018 Canaan Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
#include <transform.h>
|
||||||
|
#include <math.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void k210_fft_test(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;
|
||||||
|
}
|
||||||
|
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_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];
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
#ifdef __RT_THREAD_H__
|
||||||
|
MSH_CMD_EXPORT(k210_fft_test,k210 fft test );
|
||||||
|
#endif
|
Loading…
Reference in New Issue