/** * The UltrasoundDetector class can be used to help analyze an * ultrasonic signal. Currently it uses the Goertzel Algorithm to * perform the signal analysis, but additional methods could easily * be added in future versions to uses alternate analysis alogrithms. * * @author Chris Palistrant, Tony Offer * @version 0.0, May 2004 */ public class UltrasoundDetector{ float SAMPLING_RATE = 44100.0F; float TARGET_FREQUENCY = 21000.0F; int N = 420; Goertzel g; static double[] signal; /** * Default Constructor. By default the sampling rate is set to * 44.1kHz, and the frequency to detect is 21kHz. Additionally the * block size used in the analysis is set appropriately. * */ public UltrasoundDetector(){ this(44100.0F, 21000.0F, 420); } /** * Constructor. The sample rate, frequency to search for and the block * size can be set. The block size should be large; in order to allow * fine granularity. It should also be set so that the frequency will be * set around the center of the bin. This can be accomplished by finding * n so that n*targetFreq/sampleRate = I and the value of I i equal to * an integer. * * @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 */ public UltrasoundDetector(float sampleRate, float targetFreq, int n){ g = new Goertzel(sampleRate, targetFreq, n); SAMPLING_RATE = sampleRate; TARGET_FREQUENCY = targetFreq; N = n; /* //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 = 10; 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); } */ } /** * This method should be called to initialize signal porcessing method. * */ public void signalAnalysisInit(){ g.initGoertzel(); } /** * This should not be called until after signalAnalysisInit * has been called. The method is used to load all of the * samples that could potentially be analyzed. * * @param samples is an array of doubles * @return returns true if sample.length != 0, false otherwise */ public boolean loadSignal(double[] samples){ if(samples.length == 0) return false; 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 method is called once the signal is loaded and ready to * be analyzed. This method is used as a debouncing method to * call the dsp algorithm on the loaded samples and additionally * ensure that the signal is prevalent enough for a sufficient period * of time. * * @return boolean indicating true when the targetFrequency is found * and false otherwise. */ public boolean testSignal(){ boolean freq_present = false; int debounceValue = 20; 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 > 100000){ count++; if(count >= debounceValue) return true; } else count = 0; } if(count >= debounceValue) return true; else return false; } /** * Currently does nothing. */ public static void main(String[] args){ } }