I'm trying to create a spectrogram like the one in matplotlib and in this library, they return the PSD (Power Spectra Density) rather than the absolute magnitude etc..
I want to implement the PSD into my own code (written in C++) I've been looking at the source code for matplotlib it looks something like this:
result, windowVals = apply_window(result, window, axis=0,
return_window=True)
result = np.fft.fft(result, n=pad_to, axis=0)[:numFreqs, :]
result = np.conjugate(result) * result
# calculations for PSD
result /= (np.abs(windowVals)**2).sum()
result[1:-1] *= scaling_factor
Link can be found: Here
Now I would like to do the same, I'm up to the part where I've applied windows, and, performed the DFT. From there, is where I think I am going wrong.
Here is my code for calculating PSD.
std::vector CalculatePSD(std::vector &vals)
{
std::vector<double> hanning = getHanningWindow(vals.size());
std::vector<double> vals2(vals.size());
for(unsigned i=0; (i < vals.size()); i++)
{
double v = vals[i].re * (-1 * vals[i].im);
vals2[i] = v * v;
}
double vi = 0.0;
for(unsigned i=0; (i < vals2.size()); i++)
{
vi += abs(hanning[i]);
}
for(unsigned i=0; (i < vals2.size()); i++)
{
vals2[i] /= vi;
}
for(unsigned i=0; (i < vals2.size()); i++)
{
vals2[i] *= 2;
}
return vals2;
}
My results that I get:
[ 2.66926000e-10 4.71270000e-10 3.25024000e-10 1.86008000e-10
8.68276000e-11 2.53098000e-11 7.92737000e-13 5.29274000e-12
1.90057000e-11 3.27736000e-11 4.42093000e-11 4.60725000e-11
4.98549000e-11 6.08991000e-11 5.59033000e-11 2.26625000e-11
7.17159000e-13 1.65150000e-12 1.31530000e-12 7.86863000e-14
1.59211000e-13 2.80960000e-13 1.25471000e-13 1.35225000e-11
1.09812000e-10 3.49411000e-10 5.96210000e-10 6.43539000e-10
4.85667000e-10 2.46446000e-10 7.61480000e-11 7.70735000e-12
3.79924000e-13 4.16633000e-13 9.22683000e-12 6.23747000e-11
1.80818000e-11 5.13819000e-11 7.20294000e-10 2.46505000e-09
4.42844000e-09 4.77968000e-09 3.06048000e-09 1.12040000e-09
1.15313000e-10 4.78101000e-11 2.96048000e-10 3.93216000e-10
2.66339000e-10 1.01348000e-10 3.13012000e-11 3.59365000e-11
3.00758000e-11 2.44970000e-11 4.19013000e-12 1.92963000e-12
7.62176000e-13 9.83650000e-14 4.47749000e-15 3.29484000e-19
7.46089000e-14 3.99184000e-12 4.75458000e-11 3.36518000e-10
9.34579000e-10 9.14683000e-10 1.34570000e-10 6.47235000e-11
1.21893000e-10 1.44874000e-11 5.37149000e-15 1.93477000e-11
1.15593000e-10 1.27684000e-10 2.10146000e-11 9.34294000e-13
8.85961000e-12 6.35360000e-12 3.88437000e-13 2.75095000e-13
1.07261000e-11 9.35213000e-12 4.16280000e-11 1.52995000e-11
9.86730000e-12 2.04171000e-11 9.69115000e-12 1.81067000e-12
1.64522000e-13 4.01619000e-12 2.81457000e-13 5.86617000e-13
1.33937000e-11 3.16438000e-11 8.83417000e-11 1.24155000e-10
9.36973000e-11 1.89000000e-12 4.76718000e-14 3.46776000e-13
3.88868000e-12 1.01426000e-12 7.87006000e-13 1.02698000e-10
6.80669000e-12 3.22014000e-12 9.92309000e-12 1.17853000e-10
1.20818000e-11 2.20125000e-12 8.78943000e-12 3.34323000e-10
4.28139000e-10 3.57678000e-10 1.57808000e-10 2.05267000e-11
8.98399000e-11 1.12894000e-11 3.21320000e-14 7.77191000e-12
5.91681000e-13 9.92243000e-16 2.10894000e-11 2.19397000e-12
1.14148000e-12 3.41732000e-12 1.81439000e-12 1.46689000e-11]
Whereas the results in Python:
[ 6.44554713e-04 2.26979569e-02 1.48395306e-02 1.39560086e-02
1.70585613e-02 4.24042116e-04 4.10722082e-04 1.77314474e-02
5.48046037e-03 6.86724979e-03 1.33342952e-02 5.45918807e-04
1.42011959e-06 8.15283041e-03 3.02976247e-02 2.95310636e-02
2.69222586e-02 2.70161073e-04 4.27988811e-04 8.22069685e-03
1.14550280e-03 5.94684341e-03 5.03412155e-03 2.39065158e-04
1.88851349e-03 1.63618611e-02 1.02155767e-02 5.56409334e-03
2.03783039e-02 1.30646965e-03 7.83925381e-03 6.58153969e-04
8.58222471e-05 4.90329132e-03 9.27321780e-03 2.18878971e-02
7.80419597e-03 1.65506496e-05 2.12233732e-03 3.48564618e-02
3.04324943e-02 1.14097124e-02 1.83163044e-02 5.53528648e-04
1.72024876e-03 1.05496508e-02 1.22350425e-02 6.81764861e-03
2.18181750e-02 1.25305967e-04 3.45533908e-04 2.52806605e-02
2.79032703e-02 3.30741745e-02 8.92045889e-03 1.43861624e-04
1.37729407e-03 4.40048633e-02 4.43466583e-02 3.21348174e-02
1.97845126e-02 4.76052263e-05 1.90059116e-03 1.36124930e-02
3.08483724e-02 3.18817777e-02 4.22224299e-02 6.48991341e-04
3.37298579e-04 1.92796091e-02 3.26384995e-02 7.44582047e-03
2.75911372e-02 8.24143406e-05 6.19298800e-04 2.18909904e-02
7.85534253e-03 1.35622242e-02 1.64534364e-02 4.24610034e-07
1.25296965e-04 3.85049720e-03 1.56208315e-02 1.51067447e-02
1.15560295e-02 1.91845524e-02 1.51484986e-02 3.68090803e-05
4.56878093e-04 1.32583767e-02 2.67413477e-02 2.12116190e-02
1.40731136e-02 7.46782595e-06 7.56130481e-04 1.11894743e-02
3.82556474e-02 2.20488800e-02 1.18449472e-02 6.41610843e-05
8.93214478e-04 1.44705708e-02 8.95544599e-03 8.24627650e-03
1.54125088e-02 3.82922435e-07 1.21567170e-03 3.66207393e-02
2.52421164e-02 2.79258696e-02 2.42711875e-02 4.41070028e-04
9.18506931e-04 2.29391748e-02 2.93676503e-06 3.51546485e-02
1.53622376e-03 3.93588210e-05 3.35935113e-04 1.74232319e-02
1.89744096e-02 1.02178421e-02 1.54763125e-02 7.24992746e-05
3.46909205e-04 2.41130633e-02 1.96140922e-02 1.94479820e-02
1.02416629e-02 1.08582494e-04 5.91329398e-04 8.53889890e-03
8.05471223e-03 1.78734494e-02 2.12358089e-02 2.74402258e-02
1.86277585e-02 2.97114647e-06 1.58242458e-03 1.77131478e-02
1.03301989e-03 1.17236867e-02 2.70723000e-02 2.45157582e-04
1.70524416e-04 1.12361676e-03]
I'm probably going somewhere wrong with the conversion of the code, since I don't know Python all to well. If anyone spots where I might be going wrong, it would help me greatly.
EDIT:
complex<double> foo[vals.size()];
for(unsigned i=0; (i < vals.size()); i++)
{
foo[i] = complex<double>(vals[i].re, vals[i].im);
}
std::vector<double> vals2(vals.size());
for(unsigned i=0; (i < vals2.size()); i++)
{
double d =(std::conj(foo[i])*std::real(foo[i]));
}
Your function returns vals (modifying it by reference), while you seem to be storing result in vals2, which is local variable that gets deleted at the end of function.
EDIT
Yes, it seems like the error might be in conjugation - why not use std::complex functionality reproducing python code as it is instead of reinventing the wheel:
for(unsigned i=0; (i < vals.size()); i++)
{
vals2[i]= (vals[i].conj()*vals[i]).re();
}
Related
I have another question. I have been following a tutorial for creating a QPSK demodulator. Here is the link: https://wiki.gnuradio.org/index.php/Guided_Tutorial_GNU_Radio_in_C%2B%2B
I was able to fix a different issue and fixed a warning that I was receiving but, a new problem has come about and I can't seem to fix it. Here is the error:
Traceback (most recent call last):
File "/home/mariom/gr-tutorial/build/top_block.py", line 191, in <module>
main()
File "/home/mariom/gr-tutorial/build/top_block.py", line 167, in main
tb = top_block_cls()
File "/home/mariom/gr-tutorial/build/top_block.py", line 82, in __init__
self.tutorial_my_qpsk_demod_cb_0 = tutorial.my_qpsk_demod_cb(True)
AttributeError: module 'tutorial' has no attribute 'my_qpsk_demod_cb'
Noramlly when I see this error, I think I know how to fix this and go find the module tutorial and add the my_qpsk_demod_cb. This time, I seem to be running into the problem that I can't seem to find the right area or maybe I am in the right area. I understand that the issue is from the block I made from the tutorial so any thought? Here is block codes.
My_qpsk_demod_cb_impl.cc
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gnuradio/io_signature.h>
#include "my_qpsk_demod_cb_impl.h"
namespace gr {
namespace tutorial {
my_qpsk_demod_cb::sptr
my_qpsk_demod_cb::make(bool gray_code)
{
return gnuradio::get_initial_sptr
(new my_qpsk_demod_cb_impl(gray_code));
}
/*
* The private constructor
*/
my_qpsk_demod_cb_impl::my_qpsk_demod_cb_impl(bool gray_code)
: gr::block("my_qpsk_demod_cb",
gr::io_signature::make(1, 1, sizeof(gr_complex)),
gr::io_signature::make(1, 1, sizeof(char))),
d_gray_code(gray_code)
{
}
/*
* Our virtual destructor.
*/
my_qpsk_demod_cb_impl::~my_qpsk_demod_cb_impl()
{
}
void
my_qpsk_demod_cb_impl::forecast(int noutput_items,
gr_vector_int &ninput_items_required)
{
unsigned ninputs = ninput_items_required.size ();
for(unsigned i = 0; i < ninputs; i++)
ninput_items_required[i] = noutput_items;
}
unsigned char
my_qpsk_demod_cb_impl::get_minimum_distances(const gr_complex &sample)
{
if (d_gray_code) {
unsigned char bit0 = 0;
unsigned char bit1 = 0;
// The two left quadrants (quadrature component < 0) have this bit set to 1
if (sample.real() < 0) {
bit0 = 0x01;
}
// The two lower quadrants (in-phase component < 0) have this bit set to 1
if (sample.imag() < 0) {
bit1 = 0x01 << 1;
}
return bit0 | bit1;
} else {
// For non-gray code, we can't simply decide on signs, so we check every single
quadrant.
if (sample.imag() >= 0 and sample.real() >= 0) {
return 0x00;
}
else if (sample.imag() >= 0 and sample.real() < 0) {
return 0x01;
}
else if (sample.imag() < 0 and sample.real() < 0) {
return 0x02;
}
else if (sample.imag() < 0 and sample.real() >= 0) {
return 0x03;
}
}
return 0;
}
int
my_qpsk_demod_cb_impl::general_work (int noutput_items,
gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
const gr_complex *in = (const gr_complex *) input_items[0];
unsigned char *out = (unsigned char *) output_items[0];
gr_complex origin = gr_complex(0,0);
// Perform ML decoding over the input iq data to generate alphabets
for(int i = 0; i < noutput_items; i++)
{
// ML decoder, determine the minimum distance from all constellation points
out[i] = get_minimum_distances(in[i]);
}
// Tell runtime system how many input items we consumed on
// each input stream.
consume_each (noutput_items);
// Tell runtime system how many output items we produced.
return noutput_items;
}
} /* namespace tutorial */
} /* namespace gr */
my_qpsk_demod_cb_impl.h
#ifndef INCLUDED_TUTORIAL_MY_QPSK_DEMOD_CB_IMPL_H
#define INCLUDED_TUTORIAL_MY_QPSK_DEMOD_CB_IMPL_H
#include <tutorial/my_qpsk_demod_cb.h>
namespace gr {
namespace tutorial {
class my_qpsk_demod_cb_impl : public my_qpsk_demod_cb
{
private:
bool d_gray_code;
public:
my_qpsk_demod_cb_impl(bool gray_code);
~my_qpsk_demod_cb_impl();
unsigned char get_minimum_distances(const gr_complex &sample);
// Where all the action really happens
void forecast (int noutput_items, gr_vector_int &ninput_items_required);
int general_work(int noutput_items,
gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items);
};
} // namespace tutorial
} // namespace gr
#endif /* INCLUDED_TUTORIAL_MY_QPSK_DEMOD_CB_IMPL_H */
I think you are missing swig/dependencies or PYTHONPATH. I had the same issue, and was able to resolve it by following these fixes:
Install dependencies specific to your environment (including swig): https://wiki.gnuradio.org/index.php/UbuntuInstall#Bionic_Beaver_.2818.04.29_through_Eoan_Ermine_.2819.10.29
Configure PYTHONPATH and/or LD_LIBRARY_PATH according to these steps: https://wiki.gnuradio.org/index.php/ModuleNotFoundError
(Note that order may matter according to this case: https://lists.gnu.org/archive/html/discuss-gnuradio/2016-03/msg00065.html)
I'm trying to realize a multi trilateration in c++. I have three ranges with which I want to determine a certain point in 3d space. I've already looked up for solutions and found a usable python code snipped. Then I have rewritten the whole snipped in c++ but the results are kind of odd and of the expected results. Their must be some common mistakes which I just don't see (maybe it's too obvious lol).
The test data is from here, and I know that this linear way of solving the gps trillat problem is not even remotely accurate but that's not important for my purpose.
The resulting vector is: -3.39803e+29, 3.39803e+29, -3.39803e+29 which cannot be true.
/* Recursive function for finding determinant of matrix.
n(rows) is current dimension of A[][]. */
double clacDeterminant(double **A, int rows)
{
double D = 0; // Initialize result
// Base case : if matrix contains single element
if (rows == 1)
return A[0][0];
int sign = 1; // To store sign multiplier
// Iterate for each element of first row
for (int f = 0; f < rows; f++)
{
// Getting Cofactor of A[0][f]
double **temp = getCofactor(A, 0, f, rows);
D += sign * A[0][f] * clacDeterminant(A, rows - 1);
// terms are to be added with alternate sign
sign = -sign;
}
return D;
}
// Function to get adjoint of A[N][N] in adj[N][N].
double** calcAdjoint(double **A, int matrixArows)
{
double** adj = allocate2Ddouble(matrixArows, posMTrillatASize);
int sign = 0;
for (int i=0; i<matrixArows; i++)
{
for (int j=0; j<posMTrillatASize; j++)
{
// Get cofactor of A[i][j]
double **temp = getCofactor(A, i, j, posMTrillatASize);
// sign of adj[j][i] positive if sum of row
// and column indexes is even.
sign = ((i+j)%2==0)? 1: -1;
// Interchanging rows and columns to get the
// transpose of the cofactor matrix
adj[i][j] = (sign)*(clacDeterminant(A, posMTrillatASize-1));
}
}
return adj;
}
// by https://www.programiz.com/cpp-programming/examples/matrix-multiplication-function modified by L.K.
// method assumes that matrices have same dim sizes
double** multiplyMatrices(double **matrixA, double **matrixB, int matrixArows)
{
double** outputMatrix = allocate2Ddouble(matrixArows, posMTrillatASize);
int i, j, k;
// Initializing elements of matrix mult to 0.
for(i = 0; i < matrixArows; ++i)
{
for(j = 0; j < posMTrillatASize; ++j)
{
outputMatrix[i][j] = 0;
}
}
// Multiplying matrix matrixA and matrixB and storing in array mult.
for(i = 0; i < matrixArows; ++i)
{
for(j = 0; j < posMTrillatASize; ++j)
{
for(k=0; k<posMTrillatASize; ++k)
{
outputMatrix[i][j] += matrixA[i][k] * matrixB[k][j];
}
}
}
return outputMatrix;
}
double* multiplyMatrixByVector(double **matrixA, double vectorB[])
{
double vectorRes[posMTrillatASize];
memset(vectorRes, 0, posMTrillatASize*sizeof(double));
for (int i=0;i<posMTrillatASize;i++)
{
for (int j=0;j<posMTrillatASize;j++)
{
vectorRes[i]+= (matrixA[i][j]*vectorB[j]);
}
}
return vectorRes;
}
double** transpose2DimMatrix(double **inputArr, int matrixArows, int transpose2DimMatrix)
{
double **outputArr = allocate2Ddouble(transpose2DimMatrix, matrixArows);
for (int i = 0; i < matrixArows; ++i)
{
for (int j = 0; j < transpose2DimMatrix; ++j)
{
outputArr[j][i] = inputArr[i][j];
}
}
return outputArr;
}
// Function to calculate and store inverse, returns 0 if false
// matrix is singular by https://www.geeksforgeeks.org/adjoint-inverse-matrix/
double** calcInverse(double **A, int matrixArows)
{
double** inverse = allocate2Ddouble(matrixArows, posMTrillatASize);
// Find determinant of A[][]
int det = clacDeterminant(A, posMTrillatASize);
if (det == 0)
{
cout << "Singular matrix, can't find its inverse";
return 0;
}
// Find adjoint
double **adj = calcAdjoint(A, matrixArows);
// Find Inverse using formula "inverse(A) = adj(A)/det(A)"
for (int i=0; i<matrixArows; i++)
for (int j=0; j<posMTrillatASize; j++)
inverse[i][j] = adj[i][j]/double(det);
return inverse;
}
double* leastSquareReg(double **matrixA, double vectorB[], int matrixArows, int matrixAcol)
{
double **matrixATransposed = transpose2DimMatrix(matrixA, matrixArows, matrixAcol);
double **matrixATransposedA = multiplyMatrices(matrixATransposed, matrixA, matrixAcol);
double **matrixATransposedAInverse = calcInverse(matrixATransposedA, matrixArows);
double **matrixATransposedAAdd = multiplyMatrices(matrixATransposedAInverse, matrixATransposed, matrixArows);
double *finalX = multiplyMatrixByVector(matrixATransposedAAdd, vectorB);
return finalX;
}
ecefPos trillatPosFromRange(satLocation finalSatPos, satRanges finalSatRanges)
{
std::map<int, ecefPos>::iterator it_;
std::map<int, double>::iterator finalSatRangesMap;
int matrixArows, matrixAcol = 0;
double x, y, z;
double Am, Bm, Cm, Dm;
double range;
int nSat = finalSatPos.locations.size();
ecefPos finalPos = { 0.0, 0.0, 0.0 };
matrixAcol = posMTrillatASize;
matrixArows = nSat;
double **matrixA = allocate2Ddouble(nSat, 3);
double vectorB[posMTrillatASize] = {};
int i = 0;
for (it_ = finalSatPos.locations.begin(); it_ != finalSatPos.locations.end(); it_++)
{
// look up for pseudo range with same sat id
finalSatRangesMap = finalSatRanges.ranges.find(it_->first);
range = finalSatRangesMap->second;
if (it_ != finalSatPos.locations.end())
{
x = it_->second.x;
y = it_->second.y;
z = it_->second.z;
Am = -2*x;
Bm = -2*y;
Cm = -2*z;
Dm = EARTH_RADIUS_KM*EARTH_RADIUS_KM + (pow(x,2)+pow(y,2)+pow(z,2)) - pow(range,2);
matrixA[i][0] = Am;
matrixA[i][1] = Bm;
matrixA[i][2] = Cm;
vectorB[i] = Dm;
i++;
} else
{
std::cout << "could not find sat pos for user pos trilateration" << std::endl;
}
}
// least square regression
double *finalECEF = leastSquareReg(matrixA, vectorB, matrixArows, matrixAcol);
finalPos.x = finalECEF[0];
finalPos.y = finalECEF[1];
finalPos.z = finalECEF[2];
for (int i = 0; i < 5; ++i)
{
std::cout << finalECEF[i] << std::endl;
}
return finalPos;
}
I'm trying to build a simple C extension for Python, initially I'm trying to return the contents of an unsigned char array (binary data).
unsigned char frame_out[200];
// test data
for (int i = 0; i < 199; i++) {
frame_out[i] = (i&0xff);
}
PyObject* result = Py_BuildValue("y#", frame_out, 199);
return result;
The code above works fine and I can print the test values in Python. But I want the array, frame_out, to be dynamic so I use new() as shown below.
char* frame_out = new char[200]
// test data
for (int i = 0; i < 199; i++) {
frame_out[i] = (i&0xff);
}
PyObject* result = Py_BuildValue("y#", frame_out, 199);
return result;
This now gives an error when called from Python:
Process finished with exit code -1073741819 (0xC0000005)
I have also tried using malloc:
char* frame_out = (char* )malloc( sizeof(char) * 200);
But this gives the same error.
I have checked result and this is not null. What have I done wrong?
I created a *.so file for use in Python using SWIG, but when I import it I get this:
/_analyzer.so: undefined symbol: autocorellation
I did almost everything according to this instruction: https://scipy.github.io/old-wiki/pages/Cookbook/SWIG_NumPy_examples.html
my code is following:
analyzer.h:
void autocorellation(double *in, double *out, long long n);
analyzer.cpp:
#include "analyzer.h"
#include <math.h>
#include <stdlib.h>
#define PI 3.14159265358979323846
typedef struct {
double real;
double im;
} Complex;
void complex_multiply(Complex a,Complex b,Complex* c){
c->real = a.real * b.real - a.im * b.im;
c->im = a.real * b.im + a.im * b.real;
}
void complex_multiply_int(int a, Complex b,Complex* c){
c->real = a * b.real;
c->im = a * b.im;
}
void complex_sum(Complex a,Complex b,Complex* c){
c->real = a.real + b.real;
c->im = a.im + b.im;
}
void complex_conjugate(Complex* a,Complex* b,long long n){
for(int i = 0; i < n; ++i){
b[i].real = a[i].real;
b[i].im = -1 * a[i].im;
}
}
long long rev (long long num, long long lg_n) {
long long res = 0;
for (long long i=0; i < lg_n; ++i)
if (num & (1 << i))
res |= 1 << (lg_n-1-i);
return res;
}
void fft (Complex* a, long long n,bool invert) {
long long lg_n = 0;
while ((1 << lg_n) < n)
++lg_n;
for (long long i=0; i<n; ++i){
long long r= rev(i,lg_n);
if (i < r){
a[i].real = a[i].real + a[r].real;
a[r].real = a[i].real - a[r].real;
a[i].real = a[i].real - a[r].real;
a[i].im = a[i].im + a[r].im;
a[r].im = a[i].im - a[r].im;
a[i].im = a[i].im - a[r].im;
}
}
for (long long len=2; len<=n; len <<= 1) {
double ang = 2*PI/len * (invert ? -1 : 1);
Complex wn;
wn.real = cos(ang);
wn.im = sin(ang);
for (long long i=0; i<n; i+=len) {
Complex w;
w.real = 1;
w.im = 0;
long long ll = (long long)(len * 0.5);
for (long long j=0; j< ll; ++j) {
Complex u = a[i+j],v;
complex_multiply(a[i+j+ll],w,&v);
complex_sum(u,v,&a[i+j]);
complex_multiply_int(-1,v,&v);
complex_sum(u,v,&a[i+j+ll]);
complex_multiply(w,wn,&w);
}
}
}
if (invert)
for (long long i=0; i<n; ++i){
a[i].real /= n;
a[i].im /= n;
}
}
void autocorellation(double *in, double *out, long long n){
long long le = 1;
while(n > le)
le *= 2;
double m = 0;
for(int i = 0; i < n; ++i)
m+=in[i];
m /= n;
for(int i = 0; i < n; ++i)
in[i] -= m;
Complex* a = (Complex*) malloc(le*sizeof(Complex));
Complex* b = (Complex*) malloc(le*sizeof(Complex));
for(long long i = 0; i < n; ++i){
a[i].im = 0;
a[i].real = in[i];
}
for(long long i = n; i < le; ++i){
a[i].im = 0;
a[i].real = 0;
}
fft(a,le,false);
complex_conjugate(a,b,le);
Complex* c = (Complex*) malloc(le*sizeof(Complex));
for(long long i = 0; i < le; ++i)
complex_multiply(b[i],a[i],&c[i]);
fft(c,le,true);
for(long long i = 0; i < n; ++i)
out[i] = (c[i].real/c[0].real);
free(a);
free(b);
free(c);
}
analyzer.i:
%module analyzer
%{
#define SWIG_FILE_WITH_INIT
#include "analyzer.h"
%}
%include "numpy.i"
%init %{
import_array();
%}
%apply (double* IN_ARRAY1,int DIM1) {(double *in, long long n)}
%apply (double* ARGOUT_ARRAY1,int DIM1) {(double *out, long long n)}
%include "analyzer.h"
setup.py:
#! /usr/bin/env python
# System imports
from distutils.core import *
from distutils import sysconfig
# Third-party modules - we depend on numpy for everything
import numpy
# Obtain the numpy include directory. This logic works across numpy versions.
try:
numpy_include = numpy.get_include()
except AttributeError:
numpy_include = numpy.get_numpy_include()
# ezrange extension module
_analyzer = Extension("_analyzer",
["analyzer.i","analyzer.cpp"],
include_dirs = [numpy_include],
)
# ezrange setup
setup( name = "range function",
description = "Autocorellation function evaluation",
author = "Bodya",
version = "1.0",
ext_modules = [_analyzer]
)
The difference between your code and the cookbook examples is that your code is C++. Therefore, you need to pass the -c++ option to SWIG. In the construction of Extension(...) in setup.py, simply add swig_opts=['-c++'],.
Note that distutils will still invoke the C compiler on the generated wrapper file, but this will have a .cpp extension, so it should be compiled correctly if the compiler is gcc or clang.
My experience using distutils or setuptools for C++ SWIG extensions that are even slightly beyond trivial has been poor, so I invoke SWIG to generate a wrapper outside of distutils (I do it via a Makefile) and only use distutils to compile the extension from the wrapper file.
I'm interested in knowing just how matplotlib processes the spectrogram. I understand most parts, specifically in the FFT and others, but, to me the scaling does not seem correct. The default is to return the PSD of the signal, however, I cannot seem to replicate it whatsoever. For example, in matplotlib I get this result:
However, when trying to replicate this (in C++) I get this result:
In C++ and plotted with matplotlib I get this result:
I'm mainly interested in how they somehow "remove" the noise factor to show the bins which have the most power in them. The graph I shove (above) in C++ I get similar results, yet, they are different.
Any help would be really appreciated.
std::vector<std::vector<Complex::complex> > ComputeSTFT(std::vector<double>
&vals, std::size_t NFFT, std::size_t overlap)
{
std::vector<std::vector<double> > temp_vars = frame(vals, NFFT, overlap);
std::vector<std::vector<Complex::complex> > STFT(temp_vars.size());
std::vector<double> hanning = getHanningWindow(256);
for(unsigned i=0; (i < temp_vars.size()); i++)
{
for(unsigned j=0; (j < temp_vars[i].size()); j++)
{
double calculation = temp_vars[i][j] * hanning[j];
calculation = (calculation == -0) ? 0 : calculation;
temp_vars[i][j] = calculation;
}
}
std::vector<std::vector<Complex::complex> > fft_vars(temp_vars.size());
for(unsigned i=0; (i < temp_vars.size()); i++)
{
fft_vars.resize(temp_vars[i].size());
FFT f(temp_vars[i].begin(), temp_vars[i].end(), temp_vars[i].size());
std::vector<Complex::complex> temp_fft = f.transformed();
fft_vars[i] = temp_fft;
}
for(unsigned i=0; (i < temp_vars.size()); i++)
{
STFT[i].resize(temp_vars[i].size()/2+1);
for(unsigned j=0; (j < temp_vars[i].size()/2 + 1); j++)
{
STFT[i][j].re = fft_vars[i][j].re;
STFT[i][j].im = fft_vars[i][j].im;
}
}
return STFT;
}
std::vector<double> CalculatePSD(std::vector<Complex::complex> &vals)
{
std::vector<double> result(vals.size());
for(unsigned i=0; (i < vals.size()); i++)
{
double mag = vals[i].re * vals[i].re + vals[i].im * vals[i].im;
result[i] = mag;
}
std::vector<double> hanning = getHanningWindow(128);
double sum = 0.0;
for(unsigned i=0; (i < vals.size()); i++)
{
sum += abs(hanning[i]);
}
for(unsigned i=0; (i < vals.size()); i++)
{
result[i] = result[i] * 2/(12000)*sum;
//result[i] /= sum;
//result[i] *= 1;
}
return result;
}