/** * The UltrasoundDetector class can be used to help analyze an ultrasound signal. * This class is based on a C program implemented by Kevin Banks of * Embedded Systems Programming. * * @author Chris Palistrant, Tony Offer * @version 0.0, May 2004 */ public class UltrasoundDetector{ public static final int THRESHOLD = 3500; protected float SAMPLING_RATE = 44100.0F; protected float TARGET_FREQUENCY = 21000.0F; protected int N = 420; protected boolean DEBUG = false; protected Goertzel g; //static double[] signal; /** * Default Constructor */ public UltrasoundDetector(){ this(44100.0F, 21000.0F, 420, false); } /** * Constructor. * @param sampleRate is the sampling rate of the signal to be analyzed * @param targetFreq is the frequency that Goertzel will look for. * @param n is the block size to use with Goertzel * @param debug indicates whether or not to turn debugging info on. */ public UltrasoundDetector(float sampleRate, float targetFreq, int n, boolean debug){ g = new Goertzel(sampleRate, targetFreq, n, debug); SAMPLING_RATE = sampleRate; TARGET_FREQUENCY = targetFreq; N = n; DEBUG = debug; /* //Not tested; but intended to eliminate n from param list by computing n based on N float temp_n; float a = targetFreq/sampleRate; for(int n = 200; n <= 600; n++){ temp_n = a*n; //if temp_n is accurate to 0.0XXX of an int, then its okay if( ( (int)(temp_n*10) - ((int)temp_n)*10 ) == 0 ) N = temp_n; } if(n==0){ System.out.println("Block size error"); System.exit(0); } */ } /** * Method to initialize the Goertzel algorithm. If this method is * not called, the Goertzel algorithm will be initialized using the * default values defined in Goertzel.java. */ public void init() { g.initGoertzel(); } /** * Provide means to access the value of N that is used by the * Goertzel algorithm to detect the presence of a specified * frequency. N should be the number of samples that are given to * this class to process since the Goertzel algorithm returns a * result every N samples. * * @return The value of N used by the Goertzel algorithm. */ public int getN() { return N; } /** * This should not be called until after signalAnalysisInit * has been called. * * @param samples is an array of doubles * @return returns true if loaded, false otherwise */ /* boolean loadSignal(double[] samples){ signal = new double[samples.length]; if(g.DEBUG){ System.out.println("USD:loadSignal:length of N " + N); System.out.println("USD:loadSignal:length of sample.length " + samples.length); } for(int i = 0; i < samples.length; i++) signal[i] = samples[i]; return true; } */ /** * This is the main method of the UltrasoundDetector class and it is * used for testing N samples for the presence of the frequency * specified by TARGET_FREQUENCY. An array of size N and type * double is passed into this method and tested to see whether or * not the desired frequency is present in the N samples. * * @param block An array of type double containing the N samples. * @return Boolean indicating whether or not the frequency * was present. */ public boolean analyze(double [] block) { double mag; // Check to make sure that the size of 'block' is exactly N. // The UltrasoundDetector class is designed to process exactly N // samples at a time. if (block.length != N) { System.out.println("UltrasoundDetector: Block size is not " + "equal to N where N is " + N); System.exit(1); } // Process each of the N samples using the Goertzel object. for (int i = 0; i < N; i++) g.processSample(block[i]); // N samples have been processed. The Goertzel algorithm is now // ready to get the magnitude, which will enable a decision as // to the presence of the desired frequency. The method called // here employs the optimized Goertzel algorithm without phase // information. mag = java.lang.Math.sqrt(g.getMagnitudeSquared()); /* if (DEBUG) System.out.println("Magnitude: " + mag + " (" + Thread.currentThread().getName() + ")");*/ if(DEBUG) System.out.println("Magnitude: " + mag + " (" + Thread.currentThread().toString() + ")"); // Finished processing N samples. Reset the Goertzel algorithm. g.resetGoertzel(); // If the calculated magnitude is high enough, return 'true' // indicating the desired frequency was present in this block of // N samples. if (mag > THRESHOLD) return true; else return false; } /** * This method is called once the signal is loaded and ready to * be analyzed. * * * @return boolean indicating true when the targetFrequency is found * and false otherwise. */ /* boolean testSignal(){ boolean freq_present = false; int debounceValue = 5; double[] parts = new double[2]; double real, img, magnitudeSquared, mag; // Process the samples int iters = signal.length/N; if(g.DEBUG){ System.out.println("The val of N is " + N); System.out.println("The val of iters is " + iters); } int index = 0; int count = 0; for(int j = 1; j <= iters; j++){ for(; index < N*j; index++){ g.processSample(signal[index]); } parts = g.getRealImag(parts); real = parts[0]; img = parts[1]; magnitudeSquared = real*real + img*img; mag = java.lang.Math.sqrt(magnitudeSquared); g.resetGoertzel(); if(g.DEBUG){ System.out.println("The mag is " + mag + " and the mag_squared " + magnitudeSquared + " count: " + count); } if(mag > THRESHOLD){ count++; if(count >= debounceValue) return true; } else count = 0; } if(count >= debounceValue) return true; else return false; } */ }