public static void Main(string[] args) { const int sampleRate = 48000; const float tone = 69.3f; var decoder = CTCSSDecoder.Create(tone, sampleRate); using (var udpClient = new UdpClient(7355)) { var buffer = new CircularBuffer.CircularBuffer <float>(decoder.FrameSize, new float[0]); var ctcssPrev = false; int debounce = 0; int debounceMax = 3; var slicer = new Slicer <float>(48000 / 50); var sw = System.Diagnostics.Stopwatch.StartNew(); while (true) { IPEndPoint recievedFrom = new IPEndPoint(IPAddress.Any, 0); var data = udpClient.Receive(ref recievedFrom); //Console.WriteLine(data.Length); foreach (var slice in slicer.GetSlices(ToFloats(data))) { foreach (var sample in slice) { buffer.PushBack(sample); } if (!buffer.IsFull) { continue; } var ctcss = decoder.HasCTCSS(buffer.ToArray(), out var level, out var ratio); if (ctcss) { debounce = Math.Min(debounce + 1, debounceMax); } else { debounce = Math.Max(debounce - 1, 0); } Console.Clear(); Console.WriteLine($"{debounce >= debounceMax} {level} {ratio}"); } } } //int positive = 0; //int negative = 0; //var noiseThreshold = 0f; //for (int i = 0; i < 100; i++) //{ // var noise = i / 100f; // var signal = SignalGenerator.Sinus(sampleRate, decoder.FrameSize, 67) // .Select(f => f * 0.15f) // .AddNoise(noise).ToArray(); // if (decoder.HasCTCSS(signal)) // { // positive++; // if(negative == 0) // noiseThreshold = noise; // } // else // { // negative++; // } // Console.Clear(); // Console.WriteLine($"Positive {positive}"); // Console.WriteLine($"Negative {negative}"); //} //Console.WriteLine(noiseThreshold); //float frequencyOfInterest = 67; //float binWidthInHz = 4f; //float numberOfSamplesForRequiredBinWidth = sampleRate / binWidthInHz; //float samplesRequiredForOnePEriod = sampleRate / frequencyOfInterest; //int framesSize = (int)Math.Round(numberOfSamplesForRequiredBinWidth + (numberOfSamplesForRequiredBinWidth % samplesRequiredForOnePEriod)); //var signal = SignalGenerator.Sinus(sampleRate, framesSize, 69.3f).Select(f => f * 0.15f)/*.AddNoise(0.9f)*/.ToArray(); //var frequenciesOfInterest = new[] { frequencyOfInterest - binWidthInHz, frequencyOfInterest, frequencyOfInterest + binWidthInHz }; //var goertzel = Goertzel.Create(signal.Length, sampleRate, FFTWindowBuilder.Hann(signal.Length), frequenciesOfInterest); //var responses = goertzel.Evaluate(signal).ToArray(); //foreach (var response in responses) //{ // Console.WriteLine(response); //} //Console.WriteLine("============================="); //var bla = (responses[0] + responses[2]) / 2f; //bla = responses[1] / bla; //Console.WriteLine(bla); //var file = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "/test.csv"; //if (File.Exists(file)) // File.Delete(file); //File.WriteAllLines(file, CompareFilterWindowsPhaseResponse()); //const float frequency = 67; //var signal = SignalGenerator.GenerateNoise((int)(((1f / frequency) * 10f) * 48000f) + 1).ToArray(); //var max = signal.Max(); //var min = signal.Min(); //var amp1f = GoertzelMag(signal, 48000, frequency); //var amp2f = GoertzelMag(signal, 48000, frequency * 2); //var amp4f = GoertzelMag(signal, 48000, frequency * 4); //Console.WriteLine(amp1f); //Console.WriteLine(amp2f); //Console.WriteLine(amp4f); }
public HighPrecisionTimer(int interval) { log.Info("Starting HighPrecisionTimer with" + interval.ToString() + " ms interval"); if (interval < 1) { throw new ArgumentOutOfRangeException(); } System.Diagnostics.Trace.Assert(interval >= 10, "Not reliable/tested, may use too much CPU"); cancelSource = new CancellationTokenSource(); // Used to report timing accuracy for 1 sec, running total tickTiming = new CircularBuffer.CircularBuffer <int>(1000 / interval, true); var watch = System.Diagnostics.Stopwatch.StartNew(); long durationMs = 0; long totalTicks = 0; long nextStop = interval; long lastReport = 0; var task = new Task(() => { while (!this.cancelSource.IsCancellationRequested) { long msLeft = nextStop - watch.ElapsedMilliseconds; if (msLeft <= 0) { durationMs = watch.ElapsedMilliseconds; totalTicks = durationMs / interval; tickTiming.Put((int)(durationMs - nextStop)); if (durationMs - lastReport >= 1000) { // Report log.Debug(string.Concat("Last second - avg: {0:F1} best: {1} worst: {2}", tickTiming.Average(), tickTiming.Min(), tickTiming.Max())); lastReport = durationMs; } var handler = Tick; if (handler != null) { handler(this, new TickEventArgs(TimeSpan.FromMilliseconds(durationMs), totalTicks)); } // Calculate when the next stop is. If we're too slow on the trigger then we'll skip ticks nextStop = interval * (watch.ElapsedMilliseconds / interval + 1); } else if (msLeft < 16) { System.Threading.SpinWait.SpinUntil(() => watch.ElapsedMilliseconds >= nextStop); continue; } System.Threading.Thread.Sleep(1); } }, cancelSource.Token, TaskCreationOptions.LongRunning); task.Start(); }
public HighPrecisionTimer(int intervalMs, bool startRunning = true) { log.Info("Starting HighPrecisionTimer with {0} ms interval", intervalMs); if (intervalMs < 1) throw new ArgumentOutOfRangeException(); System.Diagnostics.Trace.Assert(intervalMs >= 10, "Not reliable/tested, may use too much CPU"); this.IntervalMs = intervalMs; this.cancelSource = new CancellationTokenSource(); this.taskComplete = new ManualResetEvent(false); #if PROFILE // Used to report timing accuracy for 1 sec, running total tickTiming = new CircularBuffer.CircularBuffer<int>(1000 / intervalMs, true); execTiming = new CircularBuffer.CircularBuffer<long>(1000 / intervalMs, true); #endif var watch = System.Diagnostics.Stopwatch.StartNew(); long durationMs = 0; long totalTicks = 0; long nextStop = intervalMs; #if PROFILE long lastReport = 0; #endif this.task = new Task(() => { var eventArgs = new TickEventArgs(); while (!this.cancelSource.IsCancellationRequested) { long msLeft = nextStop - watch.ElapsedMilliseconds; if (msLeft <= 0) { durationMs = watch.ElapsedMilliseconds; totalTicks = durationMs / intervalMs; #if PROFILE var execWatch = System.Diagnostics.Stopwatch.StartNew(); #endif var handler = Tick; if (handler != null) { eventArgs.Duration = TimeSpan.FromMilliseconds(durationMs); eventArgs.TotalTicks = totalTicks; handler(this, eventArgs); if (eventArgs.Cancel) break; } #if PROFILE execWatch.Stop(); execTiming.Put(execWatch.ElapsedTicks); tickTiming.Put((int)(durationMs - nextStop)); if (durationMs - lastReport >= 1000) { // Report log.Debug("HighPTimer avg: {0:F1} best: {1} worst: {2} MaxExec: {3:N1}ms", tickTiming.Average(), tickTiming.Min(), tickTiming.Max(), TimeSpan.FromTicks(execTiming.Max()).TotalMilliseconds); lastReport = durationMs; } #endif // Calculate when the next stop is. If we're too slow on the trigger then we'll skip ticks nextStop = intervalMs * (watch.ElapsedMilliseconds / intervalMs + 1); continue; } else if (msLeft < 16) { System.Threading.SpinWait.SpinUntil(() => watch.ElapsedMilliseconds >= nextStop); continue; } System.Threading.Thread.Sleep(1); } this.taskComplete.Set(); }, cancelSource.Token, TaskCreationOptions.LongRunning); if (startRunning) this.task.Start(); }
public HighPrecisionTimer2(int intervalMs, bool startRunning = true) { this.log = Log.Logger; this.log.Information("Starting HighPrecisionTimer2 with {0} ms interval", intervalMs); this.outputValue = new Subject <long>(); if (intervalMs < 1) { throw new ArgumentOutOfRangeException(); } System.Diagnostics.Trace.Assert(intervalMs >= 10, "Not reliable/tested, may use too much CPU"); this.IntervalMs = intervalMs; this.cancelSource = new CancellationTokenSource(); this.taskComplete = new ManualResetEvent(false); #if PROFILE // Used to report timing accuracy for 1 sec, running total tickTiming = new CircularBuffer.CircularBuffer <int>(1000 / intervalMs, true); execTiming = new CircularBuffer.CircularBuffer <long>(1000 / intervalMs, true); #endif watch = System.Diagnostics.Stopwatch.StartNew(); long durationMs = 0; long nextStop = intervalMs; #if PROFILE long lastReport = 0; #endif this.task = new Task(() => { while (!this.cancelSource.IsCancellationRequested) { long msLeft = nextStop - watch.ElapsedMilliseconds; if (msLeft <= 0) { durationMs = watch.ElapsedMilliseconds; #if PROFILE var execWatch = System.Diagnostics.Stopwatch.StartNew(); #endif this.outputValue.OnNext(durationMs); #if PROFILE execWatch.Stop(); execTiming.Put(execWatch.ElapsedTicks); tickTiming.Put((int)(durationMs - nextStop)); if (durationMs - lastReport >= 1000) { // Report log.Debug("HighPTimer avg: {0:F1} best: {1} worst: {2} MaxExec: {3:N1}ms", tickTiming.Average(), tickTiming.Min(), tickTiming.Max(), TimeSpan.FromTicks(execTiming.Max()).TotalMilliseconds); lastReport = durationMs; } #endif // Calculate when the next stop is. If we're too slow on the trigger then we'll skip ticks nextStop = intervalMs * (watch.ElapsedMilliseconds / intervalMs + 1); continue; } else if (msLeft < 16) { System.Threading.SpinWait.SpinUntil(() => watch.ElapsedMilliseconds >= nextStop); continue; } System.Threading.Thread.Sleep(1); } this.taskComplete.Set(); }, cancelSource.Token, TaskCreationOptions.LongRunning); if (startRunning) { this.task.Start(); } }