Electronics > Beginners
Making a sound camera
<< < (12/13) > >>
ebastler:

--- Quote from: daslolo on May 01, 2018, 11:03:03 pm ---Anyway I got the FFT running, and having two cores is sweet, so I might as well use programming to make this thing.
https://github.com/laurentopia/M5-Signal-Multimeter

--- End quote ---

What's the hardware in that picture? (The little screen plus processor device to the left?) Looks neat!
hamster_nz:

--- Quote from: Marco on May 08, 2018, 01:36:20 pm ---
--- Quote from: hamster_nz on May 04, 2018, 03:02:43 am ---The signature must also have structure to it - one bit of pure random noise is much like any other bit of random noise.

--- End quote ---

It's the opposite, each bit of noise is unique. A white noise source will give a really clear spike when you cross correlate two microphones receiving it.

--- End quote ---

Yes, you are right.
daslolo:

--- Quote from: ebastler on May 08, 2018, 07:50:25 pm ---
--- Quote from: daslolo on May 01, 2018, 11:03:03 pm ---Anyway I got the FFT running, and having two cores is sweet, so I might as well use programming to make this thing.
https://github.com/laurentopia/M5-Signal-Multimeter

--- End quote ---

What's the hardware in that picture? (The little screen plus processor device to the left?) Looks neat!

--- End quote ---
M5Stack
daslolo:

--- Quote from: hamster_nz on May 08, 2018, 12:03:18 pm ---I will be the first to admit that this is just a hack, you will need to develop and test it...

--- End quote ---

Thank you so much: it does what I need. I like that you didn't bother with FFT and I never realized how slow DFT is until now :)
Why is the FFT size half the sample size?
In term of cpu cost, counting 5 microphones will this need 5!=120x iFFT + 5x FFT + 5x flipped FFT?
You flip X1 before doing a complex mult, is this the equivalent to a convolution? If so, could the entire thing be done with applying a NxN kernel to both signal?

If anyone wants to try it real quick on their mCPU, here is the arduino code:


--- Code: ---#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "Adafruit_GFX.h"// Hardware-specific library
#include <MCUFRIEND_kbv.h>
MCUFRIEND_kbv tft;

#define POINTS   (128)
#define FFT_SIZE (POINTS/2+1)
#define PI       (3.1415926535897932384626433)

double samples1[POINTS], samples2[POINTS], samples1flipped[POINTS];
double spectrum1_r[FFT_SIZE], spectrum1_i[FFT_SIZE];
double spectrum2_r[FFT_SIZE], spectrum2_i[FFT_SIZE];
double spectrumX_r[FFT_SIZE], spectrumX_i[FFT_SIZE];
double samplesX[POINTS];


/**********************************************************************/
void generate_signature(double *samples)
{
int i;
for (i = 0; i < POINTS; i++)
samples[i] = 0;

for (i = 0; i < 5; i++) samples[i] = -1.0;
for (i = 5; i < 10; i++) samples[i] = 1.0;
for (i = 10; i < 15; i++) samples[i] = -1.0;
for (i = 15; i < 20; i++) samples[i] = 1.0;
}

/**********************************************************************/
void flip_samples(double *s1, double *s2)
{
int i;
for (i = 0; i < POINTS; i++)
s2[i] = s1[POINTS - 1 - i];
}
/**********************************************************************/
void offset_sample(double *samples1, double *samples2, int offset)
{
int i;
for (i = 0; i < POINTS; i++)
samples2[i] = samples1[(i - offset) % POINTS];
}

/**********************************************************************/
void complex_mult(double *r1, double *i1,
double *r2, double *i2,
double *r3, double *i3)
{
int i;
for (i = 0; i < FFT_SIZE; i++)
{
r3[i] = (r1[i] * r2[i]) - (i1[i] * i2[i]);
i3[i] = (r1[i] * i2[i]) + (r2[i] * i1[i]);
}
}

/**********************************************************************/
void add_noise(double *samples, double level)
{
int i;
for (i = 0; i < POINTS; i++)
{
samples[i] += (rand()*level) / RAND_MAX;
}
}

/**********************************************************************/
void print_max(double *samples)
{
int    max_i = 0;
double max = samples[0];
int i;
for (i = 1; i < POINTS; i++)
{
if (samples[i] > max)
{
max_i = i;
max = samples[i];
}
}

if (max_i >= POINTS / 2)
max_i -= POINTS;
printf("Max is at %i (%10.4f)\n", max_i, max);
 tft.drawLine(max_i, 50, max_i,150, 0b111111111100000);
tft.setCursor(0, 170);
tft.print("Offset = ");
 tft.print(max_i);
}

/**********************************************************************/
void dft(double *samples, double *r, double *i)
{
int b, p;
for (b = 0; b < FFT_SIZE; b++)
{
r[b] = 0.0;
i[b] = 0.0;
for (p = 0; p < POINTS; p++)
{
double angle = 2 * PI*b*p / POINTS;
r[b] += samples[p] * cos(angle);
i[b] -= samples[p] * sin(angle);
}
}
}

/******************************************************/
void idft(double *r, double *i, double *samples)
{
int b, p;
double rs[FFT_SIZE];
double is[FFT_SIZE];

for (b = 0; b < FFT_SIZE; b++)
{
rs[b] = r[b] / (POINTS / 2);
is[b] = -i[b] / (POINTS / 2);
}
rs[0] = r[0] / POINTS;
rs[FFT_SIZE - 1] = r[FFT_SIZE - 1] / POINTS;

for (p = 0; p < POINTS; p++)
{
for (b = 0; b < FFT_SIZE; b++)
{
double angle = 2 * PI*b*p / POINTS;
samples[p] += (rs[b] * cos(angle)) + (is[b] * sin(angle));
}
}
}
/******************************************************/
void setup(void)
{
Serial.begin(115200);
  uint16_t ID = tft.readID();
  tft.begin(ID);
  tft.setRotation(1);
  tft.fillScreen(0x0000);

int i;
/* Prepare the data */
generate_signature(samples1);
offset_sample(samples1, samples2, 50);
add_noise(samples2, 0.8);

 double timer = micros();

/* Flip the samples to turn convolution it to correlation */
flip_samples(samples1, samples1flipped);

/* Take the DFT */
dft(samples1flipped, spectrum1_r, spectrum1_i);
dft(samples2, spectrum2_r, spectrum2_i);

/* Multiply the spectrums */
complex_mult(spectrum2_r, spectrum2_i,
spectrum1_r, spectrum1_i,
spectrumX_r, spectrumX_i);

/* Inverse DFT to find how well they match */
idft(spectrumX_r, spectrumX_i, samplesX);

tft.setCursor(0,0);
  tft.println(micros()-timer);

for (i = 0; i < POINTS; i++)
{
tft.drawLine(i, 100 - 10 * samples1[i - 1], i, 100 - 10 * samples1[i], 0b0000000000011111);
tft.drawLine(i, 100 - 10 * samples2[i - 1], i, 100 - 10 * samples2[i], 0b0000010000011111);
tft.drawLine(i, 100 - 2 * samplesX[i - 1], i, 100 - 2 * samplesX[i],   0b1111100000000000);
}
print_max(samplesX);
}

void loop(void) {}
--- End code ---
hamster_nz:

--- Quote from: daslolo on May 09, 2018, 11:18:14 pm ---Thank you so much: it does what I need. I like that you didn't bother with FFT and I never realized how slow DFT is until now :)

--- End quote ---

You could easily make it a bit faster by not calling SIN() and COS() so much, you can make a lookup table but it will cost you in memory. That way sin() and cos() become something like:

sin = sin_table[(index*band)%table_size];
cos = sin_table[(table_size/4+index*band)%table_size];

You have to 'flip' (actually mirror in time) the needle that you are looking for in the haystack.  My code is slightly wrong, and gives you a peak with an offset that is off by one - item 0 should not move, but items[1] & items[n-1] should swap and so on.

I am not sure you will need all 120 IFFTs. You may only need to do a handful to get enough information that you can locate the source.
Navigation
Message Index
Next page
Previous page
There was an error while thanking
Thanking...

Go to full version
Powered by SMFPacks Advanced Attachments Uploader Mod