feat: Initial esp32-hacking project with firmware sources and docs
This commit is contained in:
162
esp-crab/slave_recv/main/app/app_ifft.c
Normal file
162
esp-crab/slave_recv/main/app/app_ifft.c
Normal file
@@ -0,0 +1,162 @@
|
||||
/* 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);
|
||||
}
|
||||
Reference in New Issue
Block a user