How to detect frequency using Goertzel algorithm - java

I am really struggling to figure this out. Essentially I am trying to find what frequency is being played via the mic. To my understand, I need to bruteforce the Goertzel algorithm. So essentially I just try every frequency using the Goertzel algorithm until I find the correct one. However, I do not understand how I actually know when the Goertzel algorithm has found the correct algorithm. Could someone please help me.
MainActivity.java
import androidx.appcompat.app.AppCompatActivity;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private Button recordButton;
private TextView result;
private AudioRecord recording;
private static final int RECORDER_SAMPLERATE = 10000;
private static final int RECORDER_CHANNELS = AudioFormat.CHANNEL_IN_MONO;
private static final int RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;
int bufferSize = AudioRecord.getMinBufferSize(RECORDER_SAMPLERATE, RECORDER_CHANNELS, RECORDER_AUDIO_ENCODING);
double[] dbSample = new double[bufferSize];
short[] sample = new short[bufferSize];
private int frequency = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recordButton = findViewById(R.id.recordButton);
result = findViewById(R.id.resultTextView);
recordButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
recording = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, RECORDER_SAMPLERATE,
RECORDER_CHANNELS, RECORDER_AUDIO_ENCODING, bufferSize);
recording.startRecording();
int bufferReadResult = recording.read(sample, 0, bufferSize);
for (int j = 0; j < bufferSize && j < bufferReadResult; j++) {
dbSample[j] = (double) sample[j];
goertzel.processSample(dbSample[j]);
}
// Is this correct?
magnitude = Math.sqrt(goertzel.getMagnitudeSquared());
if(magnitude > maxMagnitude){
maxMagnitude = magnitude;
System.out.println("Freq is: " + Integer.toString(frequency));
}
goertzel.resetGoertzel();
frequency += 1;
}
});
}
}
Goertzel.java
public class Goertzel {
private float samplingRate;
private float targetFrequency;
private long n;
private double coeff, Q1, Q2;
private double sine, cosine;
public Goertzel(float samplingRate, float targetFrequency, long inN) {
this.samplingRate = samplingRate;
this.targetFrequency = targetFrequency;
n = inN;
}
public void resetGoertzel() {
Q1 = 0;
Q2 = 0;
}
public void initGoertzel() {
int k;
float floatN;
double omega;
floatN = (float) n;
k = (int) (0.5 + ((floatN * targetFrequency) / samplingRate));
omega = (2.0 * Math.PI * k) / floatN;
sine = Math.sin(omega);
cosine = Math.cos(omega);
coeff = 2.0 * cosine;
resetGoertzel();
}
public void processSample(double sample) {
double Q0;
Q0 = coeff * Q1 - Q2 + sample;
Q2 = Q1;
Q1 = Q0;
}
public double[] getRealImag(double[] parts) {
parts[0] = (Q1 - Q2 * cosine);
parts[1] = (Q2 * sine);
return parts;
}
public double getMagnitudeSquared() {
return (Q1 * Q1 + Q2 * Q2 - Q1 * Q2 * coeff);
}
}

You've asked about brute-forcing Goertzel specifically, so here is an annotated JUnit test that illustrates a reasonable approach:
public class TestGoertzel
{
private float[] freqs;
private Goertzel[] goertzels;
private static final int RECORDER_SAMPLERATE = 10000;
private static final int INPUT_SAMPLES = 256; //Roughly 26 ms of audio. This small array size was
//chosen b/c the number of frequency "bins" is typically related to the number of input samples,
//for engineering applications. If we only check 256 samples of audio, our "DFT" need only include
//128 output "bins". You can resize this to suit, but keep in mind that the processing time will
//increase exponentially.
#Test
public void test()
{
freqs = new float[INPUT_SAMPLES / 2]; //To prevent frequency-domain aliasing, we cannot test for 256 frequencies; only the first 128.
goertzels = new Goertzel[freqs.length];
for(int n = 0; n < freqs.length; ++n)
{
freqs[n] = n * RECORDER_SAMPLERATE / INPUT_SAMPLES; //Determine the frequency of a wave that can fit exactly n cycles in a block of audio INPUT_SAMPLES long.
//Create a Goertzel for each frequency "bin":
goertzels[n] = new Goertzel(RECORDER_SAMPLERATE, freqs[n], INPUT_SAMPLES);
goertzels[n].initGoertzel(); //Might as well create them all at the beginning, then "reset" them as necessary.
}
//This gives you an idea of the quality of output that can be had for a real signal from your
//microphone. The curve is not perfect, but shows the "smearing" characteristic of a wave
//whose frequency does not fall neatly into a single "bin":
testFrequency(1500.0f);
//Uncomment this to see a full unit test:
//for(float freq : freqs)
//{
// testFrequency(freq);
//}
}
private void testFrequency(float freqHz)
{
System.out.println(String.format("Testing input signal of frequency %5.1fHz", freqHz));
short[] audio = generateAudioWave(freqHz, (short) 1000);
short[] magnitudes = detectFrequencies(audio);
for(int i = 0; i < magnitudes.length; ++i)
{
System.out.println(String.format("%5.1fHz: %d", freqs[i], magnitudes[i]));
}
}
private short[] generateAudioWave(float freqHz, short peakAmp)
{
short[] ans = new short[INPUT_SAMPLES];
float w0 = (float) ((2 * Math.PI) * freqHz / RECORDER_SAMPLERATE);
for(int i = 0; i < ans.length; ++i)
{
ans[i] = (short) (Math.sin(w0 * i) * peakAmp);
}
return ans;
}
private short[] detectFrequencies(short[] audio)
{
short[] ans = new short[freqs.length];
for(int i = 0; i < goertzels.length; ++i)
{
Goertzel goertzel = goertzels[i];
goertzel.resetGoertzel();
for(short s : audio)
{
goertzel.processSample((double) s);
}
ans[i] = (short) (Math.sqrt(goertzel.getMagnitudeSquared()) * 2 / INPUT_SAMPLES);
}
return ans;
}
}
Basically, for every 256 samples of audio you read in, you take that array, and run it past an array of Goertzels which cover the frequencies you are interested in (each Goertzel only measures one frequency). That gives you an output spectrum. You may interpret that spectrum how you choose; I took your question to mean, "how do you find the frequency of the LOUDEST component of the input audio?". In that case, you would search the return value of detectFrequencies() for the largest magnitude. The corresponding member of freqs is your answer.
The fact is, you probably don't want Goertzel, you want an FFT, due to FFT's superior "computational efficiency". Because Goertzel is somewhat slower (to cover a spectrum as fully as an FFT), you may have trouble getting this answer to run in real time.
As an aside, I don't think a samplerate of 10000 is supported, on Android.

Related

Using an array to call tones using stdlib java library

Using the following library:
https://introcs.cs.princeton.edu/java/stdlib/
I am trying to Play a tone in java for .4 seconds from a file using Stdin.fromFile using an array. I can write the code and make it play using playTone (double, double) the code is as follows:
package csc402;
import stdlib.StdAudio;
import stdlib.StdIn;
public class PlaySong {
public static void playTone(double frequency, double duration) {
double[] values = StdIn.readAllDoubles();
final int sliceCount = (int) (StdAudio.SAMPLE_RATE * duration);
final double[] slices = new double[sliceCount+1];
for (int i = 0; i <= sliceCount; i++) {
slices[i] = Math.sin(2 * Math.PI * i * frequency / StdAudio.SAMPLE_RATE);
}
StdAudio.play(slices);
}
public static void main(String[] args) {
StdIn.fromFile("data/a2song.txt");
playTone (0,.4);
StdAudio.close();
System.exit(0);
}
}
My a2song.txt file is as follows
278.4375
278.4375
417.1849
417.1849
468.2742
468.2742
417.1849
My question is what am I missing ? The code runs fine but isn't playing the tone.
Here is an example from the stdlib doc to play one tone:
(you probably have seen it already as your code looks like it)
https://introcs.cs.princeton.edu/java/15inout/Tone.java.html
public class Tone {
public static void main(String[] args) {
double hz = Double.parseDouble(args[0]); // frequency in Hz
double duration = Double.parseDouble(args[1]); // duration in seconds
int n = (int) (StdAudio.SAMPLE_RATE * duration);
// build sine wave with desired frequency
double[] a = new double[n+1];
for (int i = 0; i <= n; i++) {
a[i] = Math.sin(2 * Math.PI * i * hz / StdAudio.SAMPLE_RATE);
}
// play using standard audio
StdAudio.play(a);
}
}
That plays one tone, and each value in your file is one tone, so you need to call a similar method for each value of your file.
That works for me: (I did not use the StdIn.fromFile as it does not compile, I hardcoded the values in the array instead)
public static void main(String[] args) {
//StdIn.fromFile("data/a2song.txt");
double[] values = new double[] {278.4375, 278.4375, 417.1849, 417.1849, 468.2742, 468.2742, 417.1849};
for(double value : values) {
playTone (value,.4);
}
StdAudio.close();
System.exit(0);
}
public static void playTone(double frequency, double duration) {
int n = (int) (StdAudio.SAMPLE_RATE * duration);
// build sine wave with desired frequency
double[] a = new double[n+1];
for (int i = 0; i <= n; i++) {
a[i] = Math.sin(2 * Math.PI * i * frequency / StdAudio.SAMPLE_RATE);
}
// play using standard audio
StdAudio.play(a);
}

use multi-threading to generate a matrix in java to utilize all CPU cores of a supercomputer

i am working on a problem which deals with large amount of data and computation also for all that purpose we have a supercomputer with processing power of 270 T FLOPS so our data is basically in matrix form so we decided to divide the generation of matrix into several parts by using threads so problem is there only that how can we implement such thing in our function we are just using arguments to divide task but run function of thread is not taking arguments
static int start=0,end;
int row=10000;
int col =10000,count=0,m=2203,n=401;
double p=Math.PI,t=Math.sqrt(3),pi=(p/(col+1));
double mul,a,b,c,d,e,f,xx,yy;
int[][] matrix = new int [row][col];
private void sin1()
{
// TODO Auto-generated method
for (int i =start; i < row; i++)
{
for (int j = 0; j <col; j++)
{
xx=((i+1)*pi);
yy=((j+1)*pi);
a=Math.cos(((2*m)-n)*((2*(xx))/3));
b=Math.sin(((2*(n*(yy)))/t));
c=Math.cos(((((2*n)-m)*(2*(xx)))/3));
d=Math.sin(((2*m)*(yy)/t));
e=Math.cos((((m+n)*(2*(xx)))/3));
f=Math.sin((((m-n)*(2*(yy)))/t));
mul=(a*b)-(c*d)+(e*f);
if(mul<0)
{
matrix[i][j]=0;
}
else
{
matrix[i][j]=1;
}
System.out.print(matrix[i][j]);
}
System.out.println();
}
}
we at first testing it for 10 million values
The code makes it clear to me that you lack any form of Java programming knowledge. This is a bad thing if you want to write code for a super computer. Java luckily has a good set of tools to solve all kinds of problems, but you need to know which tools to use for which situation.
In your case you can i.E. use parallel streams to spread the generation across cores like this:
static final int start = 0;
static int end;
static final int row = 10000;
static final int col = 10000, count = 0, m = 2203, n = 401;
static final double t = Math.sqrt(3);
static final double pi = (Math.PI / (col + 1));
final int[][] matrix = new int[row][col];
public int generateMatrixEntry(final int i, final int j) {
final double xx = ((i + 1) * pi);
final double yy = ((j + 1) * pi);
final double a = Math.cos(((2 * m) - n) * ((2 * (xx)) / 3));
final double b = Math.sin(((2 * (n * (yy))) / t));
final double c = Math.cos(((((2 * n) - m) * (2 * (xx))) / 3));
final double d = Math.sin(((2 * m) * (yy) / t));
final double e = Math.cos((((m + n) * (2 * (xx))) / 3));
final double f = Math.sin((((m - n) * (2 * (yy))) / t));
final double mul = (a * b) - (c * d) + (e * f);
return (mul < 0) ? 0 : 1;
}
private void sin1() {
IntStream.range(start, row).parallel().forEach((i) -> {
for (int j = 0; j < col; j++) {
matrix[i][j] = generateMatrixEntry(i, j);
}
});
}
This is however just one possible solution that might or might not fit your hardware. You absolutely need someone with deeper Java knowledge to select the right tools from the set for you if the above does not solve your issues.

How to apply test functions to genetic algorithm

I have written following code for population evolution (Genetic Algorithm Implementation):
Individual.java
import java.util.Random;
public class Individual {
public static int SIZE = 500;
private int[] genes = new int[SIZE];
private double fitnessValue = 0.0;
// Getters and Setters
public void setGene(int index,int gene){
this.genes[index] = gene;
}
public int getGene(int index){
return this.genes[index];
}
public void setFitnessValue(double fitness){
this.fitnessValue = fitness;
}
public double getFitnessValue(){
return this.fitnessValue;
}
//Function to generate a new individual with random set of genes
public void generateIndividual(){
Random rand = new Random();
for(int i=0;i<SIZE;i++){
this.setGene(i, rand.nextInt(2));
}
}
//Mutation Function
public void mutate(){
Random rand = new Random();
int index = rand.nextInt(SIZE);
this.setGene(index, 1-this.getGene(index)); // Flipping value of gene
}
//Function to set Fitness value of an individual
public int evaluate(){
int fitness = 0;
for(int i=0; i<SIZE; ++i) {
fitness += this.getGene(i);
}
this.setFitnessValue(fitness);
return fitness;
}
}
Population.java
import java.util.Random;
public class Population {
final static int ELITISM = 5;
final static int POP_SIZE = 200+ELITISM; //Population size + Elitism (1)
final static int MAX_ITER = 10000;
final static double MUTATION_RATE = 0.05;
final static double CROSSOVER_RATE = 0.7;
public static int generation = 2;
private static Random rand = new Random();
private double totalFitness;
private Individual[] pop;
//Constructor
public Population(){
pop = new Individual[POP_SIZE];
//Initialising population
for(int i=0;i<POP_SIZE;i++){
pop[i] = new Individual();
pop[i].generateIndividual();
}
//Evaluating current population
this.evaluate();
}
//Storing new generation in population
public void setPopulation(Individual[] newPop) {
System.arraycopy(newPop, 0, this.pop, 0, POP_SIZE);
}
//Method to find total fitness of population
public double evaluate(){
this.totalFitness = 0.0;
for (int i = 0; i < POP_SIZE; i++) {
this.totalFitness += pop[i].evaluate();
}
return this.totalFitness;
}
//Getters
public Individual getIndividual(int index) {
return pop[index];
}
//Function to find fittest individual for elitism
public Individual getFittest() {
Individual fittest = pop[0];
for (int i = 0; i < POP_SIZE; i++) {
if (fittest.getFitnessValue() <= getIndividual(i).getFitnessValue()) {
fittest = getIndividual(i);
}
}
return fittest;
}
//CROSSOVER Function : Takes 2 individuals and returns 2 new individuals
public static Individual[] crossover(Individual indiv1,Individual indiv2) {
Individual[] newIndiv = new Individual[2];
newIndiv[0] = new Individual();
newIndiv[1] = new Individual();
int randPoint = rand.nextInt(Individual.SIZE);
int i;
for (i=0; i<randPoint; ++i) {
newIndiv[0].setGene(i, indiv1.getGene(i));
newIndiv[1].setGene(i, indiv2.getGene(i));
}
for (; i<Individual.SIZE; ++i) {
newIndiv[0].setGene(i, indiv2.getGene(i));
newIndiv[1].setGene(i, indiv1.getGene(i));
}
return newIndiv;
}
//Roulette Wheel Selection Function
public Individual rouletteWheelSelection() {
double randNum = rand.nextDouble() * this.totalFitness;
int idx;
for (idx=0; idx<POP_SIZE && randNum>0; idx++) {
randNum -= pop[idx].getFitnessValue();
}
return pop[idx-1];
}
//Main method
public static void main(String[] args) {
Population pop = new Population();
Individual[] newPop = new Individual[POP_SIZE];
Individual[] indiv = new Individual[2];
//Current Population Stats
System.out.print("Generation #1");
System.out.println("Total Fitness = "+pop.totalFitness);
System.out.println("Best Fitness = "+pop.getFittest().getFitnessValue());
int count;
for(int iter=0;iter<MAX_ITER;iter++){
count =0;
//Elitism
newPop[count] = pop.getFittest();
count++;
//Creating new population
while(count < POP_SIZE){
//Selecting parents
indiv[0] = pop.rouletteWheelSelection();
indiv[1] = pop.rouletteWheelSelection();
// Crossover
if (rand.nextDouble() < CROSSOVER_RATE ) {
indiv = crossover(indiv[0], indiv[1]);
}
// Mutation
if ( rand.nextDouble() < MUTATION_RATE ) {
indiv[0].mutate();
}
if ( rand.nextDouble() < MUTATION_RATE ) {
indiv[1].mutate();
}
// add to new population
newPop[count] = indiv[0];
newPop[count+1] = indiv[1];
count += 2;
}
// Saving new population in pop
pop.setPopulation(newPop);
//Evaluating new population
pop.evaluate();
System.out.println("Generation #"+ generation++);
System.out.print("Total Fitness = " + pop.totalFitness);
System.out.println(" ; Best Fitness = " +pop.getFittest().getFitnessValue());
}
Individual bestIndiv = pop.getFittest();
}
}
I have been asked to test my algorithm using following functions:
https://en.wikipedia.org/wiki/Test_functions_for_optimization
Test functions for single objective optimisation
Can anyone explain how it is to be done? Explanation for any one function from the list would be helpful.
What the genes should represent
I'll assume the implementation of your genetic algorithm is correct, as that is beyond the scope of this question.
Right now your fitness function is defined to be the sum of all of the genes:
double fitness = 0;
for(int i=0; i<SIZE; ++i) {
fitness += this.getGene(i);
}
this.setFitnessValue(fitness);
This is a strange thing to do: let's think about an Individual witch will have a high fitness. I hope you see that there is no real optimum, Individuals will simply tend to increase each of their genes because that will archive a higher fitness.
A second problem is that the genes should represent something: what do the doubles in the gene array actually mean? Why do we care? A possible example would be to have them represent the behavior of Individuals in a simulation. That's of course a whole other topic, so we need them to mean something simple so it's easy to calculate their fitness.
Let's let the array have size 1 and let's say x = genes[0]. The Individuals will only have one gene: the x-coordinate. Now we need to define our fitness function, we'll pick Easom with y = 0. This is how I would define the new fitness function:
double fitness = -cos(x)*cos(0)*exp(-(pow(x-PI,2)+pow(0-PI,2)));
With of course the appropriate imports at the top of the class:
import static java.lang.Math.*;
If your program does indeed optimize for fitness it should converge to x = PI. I quickly wrote my own (admittedly very ugly) implementation and it does indeed converge correctly.
One more thing: the genes should be a double[] instead of an int[], because incrementally optimizing a function doesn't really work when x can only be an int.
Why a gene array?
I think your assignment wants you to use an double array as the genes so you end up with a program that can optimize any function with any amount of variables. In programming it is always a good idea to write code that can be reused for multiple different things.
Feel free to ask any questions!
I tried to explain everything as clear as possible, but if you don't understand something feel free to ask!

Fast sine and cosine function in java

I know about the Math.sin() and Math.cos() functions, but I'm wondering if there's a way I can create (or use an already-existing) a faster function, given that I don't care about pinpoint accuracy. I'm looking to execute a basic sin or cos calculation, and have it perform essentially as fast as possible. Would simply iterating the sigma a few times be any faster than Math.sin()?
Since you don't care much about accuracy store it in a table that is precomputed or only computed once, this is what I do when I want to avoid calls to Math which can be expensive when done alot.
Roughly
public class CosSineTable {
double[] cos = new double[361];
double[] sin = new double[361];
private static CosSineTable table = new CosSineTable();
private CosSineTable() {
for (int i = 0; i <= 360; i++) {
cos[i] = Math.cos(Math.toRadians(i));
sin[i] = Math.sin(Math.toRadians(i));
}
}
public double getSine(int angle) {
int angleCircle = angle % 360;
return sin[angleCircle];
}
public double getCos(int angle) {
int angleCircle = angle % 360;
return cos[angleCircle];
}
public static CosSineTable getTable() {
return table;
}
}
I leave the optimization of the loop and methods to you.
A pre-calculated table's the way to go. Here's an implementation:
static final int precision = 100; // gradations per degree, adjust to suit
static final int modulus = 360*precision;
static final float[] sin = new float[modulus]; // lookup table
static {
// a static initializer fills the table
// in this implementation, units are in degrees
for (int i = 0; i<sin.length; i++) {
sin[i]=(float)Math.sin((i*Math.PI)/(precision*180));
}
}
// Private function for table lookup
private static float sinLookup(int a) {
return a>=0 ? sin[a%(modulus)] : -sin[-a%(modulus)];
}
// These are your working functions:
public static float sin(float a) {
return sinLookup((int)(a * precision + 0.5f));
}
public static float cos(float a) {
return sinLookup((int)((a+90f) * precision + 0.5f));
}
On my laptop, these were about 6x faster than Math.sin.
I only used one table -- the cost of shifting a cosine into a sine wasn't really discernible.
I used floats, assuming that's what you'll likely use in your calculations, given your preference for performance over precision. It doesn't make much difference here, since the bottleneck is really just the array lookup.
Here are my benchmarks:
public static void main(String[] args) {
int reps = 1<<23;
int sets = 4;
Q.pl(" Trial sinTab cosTab sinLib");
for(int i = 0; i<sets; i++) {
Q.pf("%7d\t%7.2f\t%7.2f\t%7.2f\n", i, testSinTab(reps), testCosTab(reps), testSinLib(reps));
}
}
private static float[] sample(int n) {
Random rand = new Random();
float[] values = new float[n];
for (int i=0; i<n; i++) {
values[i] = 400*(rand.nextFloat()*2-1);
}
return values;
}
private static float testSinTab(int n) {
float[] sample = sample(n);
long time = -System.nanoTime();
for (int i=0; i<n; i++) {
sample[i] = sin(sample[i]);
}
time += System.nanoTime();
return (time/1e6f);
}
private static float testCosTab(int n) {
float[] sample = sample(n);
long time = -System.nanoTime();
for (int i=0; i<n; i++) {
sample[i] = cos(sample[i]);
}
time += System.nanoTime();
return time/1e6f;
}
private static float testSinLib(int n) {
float[] sample = sample(n);
long time = -System.nanoTime();
for (int i=0; i<n; i++) {
sample[i] = (float) Math.sin(sample[i]);
}
time += System.nanoTime();
return time/1e6f;
}
output:
Trial sinTab cosTab sinLib
0 102.51 111.19 596.57
1 93.72 92.20 578.22
2 100.06 107.20 600.68
3 103.65 102.67 629.86
You can try
http://sourceforge.net/projects/jafama/
It uses look-up tables, so it might actually be slower
than Math, especially if the tables are often evicted from CPU cache,
but for thousands of successive calls it can be quite faster.
It also seems slower during class load (maybe the JIT doesn't kicks in then yet),
so you might want to avoid it in that particular use-case.
I know this question is old, but I think it's the fastest java implementation sintable with precision to 65536 elements.
public class MathHelper {
private static double[] a = new double[65536];
public static final double sin(float f) {
return a[(int) (f * 10430.378F) & '\uffff'];
}
public static final double cos(float f) {
return a[(int) (f * 10430.378F + 16384.0F) & '\uffff'];
}
static {
for (int i = 0; i < 65536; ++i) {
a[i] = Math.sin((double) i * 3.141592653589793D * 2.0D / 65536.0D);
}
}
}
Source: https://github.com/Bukkit/mc-dev/blob/master/net/minecraft/server/MathHelper.java

Extract specific frequency from Modulated signal using FFT

I've modulated a carrier frequency signal with my data using FSK like this:
double SAMPLING_TIME = 1.0 / 441000 // 44khz
int SAMPLES_PER_BIT = 136;
int ENCODING_SAMPLES_PER_BIT = SAMPLES_PER_BIT / 2;
int duration = ENCODING_SAMPLES_PER_BIT * SAMPLING_TIME;
public double[] encode(int[] bits) {
for (int i = 0; i < bits.length; i++) {
int freq = FREQUENCY_LOW;
if (bits[i] > 1)
freq = FREQUENCY_HIGH;
bitArray = generateTone(freq, duration);
message = bitArray;
}
return message;
}
private double[] generateTone(int frequency, double duration) {
int samplingRate = 1/SAMPLING_TIME; // Hz
int numberOfSamples = (int) (duration * samplingRate);
samplingTime = 2 * SAMPLING_TIME;
double[] tone = new double[numberOfSamples];
for (int i = 0; i < numberOfSamples; i++) {
double y = Math.sin(2 * Math.PI * frequency * i * SAMPLING_TIME);
tone[i] = y * CARRIER_AMPLITUDE;
}
return tone;
}
Clearly, I'm sending FREQUENCY_LOW for ZERO and FREQUENCY_HIGH for 1.
Now how do I demodulate it using FFT? I'm interested in sampling magnitudes (presence and absence) of FREQUENCY_LOW, FREQUENCY_HIGH throughout the time.
I only know basics of FFT, I was starting to write this but it doesn't make sense:
private void decode(byte[] tone, int length) {
float[] input = new float[FFT_SIZE*2]; // not sure what size? shouldn't this be buffer?
for(int i=0;i<length;i++){
input[i]=tone[i];
}
FloatFFT_1D fft = new FloatFFT_1D(FFT_SIZE);
fft.realForward(input);
}
Can someone help with code?
You can use overlapping sliding windows for your FFTs, with the window and FFT the same length as that of your data bits. Then look for magnitude peaks for your 1's and 0's in the appropriate FFT result bins across these windows. You will also need some synchronization logic for runs of 1's and 0's.
Another DSP techniques that may be less compute intensive is to do quadrature demodulation for your two frequencies and low-pass filter the result before feeding it to the synchronization logic and bit detector. Yet another possibility is two sliding Goertzel filters.

Categories

Resources