FSK FFT demodulation

Hi,

I would like to demodulate a FSK signal using frecuency analysis. The FSK signal is modulated using two main frequencies (let's say 1khz and 2khz) and using a baud rate of 50bps, so 20ms for every 0 and 1.
Taking a look at the characteristics of the Arduino Mega I thing that is possible to do it. I have seen some libraries like Goertzel's implementation (GitHub - jacobrosenthal/Goertzel: Arduino Library implementation of the Goertzel algorithm) or FHT (ArduinoFHT - Open Music Labs Wiki).

The FHT library says that is capable of performing a 256 point FHT in less than 4ms.
The Goertzel's algorithm seems to be more quickly for computing a set a frequencies (like my case), but I tried it and seems that the outputs are not stable.

Do some of you tried to do something like that? Any guidance?

It has been quite a while since I played with tone detection, including the Goertzel algorithm, but I do recall that it is difficult to get the Goertzel tuned correctly so that it is stable. Once you do, it is quite reliable and fast. With some searching, you should be able find articles that explain the dirty details.

I will do a deeper search so, great to know that somebody has obtained good results.

Here is some code I was testing on decoding DTMF signals. The sample rate and buffer size are critical (as this sets the bandwidth), as well as the other constants. The inspiration came from a Circuit Cellar article in issue 187. I would recommend experimenting on a PC or Mac using the Code::Blocks IDE (or similar) rather than Arduino.

#include <stdio.h>
#include <math.h>

#define SAMPLING_RATE	11312.0
/* for touch tone signals, this prog checks the cross talk between tones
at a given sample frequency. at 11321 Hz, 852 Hz. is defined most poorly
sjr fall 2005, also 1/29/2006, see Circuit Cellar 187*/

#define N	205
#define PI 3.1415926536

float TT[7]={697.,770.,852.,941.,1209.,1336.,1477.};
float coeff;
float Q1;
float Q2;
float sine;
float cosine;
int binwidth;

unsigned char data[N];

/* Call this routine before every "block" (size=N) of samples. */
void ResetGoertzel(void)
{
  Q2 = 0;
  Q1 = 0;
}

/* Call this once, to precompute the constants. */
void InitGoertzel(float target)
{
  int	m;
  float	floatN;
  float	omega;

  floatN = (float) N;
  binwidth = (int) (0.5 + SAMPLING_RATE/floatN);
  m = (int) (0.5 + target / (float) binwidth);
  omega = (2.0 * PI * (float) m) / floatN;
  sine = sin(omega);
  cosine = cos(omega);
  coeff = 2.0 * cosine;

  printf("Sample rate = %f \n", SAMPLING_RATE);
  printf("N = %d, bin width = %d \n", N,binwidth);
  printf("Target frequency = %f,\n", target);
  printf("m = %d and coeff = %f\n", m, coeff);
  printf("m*binwidth = %d \n\n", m*binwidth);

  ResetGoertzel();
}

/* Call this routine for every sample. */

void ProcessSample(unsigned char sample)
{
  float Q0;
  Q0 = coeff * Q1 - Q2 + (float) sample;
  Q2 = Q1;
  Q1 = Q0;
}


/* Basic Goertzel */
/* Call this routine after every block to get the complex result. */
void GetRealImag(float *realPart, float *imagPart)
{
  *realPart = (Q1 - Q2 * cosine);
  *imagPart = (Q2 * sine);
}

/* Optimized Goertzel */
/* Call this after every block to get the magnitude squared. */
float GetMagnitudeSquared(void)
{
  float result;

  result = Q1 * Q1 + Q2 * Q2 - Q1 * Q2 * coeff;
  return result;
}

/*** End of Goertzel-specific code, the remainder is test code. */

/* Synthesize some test data at a given frequency. */
void Generate(float frequency)
{
  int	index;
  float	step;

  step = frequency * ((2.0 * PI) / SAMPLING_RATE);

  /* Generate the test data */
  for (index = 0; index < N; index++)
  {
    data[index] = (unsigned char) (100.0 * sin(index * step) + 100.0);
  }
}

/* Demo */
void GenerateAndTest(float frequency)
{
  int	index;

  float	magnitudeSquared;
  float	magnitude;
  float	real;
  float	imag;

  printf("Input freq = %7.1f   ", frequency);
  Generate(frequency);
  ResetGoertzel();

  /* Process the samples. */
  for (index = 0; index < N; index++)
  {
    ProcessSample(data[index]);
  }

  GetRealImag(&real, &imag);

  magnitudeSquared = real*real + imag*imag;
  magnitude = sqrt(magnitudeSquared);
  printf("R, I, Mag= %10.2f %10.2f %10.2f\n", real, imag, magnitude);

}

int main(void)
{
  float freq,target;
  int i,j;
  for (j=0; j<7; j++)
  {
  target=TT[j];
  InitGoertzel(target);


  /* Demo */
  for (i=0; i<7; i++)
  {
    freq=TT[i];
    GenerateAndTest(freq);
  }
 }
  return 0;
}

Of course it would be better to use a laptop for having more horsepower, but I would like to experiment and do it with arduino. Thanks for the code.

It really depends on your application. If you just want to look at the data, the arduino is a good way to acquire the data (Acting as a DAQ), but it is terrible for data processing. Your PC would be much better. However, if you need to process the data then do something with it, then you use the arduino.