package rtty; import java.util.Iterator; import java.util.LinkedList; import java.util.Queue; public class ConfidenceCalculator { int _historyLen; Queue<double[]> freqHistory = new LinkedList<double[]>(); public enum State {SIG_LOST,SIG_JUST_FOUND,SIG_TRACKING,SIG_DROPPED}; State state = State.SIG_LOST; int _sampleRate = 8000; int confidence=0; //{0..100} int samplesSinceFullSearch = 0; int samplesSinceStateChange = 0; double _lastPowerMax = 0; double _lastPowerAverage = 0; double[] lastDecent = {-1,-1}; double[] currentBest = {-1,-1}; public ConfidenceCalculator (int samplerate) { _historyLen = 3; _sampleRate = samplerate; } public void samplesElapsed(int samples) { samplesSinceFullSearch += samples; samplesSinceStateChange += samples; } public boolean putFrequencies ( double f1, double f2) { boolean out = false; State entryState = state; samplesSinceFullSearch = 0; switch(state) { case SIG_LOST : if (f1 > 0 && f2 > 0){ state = State.SIG_JUST_FOUND; currentBest[0] = f1; currentBest[1] = f2; freqHistory.clear(); freqHistory.offer(new double[] {f1,f2}); out = true; } break; case SIG_JUST_FOUND : if (samplesSinceStateChange > 10 *_sampleRate){ state = State.SIG_LOST; } if(!freqsValid(f1,f2)) break; freqHistory.offer(new double[] {f1,f2}); if (freqHistory.size() > _historyLen) freqHistory.poll(); double[] f = selectFromHistory(); if (f == null) break; currentBest = f; lastDecent = currentBest; state = State.SIG_TRACKING; freqHistory.clear(); out = true; break; case SIG_TRACKING : if(!freqsValid(f1,f2)) break; if (freqSimilar(currentBest,new double[] {f1,f2})) { currentBest[0] = f1; currentBest[1] = f2; lastDecent = currentBest; confidence = confidence + (100-confidence)/2 ; } else { confidence = confidence/2 ; freqHistory.offer(new double[] {f1,f2}); if (freqHistory.size() > _historyLen) freqHistory.poll(); if (confidence < 20) { double[] ff = selectFromHistory(); if (ff == null) state = State.SIG_DROPPED; else { state = State.SIG_JUST_FOUND; currentBest = ff; } } } break; case SIG_DROPPED : if(freqsValid(f1,f2)){ if (freqSimilar(lastDecent,new double[] {f1,f2})) { state = State.SIG_TRACKING; currentBest[0] = f1; currentBest[1] = f2; lastDecent = currentBest; confidence = 50; } else { state = State.SIG_JUST_FOUND; currentBest[0] = f1; currentBest[1] = f2; out = true; } } else { if (samplesSinceStateChange > 10 *_sampleRate){ state = State.SIG_LOST; } } break; default : System.out.println("WHY AM I HERE!?!?!?!?!?!?!?!?! :o"); break; } if (entryState != state){ samplesSinceStateChange = 0; System.out.println("STATE : " + state); } return out; } private double[] selectFromHistory(){ if (freqHistory.size() < 2) return null; double[] lows = new double[freqHistory.size()]; double[] highs = new double[freqHistory.size()]; { int i =0; Iterator<double[]> iterator = freqHistory.iterator(); while(iterator.hasNext()){ double[] v = iterator.next(); lows[i] = v[0]; highs[i] = v[1]; i++; } } for (int i = 0; i < freqHistory.size()-1; i++){ for (int j = i+1; j < freqHistory.size(); j++){ if (freqSimilar(new double[] {lows[i],highs[i]},new double[] {lows[j],highs[j]})) return new double[] {(lows[i]+lows[j])/2,(highs[i]+highs[j])/2}; } } return null; } /* private boolean freqsValid(double[] in) { if (in[1] <= 0 || in[0] <= 0) return false; else return true; } */ private boolean freqsValid(double f1, double f2) { if (f1 <= 0 || f2 <= 0) return false; else return true; } private boolean freqSimilar(double[] pair1, double[] pair2) { //similar if shift < 200Hz difference // && each frequency 500 to a max of 800 if (pair2[1] <= 0 || pair2[0] <= 0 || pair1[0] <= 0 || pair1[1] <= 0) return false; double shiftdiff = Math.abs(Math.abs(pair1[1]-pair1[0]) - Math.abs(pair2[1]-pair2[0])); double f1diff = Math.abs(pair1[0] - pair2[0]); double f2diff = Math.abs(pair1[1] - pair2[1]); if (shiftdiff > 200/(double)_sampleRate) return false; if (f1diff > 400/(double)_sampleRate) return false; if (f2diff > 400/(double)_sampleRate) return false; if (f1diff+f2diff > 700/(double)_sampleRate) return false; return true; } public double getFrequencies(int i) { return currentBest[i]; } public void gotDecode() { confidence = 100 ; } public void putPowerLevels(double lastMax, double lastAverage) { if (lastAverage < _lastPowerAverage/100 && state == State.SIG_TRACKING){ state = State.SIG_DROPPED; System.out.println("STATE : " + state); } _lastPowerMax = lastMax; _lastPowerAverage = lastAverage; } public void AFCUpdate(double f1, double f2) { currentBest[0] = f1; currentBest[1] = f2; if (state == State.SIG_TRACKING){ lastDecent[0] = f1; lastDecent[1] = f2; } } public boolean fullSearchDue() { switch(state) { case SIG_LOST : if (samplesSinceFullSearch > _sampleRate / 3) // 1/3 sec return true; else return false; case SIG_JUST_FOUND : if (samplesSinceFullSearch > 1 * _sampleRate) //1sec return true; else return false; case SIG_TRACKING : if (samplesSinceFullSearch > 5 * _sampleRate) //5sec return true; else return false; case SIG_DROPPED : if (samplesSinceFullSearch > _sampleRate / 3) // 1/3 sec return true; else return false; default : System.out.println("WHY AM I HERE!?!?!?!?!?!?!?!?! :o"); return false; } } public State getState(){ return state; } //getters/setters public int getConfidence(){ return confidence; } }