Go Down

Topic: Question about magnitude (Read 4049 times) previous topic - next topic

Noisecontrol

#30
Jun 14, 2018, 03:06 pm Last Edit: Jun 14, 2018, 03:27 pm by Noisecontrol
Hello
Maximum adc is 1024 then why  when adc analized by fft ,magnitude value in per bin frequency could be greater than 1024 ?
If magnitude in per frequency should not
 be less than 1024 ?

TolpuddleSartre

Quote
Maximum adc is 1024
No, 1023.

Noisecontrol

How can i fft result ( magnitude)convert to voltage in per frequency bin?

vffgaston



DVDdoug

I don't know how it's scaled, but if you can't find it in the documentation you can calibrate it. 

For example, feed-in a 1V, 1kHz, signal and see what you get.    Then, you can use the map() function to map the values to voltage.   If you feed-in a 1V, 100Hz, signal you should get (about) the same reading in the 100Hz bin.  And if you mix the two signals both bins should still read (about) the same as before.   

Choose frequencies that are in the center of the bin frequencies.

...If you need a way to generate sine waves, Audacity can make a WAV file. that you can play on your soundcard.     You can also mix in Audacity so you can try with two (or more) known frequencies.   But since mixing is done by summation, you'll want to generate waves at -6dB (half of the maximum) or less.    And, you'll need a multimeter to measure the voltage.   

Noisecontrol

I didnt find any documantion about convert fft results to adc or voltage in google.

But when fft analized a signal , we have expected that get amplitud in per frequency base that factor analized. in other word if adc is amplitude of a signal in per time we have expected frequncies have same unit amplituid

jremington

#37
Jun 14, 2018, 05:38 pm Last Edit: Jun 14, 2018, 05:40 pm by jremington
Quote
I didnt find any documantion about convert fft results to adc or voltage in google.
Presumably you mean DAC, which standard Arduinos do not have, but why would anyone bother to document something so simple?

Code: [Select]
    analogWrite(pin,bin_value);

jremington

#38
Jun 14, 2018, 05:53 pm Last Edit: Jun 14, 2018, 06:27 pm by jremington
Quote
Maximum adc is 1024 then why  when adc analized by fft ,magnitude value in per bin frequency could be greater than 1024 ?
Possibly, depending on how the FFT results are scaled. Different FFT subroutine packages scale the output differently.

Here is an idea: write some simple programs and learn how the FFT works.

That way you can answer questions like this yourself, and learn something in the process.

Example using the OpenMusicLabs FFT library:
Code: [Select]

/*
  fft_test_constant
  example sketch for testing the fft library.
  This generates a constant data set demonstrating the DC
  offset term. Enable the fft_window() line to see the effect of
  windowing.
*/

// do #defines BEFORE #includes
#define LIN_OUT 1 // use the lin output function
#define FFT_N 32 // set to 32 point fft

#include <FFT.h> // include the library

void setup() {
  int i, k;

  Serial.begin(9600); // output on the serial port

  for (i = 0 ; i < FFT_N ; i++) { // create data samples
    fft_input[2 * i] = 1000; // put real data into even bins
    fft_input[2 * i + 1] = 0; // set odd bins to 0
  }
  //  fft_window();  //Try with and without this line, it smears

  fft_reorder(); // reorder the data before doing the fft
  fft_run(); // process the data using the fft
  fft_mag_lin(); // calculate the magnitude of the output
  // print the frequency index and amplitudes
  Serial.println("bin  amplitude");
  for (i = 0; i < FFT_N / 2; i++) {
    Serial.print(i);
    Serial.print("       ");
    Serial.println(fft_lin_out[i]);
  }
  Serial.println("Done");
}

void loop() {}


Output:
Code: [Select]

bin  amplitude
0       1000
1       0
2       0
3       0
4       0
5       0
6       0
7       0
8       0
9       0
10       0
11       0
12       0
13       0
14       0
15       0
Done

Noisecontrol

Presumably you mean DAC, which standard Arduinos do not have, but why would anyone bother to document something so simple?

Code: [Select]
    analogWrite(pin,bin_value);
No i want to convert fft results in per bin to voltage

jremington

#40
Jun 14, 2018, 06:31 pm Last Edit: Jun 14, 2018, 06:32 pm by jremington
Quote
No i want to convert fft results in per bin to voltage
Explain this comment, and explain why you think analogWrite() does not do what you want.

PieterP

#41
Jun 14, 2018, 06:34 pm Last Edit: Jun 14, 2018, 07:21 pm by PieterP
We've been over this in your previous thread.

You even started a third thread on the topic.

Please don't cross-post!

You have to correct for a couple of things:
  • Subtract the bias voltage (expressed in ADC units) from the sampled signal
  • Use the complex modulus of the FFT result to get the magnitude
  • Divide by the number of samples to correct for the FFT processing gain
  • Multiply by 2 to account for magnitude "lost" in negative part of the spectrum
  • Divide by the average amplitude of the windowing function
  • Convert the magnitude in ADC units to a voltage (*5/1024)


Here's a MATLAB/Octave script that does exactly that, together with the result, to get an understanding of what's going on. See line 58 for the actual conversion.
Code: [Select]
%% Setup

close all;

N = 128;  % 128 samples → 128 frequency bins
samples = (0:N-1)';

f_s = 256;     % 256 Hz sample frequency

f   = 64;      % Sine wave with a frequency of 64 Hz
A   = 1.25;    % and amplitude of 1.25 V peak

V_bias = 2.5;
V_ref = 5;

ADC_bits = 10;
ADC_factor = 2^ADC_bits;

t = samples / f_s;     % Generate a vector with time

sine_V = A*sin(2*pi*f*t); % Sine wave in volts
sine_V = sine_V + V_bias; % Bias
sine = sine_V * ADC_factor / V_ref; % Sine wave as sampled by the Arduino

subplot(2,2,1);
plot(samples, sine, '-o');
axis([0 N 0 ADC_factor])
title('Original 1.25 V peak, 64 Hz sine wave (ADC Units)');

%% DC offset correction

sine = sine - V_bias * ADC_factor / V_ref; % Subtract bias again

%% Windowing

window = hamming(N);
mean_window = mean(window);
windowed_sine = window.*sine; % Apply window function

subplot(2,2,3);
hold on;
plot(samples, windowed_sine, '-o');
plot(samples, ADC_factor * window / 2, '-k');
plot(samples, -ADC_factor * window / 2, '-k');
title('Sine wave after applying window');
axis([0 N -ADC_factor/2 ADC_factor/2])

%% FFT

fft_sine = fft(windowed_sine);
freq = samples * f_s / N;

subplot(2,2,2);
stem(freq, abs(fft_sine));
axis([0 f_s 0 inf]);
title('Magnitude per frequency bin after FFT');

corrected_fft = fft_sine / N * 2 / mean_window * V_ref / ADC_factor;
subplot(2,2,4);
half = length(freq) / 2;
stem(freq(1:half), abs(corrected_fft(1:half)));
axis([0 f_s / 2 0 inf]);
title('Magnitude per frequency bin after FFT (corrected)');


Here's the result:


If you want the RMS voltage, I already gave you the formula in your previous thread.

If you're using a dB scale, express the divisions as a sum of constant logarithms, using the identities log(x*y) = log(x)+log(y) and log(x/y) = log(x) - log(y).

Pieter

Coding Badly

#42
Jun 14, 2018, 07:19 pm Last Edit: Jun 14, 2018, 07:20 pm by Coding Badly

Threads merged.  Again.


Noisecontrol

#43
Jun 14, 2018, 08:17 pm Last Edit: Jun 14, 2018, 08:23 pm by Noisecontrol
You have to correct for a couple of things:
  • Subtract the bias voltage (expressed in ADC units) from the sampled signal
  • Use the complex modulus of the FFT result to get the magnitude
  • Divide by the number of samples to correct for the FFT processing gain
  • Multiply by 2 to account for magnitude "lost" in negative part of the spectrum
  • Divide by the average amplitude of the windowing function
  • Convert the magnitude in ADC units to a voltage (*5/1024)

If you have source code of this process for arduino please share it.
I dont know MATLAB code

PieterP

If you have source code of this process for arduino please share it.
I dont know MATLAB code
I don't have the Arduino code for this, and I can't test it.
The principle is explained in my post, you can look at the MATLAB implementation for inspiration.
You should be able to read it, even if you don't know the exact syntax. Line 58 is the most important line.
Can you explain what you don't understand?

Like I said before, using FFT doesn't seem to be the standard way to perform A-weighting, you should probably look into digital filters instead.

Go Up