| 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 |