-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfft.cpp
123 lines (89 loc) · 3.21 KB
/
fft.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include "fft.h"
FFT::FFT(int segmentSize, QObject *parent) : QObject(parent) {
if (segmentSize <= 0) {
emit error("FFT::FFT: Neplatná velikost vstupních segmentů.");
return;
}
// tento výpočet vyplívá z definice algoritmu FFT
for (m_maxSegmentSize = 1; m_maxSegmentSize < segmentSize; m_maxSegmentSize *= 2);
m_espdSize = (m_maxSegmentSize / 2) + 1;
m_fftCfg = kiss_fftr_alloc(m_maxSegmentSize, 0, nullptr, nullptr);
m_ifftCft = kiss_fftr_alloc(m_maxSegmentSize, 1, nullptr, nullptr);
if (!m_fftCfg || !m_ifftCft) {
emit error("FFT::FFT: Nepodařilo se alokovat potřebné zdroje (kissFFT).");
return;
}
}
FFT::~FFT() {
free(m_fftCfg);
free(m_ifftCft);
}
int FFT::espdSize() const {
return m_espdSize;
}
QVector<float> FFT::transformEucl(QVector<float> segment) {
if (segment.isEmpty())
return QVector<float>();
if (segment.size() > m_maxSegmentSize) {
emit error("FFT::transformEucl: Vstupní segment je větší je přednastavená velikost.");
return QVector<float>();
}
if (segment.size() < m_maxSegmentSize)
segment = prepareSegment(segment);
QVector<kiss_fft_cpx> cpx = realFFt(segment);
if (cpx.isEmpty()) return QVector<float>();
return euclidNorm(cpx);
}
QVector<kiss_fft_cpx> FFT::realFFt(QVector<float> segment) {
if (segment.size() != m_maxSegmentSize)
return QVector<kiss_fft_cpx>();
QVector<kiss_fft_cpx> cpx(m_espdSize);
kiss_fftr(m_fftCfg, segment.constData(), cpx.data());
return cpx;
}
QVector<float> FFT::invRealFFT(QVector<kiss_fft_cpx> cpx) {
if (cpx.size() != m_espdSize)
return QVector<float>();
QVector<float> segment(m_maxSegmentSize);
kiss_fftri(m_ifftCft, cpx.constData(), segment.data());
QMutableVectorIterator<float> i(segment);
while (i.hasNext()) {
float i_val = i.next();
i.setValue(i_val / static_cast<float>(m_espdSize));
}
return segment;
}
void FFT::realFFt(QVector<float> &segment, QVector<kiss_fft_cpx> &cpx) {
if (segment.size() != m_maxSegmentSize || cpx.size() != m_espdSize)
return;
kiss_fftr(m_fftCfg, segment.constData(), cpx.data());
}
void FFT::invRealFFT(QVector<kiss_fft_cpx> &cpx, QVector<float> &segment) {
if (cpx.size() != m_espdSize || segment.size() != m_maxSegmentSize)
return;
kiss_fftri(m_ifftCft, cpx.constData(), segment.data());
QMutableVectorIterator<float> i(segment);
while (i.hasNext()) {
float i_val = i.next();
i.setValue(i_val / static_cast<float>(m_espdSize));
}
}
QVector<float> FFT::prepareSegment(QVector<float> segment) {
if (segment.isEmpty())
return QVector<float>();
QVector<float> fftInput = segment;
int toFill = m_maxSegmentSize - fftInput.size();
for (int i = 0; i < toFill; i++)
fftInput.append(0);
return fftInput;
}
QVector<float> FFT::euclidNorm(QVector<kiss_fft_cpx> cpx) {
if (cpx.isEmpty()) return QVector<float>();
QVector<float> magnitudes;
magnitudes.reserve(m_espdSize);
for (kiss_fft_cpx val : cpx) {
float mag = qSqrt((val.r * val.r) + (val.i * val.i));
magnitudes.append(mag);
}
return magnitudes;
}