Exemplo n.º 1
0
        protected override void OnRender(DrawingContext DC)
        {
            DC.DrawRectangle(BorderBrush, null, new Rect(0, 0, ActualWidth, ActualHeight));
            Rect bounds = new Rect(
                BorderThickness.Left,
                BorderThickness.Top,
                ActualWidth - (BorderThickness.Right + BorderThickness.Left),
                ActualHeight - (BorderThickness.Top + BorderThickness.Bottom));

            DC.PushClip(new RectangleGeometry(bounds));
            DC.DrawRectangle(Background, null, bounds);

            DrawTimeAxis(DC, bounds);

            if (Signals.Empty())
            {
                return;
            }

            Signal stats     = SelectedSignal;
            Signal stabilize = stats;

            if (stabilize == null)
            {
                stabilize = Signals.First();
            }

            double sampleRate = Signals.SampleRate;

            double f0 = 0.0;

            // Remembe the clock for when we analyzed the signal to keep the signals in sync even if new data gets added in the background.
            long sync = stabilize.Clock;

            lock (stabilize.Lock)
            {
                int Decimate  = 1 << (int)Math.Floor(Math.Log(sampleRate / 22000, 2));
                int BlockSize = 8192;
                if (stabilize.Count >= BlockSize)
                {
                    double[] data = stabilize.Skip(stabilize.Count - BlockSize).ToArray();

                    // Estimate the fundamental frequency of the signal.
                    double phase;
                    double f = Frequency.Estimate(data, Decimate, out phase);

                    // Convert phase from (-pi, pi] to (0, 1]
                    phase = ((phase + Math.PI) / (2 * Math.PI));

                    // Shift all the signals by the phase in samples to align the signal between frames.
                    if (f > 1.0)
                    {
                        sync -= (int)Math.Round(phase * BlockSize / f);
                    }

                    // Compute fundamental frequency in Hz.
                    f0 = sampleRate * f / BlockSize;
                }
            }

            double mean = 0.0;
            double peak = 0.0;
            double rms  = 0.0;

            if (stats != null)
            {
                lock (stats.Lock)
                {
                    // Compute statistics of the clock signal.
                    mean = stats.Sum() / stats.Count;
                    peak = stats.Max(i => Math.Abs(i - mean), 0.0);
                    rms  = Math.Sqrt(stats.Sum(i => (i - mean) * (i - mean)) / stats.Count);
                }
            }
            else
            {
                foreach (Signal i in signals)
                {
                    lock (i.Lock) peak = Math.Max(peak, i.Max(j => Math.Abs(j), 0.0));
                }
            }

            // Compute the target min/max
            double bound  = peak;
            double gamma  = 0.1;
            double window = Math.Max(Math.Pow(2.0, Math.Ceiling(Math.Log(bound + 1e-9, 2.0))), 1e-2);

            Vmax  = Math.Max(TimeFilter(Vmax, window, gamma), Math.Abs(bound + (Vmean - mean)));
            Vmean = TimeFilter(Vmean, mean, gamma);
            if (Math.Abs(mean) * 1e2 < Vmax)
            {
                Vmean = 0.0;
            }

            DrawSignalAxis(DC, bounds);

            foreach (Signal i in signals.Except(stabilize).Append(stabilize))
            {
                lock (i.Lock) DrawSignal(DC, bounds, i, (int)(sync - i.Clock));
            }

            if (stats != null)
            {
                DrawStatistics(DC, bounds, stats.Pen.Brush, peak, mean, rms, f0);
            }

            if (tracePoint.HasValue)
            {
                DrawTrace(DC, bounds, tracePoint.Value);
            }

            DC.Pop();
        }