Files
esp32-hacking/esp-crab/master_recv/main/app/app_ifft.c

162 lines
4.8 KiB
C

/* SPI Slave example, receiver (uses SPI Slave driver to communicate with sender)
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <math.h>
#include "freertos/FreeRTOS.h"
#include "esp_log.h"
#include "app_ifft.h"
#include "IQmathLib.h"
#define PI 3.14159265358979323846f
#define PI_IQ _IQ(3.14159265358979323846)
#define PI_IQ_N2 _IQ(-6.28318530717958647692)
const int bitReverseTable[64] = {
0, 32, 16, 48, 8, 40, 24, 56,
4, 36, 20, 52, 12, 44, 28, 60,
2, 34, 18, 50, 10, 42, 26, 58,
6, 38, 22, 54, 14, 46, 30, 62,
1, 33, 17, 49, 9, 41, 25, 57,
5, 37, 21, 53, 13, 45, 29, 61,
3, 35, 19, 51, 11, 43, 27, 59,
7, 39, 23, 55, 15, 47, 31, 63
};
void IRAM_ATTR fft_iq(Complex_Iq *X, int inverse)
{
int log2N = 6;
int N = 64;
Complex_Iq *temp = (Complex_Iq *)malloc(64 * sizeof(Complex_Iq));
// Bit-reversed addressing permutation
for (int i = 0; i < N; i++) {
temp[i] = X[bitReverseTable[i]];
}
for (int i = 0; i < N; i++) {
X[i] = temp[i];
}
// Cooley-Tukey iterative FFT
for (int s = 1; s <= log2N; ++s) {
int m = 1 << s; // 2 power s
int m2 = m >> 1; // m/2
Complex_Iq w;
w.real = _IQ16(1.0);
w.imag = _IQ16(0.0);
Complex_Iq wm;
_iq16 angle = _IQ16div(PI_IQ_N2, m);
wm.real = _IQ16cos(angle);
wm.imag = _IQ16sin(angle);
if (inverse) wm.imag = -wm.imag;
for (int j = 0; j < m2; ++j) {
for (int k = j; k < N; k += m) {
Complex_Iq t, u;
u = X[k];
t.real = _IQ16mpy(w.real , X[k + m2].real) - _IQ16mpy(w.imag , X[k + m2].imag);
t.imag = _IQ16mpy(w.real , X[k + m2].imag) + _IQ16mpy(w.imag , X[k + m2].real);
X[k].real = u.real + t.real;
X[k].imag = u.imag + t.imag;
X[k + m2].real = u.real - t.real;
X[k + m2].imag = u.imag - t.imag;
}
float tmpReal = _IQ16mpy(w.real , wm.real) - _IQ16mpy(w.imag , wm.imag);
w.imag = _IQ16mpy(w.real , wm.imag) + _IQ16mpy(w.imag , wm.real);
w.real = tmpReal;
}
}
// Scale for inverse FFT
if (inverse) {
for (int i = 0; i < N; i++) {
X[i].real = _IQdiv64(X[i].real);
X[i].imag = _IQdiv64(X[i].imag);
}
}
free(temp);
}
// Bit reversal of given index 'x' with 'log2n' bits
unsigned int inline bitReverse(unsigned int x, int log2n) {
int n = 0;
for (int i = 0; i < log2n; i++) {
n <<= 1;
n |= (x & 1);
x >>= 1;
}
return n;
}
void IRAM_ATTR fft(Complex *X, int N, int inverse)
{
int log2N = log2(N);
Complex *temp = (Complex *)malloc(N * sizeof(Complex));
// Bit-reversed addressing permutation
for (int i = 0; i < N; i++) {
temp[i] = X[bitReverse(i, log2N)];
}
for (int i = 0; i < N; i++) {
X[i] = temp[i];
}
// Cooley-Tukey iterative FFT
for (int s = 1; s <= log2N; ++s) {
int m = 1 << s; // 2 power s
int m2 = m >> 1; // m/2
Complex w;
w.real = 1.0;
w.imag = 0.0;
Complex wm;
wm.real = cosf(-2.0f * PI / m);
wm.imag = sinf(-2.0f * PI / m);
if (inverse) wm.imag = -wm.imag;
for (int j = 0; j < m2; ++j) {
for (int k = j; k < N; k += m) {
Complex t, u;
u = X[k];
t.real = w.real * X[k + m2].real - w.imag * X[k + m2].imag;
t.imag = w.real * X[k + m2].imag + w.imag * X[k + m2].real;
X[k].real = u.real + t.real;
X[k].imag = u.imag + t.imag;
X[k + m2].real = u.real - t.real;
X[k + m2].imag = u.imag - t.imag;
}
float tmpReal = w.real * wm.real - w.imag * wm.imag;
w.imag = w.real * wm.imag + w.imag * wm.real;
w.real = tmpReal;
}
}
// Scale for inverse FFT
if (inverse) {
for (int i = 0; i < N; i++) {
X[i].real /= N;
X[i].imag /= N;
}
}
free(temp);
}
float complex_magnitude_iq(Complex_Iq z) {
return _IQ16toF(_IQ16mag(z.real, z.imag));
}
float complex_phase_iq(Complex_Iq z) {
return _IQ16toF(_IQ16atan2(z.imag, z.real));
}
float complex_magnitude(Complex z) {
return sqrt(z.real * z.real + z.imag * z.imag);
}
float complex_phase(Complex z) {
return atan2(z.imag, z.real);
}