예제 #1
0
        /// <summary>
        /// Do your analysis. This method is called once per segment (typically one-minute segments).
        /// </summary>
        public override RecognizerResults Recognize(AudioRecording recording, Config configuration, TimeSpan segmentStartOffset, Lazy <IndexCalculateResult[]> getSpectralIndexes, DirectoryInfo outputDirectory, int?imageWidth)
        {
            // WARNING: TODO TODO TODO = this method simply duplicates the CANETOAD analyser!!!!!!!!!!!!!!!!!!!!! ###################

            string speciesName            = configuration[AnalysisKeys.SpeciesName] ?? "<no species>";
            string abbreviatedSpeciesName = configuration[AnalysisKeys.AbbreviatedSpeciesName] ?? "<no.sp>";

            int minHz = configuration.GetInt(AnalysisKeys.MinHz);
            int maxHz = configuration.GetInt(AnalysisKeys.MaxHz);

            // BETTER TO CALCULATE THIS. IGNORE USER!
            // double frameOverlap = Double.Parse(configDict[Keys.FRAME_OVERLAP]);

            // duration of DCT in seconds
            double dctDuration = configuration.GetDouble(AnalysisKeys.DctDuration);

            // minimum acceptable value of a DCT coefficient
            double dctThreshold = configuration.GetDouble(AnalysisKeys.DctThreshold);

            // ignore oscillations below this threshold freq
            int minOscilFreq = configuration.GetInt(AnalysisKeys.MinOscilFreq);

            // ignore oscillations above this threshold freq
            int maxOscilFreq = configuration.GetInt(AnalysisKeys.MaxOscilFreq);

            // min duration of event in seconds
            double minDuration = configuration.GetDouble(AnalysisKeys.MinDuration);

            // max duration of event in seconds
            double maxDuration = configuration.GetDouble(AnalysisKeys.MaxDuration);

            // min score for an acceptable event
            double eventThreshold = configuration.GetDouble(AnalysisKeys.EventThreshold);

            // The default was 512 for Canetoad.
            // Framesize = 128 seems to work for Littoria fallax.
            // frame size
            int frameSize = configuration.GetInt(AnalysisKeys.KeyFrameSize);

            if (recording.WavReader.SampleRate != 22050)
            {
                throw new InvalidOperationException("Requires a 22050Hz file");
            }

            double windowOverlap = Oscillations2012.CalculateRequiredFrameOverlap(
                recording.SampleRate,
                frameSize,
                maxOscilFreq);

            //windowOverlap = 0.75; // previous default

            // i: MAKE SONOGRAM
            var sonoConfig = new SonogramConfig
            {
                SourceFName        = recording.BaseName,
                WindowSize         = frameSize,
                WindowOverlap      = windowOverlap,
                NoiseReductionType = NoiseReductionType.None,
            };

            // sonoConfig.NoiseReductionType = SNR.Key2NoiseReductionType("STANDARD");
            TimeSpan recordingDuration = recording.Duration;
            int      sr           = recording.SampleRate;
            double   freqBinWidth = sr / (double)sonoConfig.WindowSize;

            /* #############################################################################################################################################
             * window    sr          frameDuration   frames/sec  hz/bin  64frameDuration hz/64bins       hz/128bins
             * 1024     22050       46.4ms          21.5        21.5    2944ms          1376hz          2752hz
             * 1024     17640       58.0ms          17.2        17.2    3715ms          1100hz          2200hz
             * 2048     17640       116.1ms          8.6         8.6    7430ms           551hz          1100hz
             */

            // int minBin = (int)Math.Round(minHz / freqBinWidth) + 1;
            // int maxbin = minBin + numberOfBins - 1;
            BaseSonogram sonogram = new SpectrogramStandard(sonoConfig, recording.WavReader);
            int          rowCount = sonogram.Data.GetLength(0);
            int          colCount = sonogram.Data.GetLength(1);

            // double[,] subMatrix = MatrixTools.Submatrix(sonogram.Data, 0, minBin, (rowCount - 1), maxbin);

            // ######################################################################
            // ii: DO THE ANALYSIS AND RECOVER SCORES OR WHATEVER
            //minDuration = 1.0;
            Oscillations2012.Execute(
                (SpectrogramStandard)sonogram,
                minHz,
                maxHz,
                dctDuration,
                minOscilFreq,
                maxOscilFreq,
                dctThreshold,
                eventThreshold,
                minDuration,
                maxDuration,
                out var scores,
                out var oscillationEvents,
                out var hits,
                segmentStartOffset);

            var acousticEvents = oscillationEvents.ConvertSpectralEventsToAcousticEvents();

            acousticEvents.ForEach(ae =>
            {
                ae.SpeciesName            = speciesName;
                ae.SegmentDurationSeconds = recordingDuration.TotalSeconds;
                ae.SegmentStartSeconds    = segmentStartOffset.TotalSeconds;
                ae.Name = abbreviatedSpeciesName;
            });

            var plot = new Plot(this.DisplayName, scores, eventThreshold);

            return(new RecognizerResults()
            {
                Sonogram = sonogram,
                Hits = hits,
                Plots = plot.AsList(),
                Events = acousticEvents,
            });
        }
예제 #2
0
    private void Build()
    {
        if (currentlyBuilding == null)
        {
            return;
        }

        Ray ray = Camera.main.ScreenPointToRay(Mouse.current.position.ReadValue());

        if (Physics.Raycast(ray, out RaycastHit hit))
        {
            Plot plot = hit.transform.GetComponentInParent <Plot>();

            if (plot != null)
            {
                Building building = currentlyBuilding.GetComponent <Building>();

                if (Balance <= building.Cost)
                {
                    // TODO: Sound effect


                    return;
                }

                Slot slot = plot.GetNearestSlot(hit.point);

                if (building == null)
                {
                    throw new Exception($"Mate '{currentlyBuilding.name}' is not a building!");
                }

                if (IsPositionValid(plot, slot, building.Size, out Vector2Int topRight, out Vector2Int bottomLeft))
                {
                    // Mark slots as unavailable
                    for (int y = bottomLeft.y; y <= topRight.y; y++)
                    {
                        for (int x = bottomLeft.x; x <= topRight.x; x++)
                        {
                            plot.Grid[y, x].IsAvailable = false;
                        }
                    }

                    GameObject buildingObject;

                    switch (building)
                    {
                    case SolarPanel solarPanel:
                        if (PowerSystemManager.Instance.SolarPanelCount < PowerSystemManager.Instance.SolarPanelCapacity)
                        {
                            buildingObject = Instantiate(currentlyBuilding, slot.WorldPosition, Quaternion.identity);
                            PowerSystemManager.Instance.AddSolarPanel(buildingObject);

                            Balance -= building.Cost;
                        }
                        break;

                    case Battery battery:
                        buildingObject = Instantiate(currentlyBuilding, slot.WorldPosition, Quaternion.identity);
                        PowerSystemManager.Instance.AddBattery(buildingObject);

                        Balance -= building.Cost;
                        break;

                    case ElectricalBox electricalBox:
                        buildingObject = Instantiate(currentlyBuilding, slot.WorldPosition, Quaternion.identity);
                        PowerSystemManager.Instance.AddElectricalBox(buildingObject);

                        Balance -= building.Cost;
                        break;
                    }
                    currentlyBuilding = null;
                    AudioManager.Instance.PlayBuildSound();
                }
            }
        }
    }
예제 #3
0
        // OTHER CONSTANTS
        //private const string ImageViewer = @"C:\Windows\system32\mspaint.exe";

        /// <summary>
        /// Do your analysis. This method is called once per segment (typically one-minute segments).
        /// </summary>
        public override RecognizerResults Recognize(AudioRecording recording, Config configuration, TimeSpan segmentStartOffset, Lazy <IndexCalculateResult[]> getSpectralIndexes, DirectoryInfo outputDirectory, int?imageWidth)
        {
            var recognizerConfig = new LitoriaBicolorConfig();

            recognizerConfig.ReadConfigFile(configuration);

            if (recording.WavReader.SampleRate != 22050)
            {
                throw new InvalidOperationException("Requires a 22050Hz file");
            }

            TimeSpan recordingDuration = recording.WavReader.Time;

            //// ignore oscillations below this threshold freq
            //int minOscilFreq = (int)configuration[AnalysisKeys.MinOscilFreq];
            //// ignore oscillations above this threshold freq
            int maxOscilRate = (int)Math.Ceiling(1 / recognizerConfig.MinPeriod);

            // this default framesize seems to work
            const int frameSize     = 128;
            double    windowOverlap = Oscillations2012.CalculateRequiredFrameOverlap(
                recording.SampleRate,
                frameSize,
                maxOscilRate);

            // i: MAKE SONOGRAM
            var sonoConfig = new SonogramConfig
            {
                SourceFName = recording.BaseName,

                //set default values - ignore those set by user
                WindowSize    = frameSize,
                WindowOverlap = windowOverlap,

                // the default window is HAMMING
                //WindowFunction = WindowFunctions.HANNING.ToString(),
                //WindowFunction = WindowFunctions.NONE.ToString(),
                // if do not use noise reduction can get a more sensitive recogniser.
                //NoiseReductionType = NoiseReductionType.NONE,
                NoiseReductionType = SNR.KeyToNoiseReductionType("STANDARD"),
            };

            //#############################################################################################################################################
            //DO THE ANALYSIS AND RECOVER SCORES OR WHATEVER
            var results = Analysis(recording, sonoConfig, recognizerConfig, MainEntry.InDEBUG, segmentStartOffset);

            //######################################################################

            if (results == null)
            {
                return(null); //nothing to process
            }

            var sonogram        = results.Item1;
            var hits            = results.Item2;
            var scoreArray      = results.Item3;
            var predictedEvents = results.Item4;
            var debugImage      = results.Item5;

            //#############################################################################################################################################

            var debugPath = outputDirectory.Combine(FilenameHelpers.AnalysisResultName(Path.GetFileNameWithoutExtension(recording.BaseName), this.SpeciesName, "png", "DebugSpectrogram"));

            debugImage.Save(debugPath.FullName);

            // Prune events here if erquired i.e. remove those below threshold score if this not already done. See other recognizers.
            foreach (AcousticEvent ae in predictedEvents)
            {
                // add additional info
                ae.Name                   = recognizerConfig.AbbreviatedSpeciesName;
                ae.SpeciesName            = recognizerConfig.SpeciesName;
                ae.SegmentStartSeconds    = segmentStartOffset.TotalSeconds;
                ae.SegmentDurationSeconds = recordingDuration.TotalSeconds;
            }

            var plot = new Plot(this.DisplayName, scoreArray, recognizerConfig.EventThreshold);

            return(new RecognizerResults()
            {
                Sonogram = sonogram,
                Hits = hits,
                Plots = plot.AsList(),
                Events = predictedEvents,
            });
        }
예제 #4
0
 public void ExecuteRecipe(Plot plt)
 {
     plt.AddColorbar(rightSide: false);
 }
예제 #5
0
 public (double x, double y) GetMouseCoordinates()
 {
     (double x, double y) = Plot.GetCoordinate(MouseLocationX, MouseLocationY);
     return(double.IsNaN(x) ? 0 : x, double.IsNaN(y) ? 0 : y);
 }
예제 #6
0
 public bool IsLastClaim(Plot plot)
 {
     throw new NotImplementedException("Please implement the ClaimsHandler.IsLastClaim() method");
 }
        /// <summary>
        /// Do your analysis. This method is called once per segment (typically one-minute segments).
        /// </summary>
        public override RecognizerResults Recognize(AudioRecording recording, Config configuration, TimeSpan segmentStartOffset, Lazy <IndexCalculateResult[]> getSpectralIndexes, DirectoryInfo outputDirectory, int?imageWidth)
        {
            var recognizerConfig = new LitoriaCaeruleaConfig();

            recognizerConfig.ReadConfigFile(configuration);

            // common properties
            string speciesName            = configuration[AnalysisKeys.SpeciesName] ?? "<no name>";
            string abbreviatedSpeciesName = configuration[AnalysisKeys.AbbreviatedSpeciesName] ?? "<no.sp>";

            // BETTER TO SET THESE. IGNORE USER!
            // This framesize is large because the oscillation we wish to detect is due to repeated croaks
            // having an interval of about 0.6 seconds. The overlap is also required to give smooth oscillation.
            const int    frameSize     = 2048;
            const double windowOverlap = 0.5;

            // i: MAKE SONOGRAM
            var sonoConfig = new SonogramConfig
            {
                SourceFName   = recording.BaseName,
                WindowSize    = frameSize,
                WindowOverlap = windowOverlap,

                // use the default HAMMING window
                //WindowFunction = WindowFunctions.HANNING.ToString(),
                //WindowFunction = WindowFunctions.NONE.ToString(),

                // if do not use noise reduction can get a more sensitive recogniser.
                //NoiseReductionType = NoiseReductionType.None
                NoiseReductionType      = NoiseReductionType.Standard,
                NoiseReductionParameter = 0.0,
            };

            TimeSpan recordingDuration = recording.WavReader.Time;
            int      sr              = recording.SampleRate;
            double   freqBinWidth    = sr / (double)sonoConfig.WindowSize;
            double   framesPerSecond = sr / (sonoConfig.WindowSize * (1 - windowOverlap));

            //int dominantFreqBin = (int)Math.Round(recognizerConfig.DominantFreq / freqBinWidth) + 1;
            int minBin           = (int)Math.Round(recognizerConfig.MinHz / freqBinWidth) + 1;
            int maxBin           = (int)Math.Round(recognizerConfig.MaxHz / freqBinWidth) + 1;
            var decibelThreshold = 9.0;

            BaseSonogram sonogram = new SpectrogramStandard(sonoConfig, recording.WavReader);

            // ######################################################################
            // ii: DO THE ANALYSIS AND RECOVER SCORES OR WHATEVER
            int rowCount = sonogram.Data.GetLength(0);

            // get the freq band as set by min and max Herz
            var frogBand = MatrixTools.Submatrix(sonogram.Data, 0, minBin, rowCount - 1, maxBin);

            // Now look for spectral maxima. For L.caerulea, the max should lie around 1100Hz +/-150 Hz.
            // Skip over spectra where maximum is not in correct location.
            int buffer            = 150;
            var croakScoreArray   = new double[rowCount];
            var hzAtTopOfTopBand  = recognizerConfig.DominantFreq + buffer;
            var hzAtBotOfTopBand  = recognizerConfig.DominantFreq - buffer;
            var binAtTopOfTopBand = (int)Math.Round((hzAtTopOfTopBand - recognizerConfig.MinHz) / freqBinWidth);
            var binAtBotOfTopBand = (int)Math.Round((hzAtBotOfTopBand - recognizerConfig.MinHz) / freqBinWidth);

            // scan the frog band and get the decibel value of those spectra which have their maximum within the correct subband.
            for (int x = 0; x < rowCount; x++)
            {
                //extract spectrum
                var spectrum = MatrixTools.GetRow(frogBand, x);
                int maxIndex = DataTools.GetMaxIndex(spectrum);
                if (spectrum[maxIndex] < decibelThreshold)
                {
                    continue;
                }

                if (maxIndex < binAtTopOfTopBand && maxIndex > binAtBotOfTopBand)
                {
                    croakScoreArray[x] = spectrum[maxIndex];
                }
            }

            // Perpare a normalised plot for later display with spectrogram
            DataTools.Normalise(croakScoreArray, decibelThreshold, out var normalisedScores, out var normalisedThreshold);
            var text1      = string.Format($"Croak scores (threshold={decibelThreshold})");
            var croakPlot1 = new Plot(text1, normalisedScores, normalisedThreshold);

            // extract potential croak events from the array of croak candidate
            var croakEvents = AcousticEvent.ConvertScoreArray2Events(
                croakScoreArray,
                recognizerConfig.MinHz,
                recognizerConfig.MaxHz,
                sonogram.FramesPerSecond,
                freqBinWidth,
                recognizerConfig.EventThreshold,
                recognizerConfig.MinCroakDuration,
                recognizerConfig.MaxCroakDuration,
                segmentStartOffset);

            // add necesary info into the candidate events
            var prunedEvents = new List <AcousticEvent>();

            foreach (var ae in croakEvents)
            {
                // add additional info
                ae.SpeciesName            = speciesName;
                ae.SegmentStartSeconds    = segmentStartOffset.TotalSeconds;
                ae.SegmentDurationSeconds = recordingDuration.TotalSeconds;
                ae.Name = recognizerConfig.AbbreviatedSpeciesName;
                prunedEvents.Add(ae);
            }

            // With those events that survive the above Array2Events process, we now extract a new array croak scores
            croakScoreArray = AcousticEvent.ExtractScoreArrayFromEvents(prunedEvents, rowCount, recognizerConfig.AbbreviatedSpeciesName);
            DataTools.Normalise(croakScoreArray, decibelThreshold, out normalisedScores, out normalisedThreshold);
            var text2      = string.Format($"Croak events (threshold={decibelThreshold})");
            var croakPlot2 = new Plot(text2, normalisedScores, normalisedThreshold);

            // Look for oscillations in the difference array
            // duration of DCT in seconds
            //croakScoreArray = DataTools.filterMovingAverageOdd(croakScoreArray, 5);
            double dctDuration = recognizerConfig.DctDuration;

            // minimum acceptable value of a DCT coefficient
            double dctThreshold = recognizerConfig.DctThreshold;
            double minOscRate   = 1 / recognizerConfig.MaxPeriod;
            double maxOscRate   = 1 / recognizerConfig.MinPeriod;

            Oscillations2019.DetectOscillations(croakScoreArray, framesPerSecond, decibelThreshold, dctDuration, minOscRate, maxOscRate, dctThreshold, out double[] dctScores, out double[] oscFreq);

            // ######################################################################
            // ii: DO THE ANALYSIS AND RECOVER SCORES OR WHATEVER
            var events = AcousticEvent.ConvertScoreArray2Events(
                dctScores,
                recognizerConfig.MinHz,
                recognizerConfig.MaxHz,
                sonogram.FramesPerSecond,
                freqBinWidth,
                recognizerConfig.EventThreshold,
                recognizerConfig.MinDuration,
                recognizerConfig.MaxDuration,
                segmentStartOffset);

            double[,] hits = null;
            prunedEvents   = new List <AcousticEvent>();
            foreach (var ae in events)
            {
                // add additional info
                ae.SpeciesName            = speciesName;
                ae.SegmentStartSeconds    = segmentStartOffset.TotalSeconds;
                ae.SegmentDurationSeconds = recordingDuration.TotalSeconds;
                ae.Name = recognizerConfig.AbbreviatedSpeciesName;
                prunedEvents.Add(ae);
            }

            // do a recognizer test.
            if (MainEntry.InDEBUG)
            {
                //TestTools.RecognizerScoresTest(scores, new FileInfo(recording.FilePath));
                //AcousticEvent.TestToCompareEvents(prunedEvents, new FileInfo(recording.FilePath));
            }

            var scoresPlot = new Plot(this.DisplayName, dctScores, recognizerConfig.EventThreshold);

            if (true)
            {
                // display a variety of debug score arrays
                // calculate amplitude at location
                double[] amplitudeArray = MatrixTools.SumRows(frogBand);
                DataTools.Normalise(amplitudeArray, decibelThreshold, out normalisedScores, out normalisedThreshold);
                var amplPlot = new Plot("Band amplitude", normalisedScores, normalisedThreshold);

                var debugPlots = new List <Plot> {
                    scoresPlot, croakPlot2, croakPlot1, amplPlot
                };

                // NOTE: This DrawDebugImage() method can be over-written in this class.
                var debugImage = DrawDebugImage(sonogram, prunedEvents, debugPlots, hits);
                var debugPath  = FilenameHelpers.AnalysisResultPath(outputDirectory, recording.BaseName, this.SpeciesName, "png", "DebugSpectrogram");
                debugImage.Save(debugPath);
            }

            return(new RecognizerResults()
            {
                Sonogram = sonogram,
                Hits = hits,
                Plots = scoresPlot.AsList(),
                Events = prunedEvents,

                //Events = events
            });
        }
예제 #8
0
 private void ClearNIPlot(Graph graph, Plot plot)
 {
     graph.Invoke(new ClearDataDelegate(plot.ClearData));
 }
예제 #9
0
 public void Render(Plot plt)
 {
     double[,] imageData = DataGen.SampleImageData();
     plt.PlotHeatmap(imageData);
 }
예제 #10
0
        public Line FindBestGap(Plot obstacles)
        {
            List <Region> regions = obstacles.Regions;

            double bestGapDistance = 0;
            Line   bestGap         = null;

            // Sanity check
            if (regions.Count == 0)
            {
                // Return Line representing gap straight in front of Ascent
                return(DriveContext.GapStraightInFront());
            }

            // Check first and last Region gaps (may be same Region if only one Region)
            Region firstRegion = regions.ElementAt(0);
            Region lastRegion  = regions.ElementAt(regions.Count - 1);

            // Check if leftmost Coordinate in the leftmost Region is on the right half of the entire FOV. If it is, make leftEdgeCoordinate where the
            // max-acceptable-range meets the left FOV line, since the FindClosestPointOnLine function return will cause errors for 180 degree FOV.
            Coordinate leftEdgeCoordinate = Line.FindClosestPointOnLine(DriveContext.LRF_LEFT_FOV_EDGE, firstRegion.StartCoordinate);

            if (firstRegion.StartCoordinate.X > 0)
            {
                leftEdgeCoordinate = new Coordinate(-AutonomousService.OBSTACLE_DETECTION_DISTANCE, 0, CoordSystem.Cartesian);
            }
            Line leftEdgeGap = new Line(leftEdgeCoordinate, firstRegion.StartCoordinate);

            // Check if rightmost Coordinate in the rightmost Region is on the left half of the entire FOV. If it is, make rightEdgeCoordinate where the
            // max-acceptable-range meets the right FOV line, since the FindClosestPointOnLine function return will cause errors for 180 degree FOV.
            Coordinate rightEdgeCoordinate = Line.FindClosestPointOnLine(DriveContext.LRF_RIGHT_FOV_EDGE, lastRegion.EndCoordinate);

            if (lastRegion.EndCoordinate.X < 0)
            {
                rightEdgeCoordinate = new Coordinate(AutonomousService.OBSTACLE_DETECTION_DISTANCE, 0, CoordSystem.Cartesian);
            }
            Line rightEdgeGap = new Line(rightEdgeCoordinate, lastRegion.EndCoordinate);

            // Check two possible edge gaps for bestGap
            Line bestEdgeGap = leftEdgeGap.Length > rightEdgeGap.Length ? leftEdgeGap : rightEdgeGap;

            if (bestEdgeGap.Length > DriveContext.ASCENT_WIDTH)
            {
                bestGap         = bestEdgeGap;
                bestGapDistance = bestEdgeGap.Length;
            }

            // Check all non-edge Regions for bestGap (only if there is more than 1 Region)
            for (int i = 0; i < regions.Count - 1; i++)
            {
                Region leftRegion  = regions.ElementAt(i);
                Region rightRegion = regions.ElementAt(i + 1);

                double gapDistance = Plot.GapDistanceBetweenRegions(leftRegion, rightRegion);

                // If gap distance is big enough for robot to fit and larger than current bestGapDistance
                if (gapDistance > DriveContext.ASCENT_WIDTH)
                {
                    if (gapDistance > bestGapDistance)
                    {
                        bestGapDistance = gapDistance;
                        bestGap         = new Line(leftRegion.EndCoordinate, rightRegion.StartCoordinate);
                    }
                }
            }

            return(bestGap);
        }
예제 #11
0
 public void ExecuteRecipe(Plot plt)
 {
     double[] values = DataGen.RandomWalk(1_000_000);
     plt.AddSignal(values, sampleRate: 48_000);
     plt.Title("One Million Points");
 }
예제 #12
0
        /// <summary>
        /// Do your analysis. This method is called once per segment (typically one-minute segments).
        /// </summary>
        /// <param name="recording"></param>
        /// <param name="configuration"></param>
        /// <param name="segmentStartOffset"></param>
        /// <param name="getSpectralIndexes"></param>
        /// <param name="outputDirectory"></param>
        /// <param name="imageWidth"></param>
        /// <returns></returns>
        public override RecognizerResults Recognize(AudioRecording recording, Config configuration, TimeSpan segmentStartOffset, Lazy <IndexCalculateResult[]> getSpectralIndexes, DirectoryInfo outputDirectory, int?imageWidth)
        {
            string speciesName            = configuration[AnalysisKeys.SpeciesName] ?? "<no species>";
            string abbreviatedSpeciesName = configuration[AnalysisKeys.AbbreviatedSpeciesName] ?? "<no.sp>";

            int minHz = configuration.GetInt(AnalysisKeys.MinHz);
            int maxHz = configuration.GetInt(AnalysisKeys.MaxHz);

            // BETTER TO CALCULATE THIS. IGNORE USER!
            // double frameOverlap = Double.Parse(configDict[Keys.FRAME_OVERLAP]);

            // duration of DCT in seconds
            double dctDuration = configuration.GetDouble(AnalysisKeys.DctDuration);

            // minimum acceptable value of a DCT coefficient
            double dctThreshold = configuration.GetDouble(AnalysisKeys.DctThreshold);

            // ignore oscillations below this threshold freq
            int minOscilFreq = configuration.GetInt(AnalysisKeys.MinOscilFreq);

            // ignore oscillations above this threshold freq
            int maxOscilFreq = configuration.GetInt(AnalysisKeys.MaxOscilFreq);

            // min duration of event in seconds
            double minDuration = configuration.GetDouble(AnalysisKeys.MinDuration);

            // max duration of event in seconds
            double maxDuration = configuration.GetDouble(AnalysisKeys.MaxDuration);

            // min score for an acceptable event
            double eventThreshold = configuration.GetDouble(AnalysisKeys.EventThreshold);

            // The default was 512 for Canetoad.
            // Framesize = 128 seems to work for Littoria fallax.
            // frame size
            int frameSize = configuration.GetInt(AnalysisKeys.KeyFrameSize);

            if (recording.WavReader.SampleRate != 22050)
            {
                throw new InvalidOperationException("Requires a 22050Hz file");
            }

            double windowOverlap = Oscillations2012.CalculateRequiredFrameOverlap(
                recording.SampleRate,
                frameSize,
                maxOscilFreq);

            //windowOverlap = 0.75; // previous default

            // i: MAKE SONOGRAM
            var sonoConfig = new SonogramConfig
            {
                SourceFName   = recording.BaseName,
                WindowSize    = frameSize,
                WindowOverlap = windowOverlap,

                //NoiseReductionType = NoiseReductionType.NONE,
                NoiseReductionType      = NoiseReductionType.Standard,
                NoiseReductionParameter = 0.2,
            };

            TimeSpan recordingDuration = recording.Duration;
            int      sr           = recording.SampleRate;
            double   freqBinWidth = sr / (double)sonoConfig.WindowSize;

            BaseSonogram sonogram = new SpectrogramStandard(sonoConfig, recording.WavReader);
            int          rowCount = sonogram.Data.GetLength(0);
            int          colCount = sonogram.Data.GetLength(1);

            // double[,] subMatrix = MatrixTools.Submatrix(sonogram.Data, 0, minBin, (rowCount - 1), maxbin);

            // ######################################################################
            // ii: DO THE ANALYSIS AND RECOVER SCORES OR WHATEVER
            // This window is used to smooth the score array before extracting events.
            // A short window preserves sharper score edges to define events but also keeps noise.
            int scoreSmoothingWindow = 5;

            Oscillations2012.Execute(
                (SpectrogramStandard)sonogram,
                minHz,
                maxHz,
                dctDuration,
                minOscilFreq,
                maxOscilFreq,
                dctThreshold,
                eventThreshold,
                minDuration,
                maxDuration,
                scoreSmoothingWindow,
                out var scores,
                out var acousticEvents,
                out var hits,
                segmentStartOffset);

            acousticEvents.ForEach(ae =>
            {
                ae.SpeciesName            = speciesName;
                ae.SegmentDurationSeconds = recordingDuration.TotalSeconds;
                ae.SegmentStartSeconds    = segmentStartOffset.TotalSeconds;
                ae.Name = abbreviatedSpeciesName;
            });

            var plot  = new Plot(this.DisplayName, scores, eventThreshold);
            var plots = new List <Plot> {
                plot
            };

            // DEBUG IMAGE this recognizer only. MUST set false for deployment.
            bool displayDebugImage = MainEntry.InDEBUG;

            if (displayDebugImage)
            {
                Image debugImage = DisplayDebugImage(sonogram, acousticEvents, plots, hits);
                var   debugPath  = outputDirectory.Combine(FilenameHelpers.AnalysisResultName(Path.GetFileNameWithoutExtension(recording.BaseName), this.Identifier, "png", "DebugSpectrogram"));
                debugImage.Save(debugPath.FullName);
            }

            return(new RecognizerResults()
            {
                Sonogram = sonogram,
                Hits = hits,
                Plots = plots,
                Events = acousticEvents,
            });
        }
        static void SavePlot(Plot plot, string fileName)
        {
            string filePath = $"{AnalysisDirectoryPath}/{fileName}";

            plot.SaveFig(filePath);
        }
예제 #14
0
        /// <summary>
        /// Do your analysis. This method is called once per segment (typically one-minute segments).
        /// </summary>
        public override RecognizerResults Recognize(AudioRecording recording, Config configuration, TimeSpan segmentStartOffset, Lazy <IndexCalculateResult[]> getSpectralIndexes, DirectoryInfo outputDirectory, int?imageWidth)
        {
            var recognizerConfig = new CriniaRemotaConfig();

            recognizerConfig.ReadConfigFile(configuration);

            // BETTER TO SET THESE. IGNORE USER!
            // this default framesize seems to work
            const int    frameSize     = 256;
            const double windowOverlap = 0.25;

            // i: MAKE SONOGRAM
            var sonoConfig = new SonogramConfig
            {
                SourceFName   = recording.BaseName,
                WindowSize    = frameSize,
                WindowOverlap = windowOverlap,

                // use the default HAMMING window
                //WindowFunction = WindowFunctions.HANNING.ToString(),
                //WindowFunction = WindowFunctions.NONE.ToString(),

                // if do not use noise reduction can get a more sensitive recogniser.
                //NoiseReductionType = NoiseReductionType.None
                NoiseReductionType      = NoiseReductionType.Standard,
                NoiseReductionParameter = 0.0,
            };

            TimeSpan recordingDuration = recording.WavReader.Time;
            int      sr               = recording.SampleRate;
            double   freqBinWidth     = sr / (double)sonoConfig.WindowSize;
            int      minBin           = (int)Math.Round(recognizerConfig.MinHz / freqBinWidth) + 1;
            int      maxBin           = (int)Math.Round(recognizerConfig.MaxHz / freqBinWidth) + 1;
            var      decibelThreshold = 6.0;

            BaseSonogram sonogram = new SpectrogramStandard(sonoConfig, recording.WavReader);

            // ######################################################################
            // ii: DO THE ANALYSIS AND RECOVER SCORES OR WHATEVER
            int rowCount = sonogram.Data.GetLength(0);

            double[] amplitudeArray = MatrixTools.GetRowAveragesOfSubmatrix(sonogram.Data, 0, minBin, rowCount - 1, maxBin);
            double[] topBand        = MatrixTools.GetRowAveragesOfSubmatrix(sonogram.Data, 0, maxBin + 3, rowCount - 1, maxBin + 9);
            double[] botBand        = MatrixTools.GetRowAveragesOfSubmatrix(sonogram.Data, 0, minBin - 3, rowCount - 1, minBin - 9);
            double[] diffArray      = new double[amplitudeArray.Length];
            for (int i = 0; i < amplitudeArray.Length; i++)
            {
                diffArray[i] = amplitudeArray[i] - topBand[i] - botBand[i];
                if (diffArray[i] < 1.0)
                {
                    diffArray[i] = 0.0;
                }
            }

            bool[] peakArray = new bool[amplitudeArray.Length];
            for (int i = 1; i < diffArray.Length - 1; i++)
            {
                if (diffArray[i] < decibelThreshold)
                {
                    continue;
                }

                if (diffArray[i] > diffArray[i - 1] && diffArray[i] > diffArray[i + 1])
                {
                    peakArray[i] = true;
                }
            }

            // calculate score array based on density of peaks
            double frameDuration = (double)frameSize / sr;

            // use a stimulus-decay function
            double durationOfDecayTail = 0.35; // seconds
            int    lengthOfDecayTail   = (int)Math.Round(durationOfDecayTail / frameDuration);
            double decayrate           = 0.95;

            //double decay = -0.05;
            //double fractionalDecay = Math.Exp(decay * lengthOfDecayTail);
            // the above setting gives decay of 0.22 over 0.35 seconds or 30 frames.

            double score = 0.0;
            int    locationOfLastPeak = 0;

            double[] peakScores = new double[amplitudeArray.Length];
            for (int p = 0; p < peakScores.Length - 1; p++)
            {
                if (!peakArray[p])
                {
                    int distanceFromLastpeak = p - locationOfLastPeak;

                    // score decay
                    score *= decayrate;

                    // remove the decay tail
                    if (score < 0.5 && distanceFromLastpeak > lengthOfDecayTail && p >= lengthOfDecayTail)
                    {
                        score = 0.0;
                        for (int j = 0; j < lengthOfDecayTail; j++)
                        {
                            peakScores[p - j] = score;
                        }
                    }
                }
                else
                {
                    locationOfLastPeak = p;
                    score += 0.8;
                }

                peakScores[p] = score;
            }

            var events = AcousticEvent.ConvertScoreArray2Events(
                peakScores,
                recognizerConfig.MinHz,
                recognizerConfig.MaxHz,
                sonogram.FramesPerSecond,
                freqBinWidth,
                recognizerConfig.EventThreshold,
                recognizerConfig.MinDuration,
                recognizerConfig.MaxDuration,
                segmentStartOffset);

            double[,] hits = null;

            var prunedEvents = new List <AcousticEvent>();

            foreach (var ae in events)
            {
                if (ae.EventDurationSeconds < recognizerConfig.MinDuration || ae.EventDurationSeconds > recognizerConfig.MaxDuration)
                {
                    continue;
                }

                // add additional info
                ae.SpeciesName            = recognizerConfig.SpeciesName;
                ae.SegmentStartSeconds    = segmentStartOffset.TotalSeconds;
                ae.SegmentDurationSeconds = recordingDuration.TotalSeconds;
                ae.Name = recognizerConfig.AbbreviatedSpeciesName;
                prunedEvents.Add(ae);
            }

            // do a recognizer test.
            if (MainEntry.InDEBUG)
            {
                // var testDir = new DirectoryInfo(outputDirectory.Parent.Parent.FullName);
                // TestTools.RecognizerScoresTest(recording.BaseName, testDir, recognizerConfig.AnalysisName, peakScores);
                // AcousticEvent.TestToCompareEvents(recording.BaseName, testDir, recognizerConfig.AnalysisName, prunedEvents);
            }

            var plot = new Plot(this.DisplayName, peakScores, recognizerConfig.EventThreshold);

            if (false)
            {
                // display a variety of debug score arrays
                double[] normalisedScores;
                double   normalisedThreshold;
                DataTools.Normalise(amplitudeArray, decibelThreshold, out normalisedScores, out normalisedThreshold);
                var amplPlot = new Plot("Band amplitude", normalisedScores, normalisedThreshold);
                DataTools.Normalise(diffArray, decibelThreshold, out normalisedScores, out normalisedThreshold);
                var diffPlot = new Plot("Diff plot", normalisedScores, normalisedThreshold);

                var debugPlots = new List <Plot> {
                    plot, amplPlot, diffPlot
                };

                // NOTE: This DrawDebugImage() method can be over-written in this class.
                var debugImage = DrawDebugImage(sonogram, prunedEvents, debugPlots, hits);
                var debugPath  = FilenameHelpers.AnalysisResultPath(outputDirectory, recording.BaseName, this.SpeciesName, "png", "DebugSpectrogram");
                debugImage.Save(debugPath);
            }

            return(new RecognizerResults
            {
                Sonogram = sonogram,
                Hits = hits,
                Plots = plot.AsList(),
                Events = prunedEvents,

                //Events = events
            });
        } // Recognize()
예제 #15
0
 public void ExecuteRecipe(Plot plt)
 {
     double[,] imageData = DataGen.SampleImageData();
     plt.AddHeatmap(imageData);
 }
예제 #16
0
 public void AddPlot( Plot p )
 {
     if( plots == null )
         plots = new List<Plot>();
     plots.Add( p );
 }
예제 #17
0
        public override void DoAction(int player, PlayerAction action)
        {
            if (player != playerNum)
            {
                return;
            }

            if (state == LocalState.WaitForButton)
            {
                if (action == PlayerAction.JoystickButton)
                {
                    game.Sound.PlayBeep(playerNum);
                    state = LocalState.ZoomInStore;
                    stateTimer.Change(10, 10);
                    game.Players[playerNum].Highlight = false;
                }
            }
            else if (
                state == LocalState.InStore ||
                state == LocalState.Outside)
            {
                switch (action)
                {
                case PlayerAction.JoystickButton:
                    if (state == LocalState.Outside)
                    {
                        Plot plot =
                            game.Map.CheckHouse(
                                playerNum,
                                new Rectangle(
                                    playerSprite.X,
                                    playerSprite.Y,
                                    Graphics.SMALLPLAYERWIDTH,
                                    Graphics.SMALLPLAYERHEIGHT
                                    ));

                        if (plot != null)
                        {
                            game.Sound.PlayBeep(playerNum);
                        }
                    }
                    break;

                case PlayerAction.JoystickCenter:
                    playerSprite.StopAnimation();
                    playerSprite.ChangeDirection(SpriteDirection.S);
                    playerIncX = 0;
                    playerIncY = 0;
                    break;

                case PlayerAction.JoystickN:
                    playerSprite.StartAnimation();
                    playerSprite.ChangeDirection(SpriteDirection.N);
                    playerIncX = 0;
                    playerIncY = -1;
                    break;

                case PlayerAction.JoystickNE:
                    playerSprite.StartAnimation();
                    playerSprite.ChangeDirection(SpriteDirection.NE);
                    playerIncX = 1;
                    playerIncY = -1;
                    break;

                case PlayerAction.JoystickE:
                    playerSprite.StartAnimation();
                    playerSprite.ChangeDirection(SpriteDirection.E);
                    playerIncX = 1;
                    playerIncY = 0;
                    break;

                case PlayerAction.JoystickSE:
                    playerSprite.StartAnimation();
                    playerSprite.ChangeDirection(SpriteDirection.SE);
                    playerIncX = 1;
                    playerIncY = 1;
                    break;

                case PlayerAction.JoystickS:
                    playerSprite.StartAnimation();
                    playerSprite.ChangeDirection(SpriteDirection.S);
                    playerIncX = 0;
                    playerIncY = 1;
                    break;

                case PlayerAction.JoystickSW:
                    playerSprite.StartAnimation();
                    playerSprite.ChangeDirection(SpriteDirection.SW);
                    playerIncX = -1;
                    playerIncY = 1;
                    break;

                case PlayerAction.JoystickW:
                    playerSprite.StartAnimation();
                    playerSprite.ChangeDirection(SpriteDirection.W);
                    playerIncX = -1;
                    playerIncY = 0;
                    break;

                case PlayerAction.JoystickNW:
                    playerSprite.StartAnimation();
                    playerSprite.ChangeDirection(SpriteDirection.NW);
                    playerIncX = -1;
                    playerIncY = -1;
                    break;
                }
            }
        }
예제 #18
0
 public void Reset(float width, float height, Plot newPlot)
 {
     Plot     = newPlot;
     Settings = Plot.GetSettings(false);
     Resize(width, height);
 }
예제 #19
0
 public void ExecuteRecipe(Plot plt)
 {
     double[] values = { 778, 283, 184, 76, 43 };
     plt.AddPie(values);
 }
예제 #20
0
 public void StakeClaim(Plot plot)
 {
     throw new NotImplementedException("Please implement the ClaimsHandler.StakeClaim() method");
 }
예제 #21
0
        /// <summary>
        ///     Initializes the experiments to be monitored through a batch file that
        ///     contains all required data for the task.
        /// </summary>
        /// <param name="batchFileName">The batch file with experiment data</param>
        public bool LoadExperimentBatch(string batchFileName)
        {
            //Load unfinished experiments
            LoadOptions loadOptionsUnfinished = new LoadOptions()
            {
                Selection          = LoadOptions.ExpUnitSelection.OnlyUnfinished,
                LoadVariablesInLog = false
            };

            ExperimentBatch batchUnfinished = new ExperimentBatch();

            batchUnfinished.Load(batchFileName, loadOptionsUnfinished);

            LoggedExperiments.Clear();
            foreach (Experiment experiment in batchUnfinished.Experiments)
            {
                LoggedExperimentViewModel newExperiment = new LoggedExperimentViewModel(experiment);
                LoggedExperiments.Add(newExperiment);
            }
            //count unfinished experiments
            int numUnfinishedExperimentalUnits = batchUnfinished.CountExperimentalUnits();

            //load all experimental units and count them
            LoadOptions loadOptionsFinished = new LoadOptions()
            {
                Selection          = LoadOptions.ExpUnitSelection.OnlyFinished,
                LoadVariablesInLog = false
            };

            //we use a temp variable first to get the count of finished units so that setting the value of NumFinishedExperimentalUnitsBeforeStart triggers the progress update
            //AFTER setting the value of NumExperimentalUnits
            NumFinishedExperimentalUnitsBeforeStart = ExperimentBatch.CountExperimentalUnits(batchFileName, LoadOptions.ExpUnitSelection.OnlyFinished);
            NumExperimentalUnits = numUnfinishedExperimentalUnits + NumFinishedExperimentalUnitsBeforeStart;
            NumFinishedExperimentalUnitsAfterStart = 0;

            //Initialize pending experiment list
            m_pendingExperiments.Clear();

            foreach (var experiment in LoggedExperiments)
            {
                foreach (AppVersion version in experiment.AppVersions)
                {
                    if (!ExistsRequiredFile(version.ExeFile))
                    {
                        CaliburnUtility.ShowWarningDialog("Cannot find required file: " + version.ExeFile + ". Check the app definition file in /config/apps", "ERROR");
                        return(false);
                    }
                    foreach (string pre in version.Requirements.InputFiles)
                    {
                        if (!ExistsRequiredFile(pre))
                        {
                            CaliburnUtility.ShowWarningDialog("Cannot find required file: " + pre + ". Check the app definition file in /config/apps", "ERROR");
                            return(false);
                        }
                    }
                }
                foreach (LoggedExperimentalUnitViewModel unit in experiment.ExperimentalUnits)
                {
                    m_pendingExperiments.Add(unit.Model);
                }
            }

            BatchFileName = batchFileName;
            Plot.ClearLineSeries();
            AllMonitoredJobs.Clear();
            IsBatchLoaded = true;
            IsRunning     = false;

            return(true);
        }
예제 #22
0
        /// <summary>
        /// THE KEY ANALYSIS METHOD.
        /// </summary>
        public static Tuple <BaseSonogram, double[, ], double[], List <AcousticEvent>, Image> Analysis(
            AudioRecording recording,
            SonogramConfig sonoConfig,
            LitoriaBicolorConfig lbConfig,
            bool drawDebugImage,
            TimeSpan segmentStartOffset)
        {
            double decibelThreshold   = lbConfig.DecibelThreshold; //dB
            double intensityThreshold = lbConfig.IntensityThreshold;

            //double eventThreshold = lbConfig.EventThreshold; //in 0-1

            if (recording == null)
            {
                LoggedConsole.WriteLine("AudioRecording == null. Analysis not possible.");
                return(null);
            }

            //i: MAKE SONOGRAM
            //TimeSpan tsRecordingtDuration = recording.Duration();
            int    sr              = recording.SampleRate;
            double freqBinWidth    = sr / (double)sonoConfig.WindowSize;
            double framesPerSecond = freqBinWidth;

            // duration of DCT in seconds - want it to be about 3X or 4X the expected maximum period
            double dctDuration = 3 * lbConfig.MaxPeriod;

            // duration of DCT in frames
            int dctLength = (int)Math.Round(framesPerSecond * dctDuration);

            // set up the cosine coefficients
            double[,] cosines = MFCCStuff.Cosines(dctLength, dctLength);

            int upperBandMinBin = (int)Math.Round(lbConfig.UpperBandMinHz / freqBinWidth) + 1;
            int upperBandMaxBin = (int)Math.Round(lbConfig.UpperBandMaxHz / freqBinWidth) + 1;
            int lowerBandMinBin = (int)Math.Round(lbConfig.LowerBandMinHz / freqBinWidth) + 1;
            int lowerBandMaxBin = (int)Math.Round(lbConfig.LowerBandMaxHz / freqBinWidth) + 1;

            BaseSonogram sonogram = new SpectrogramStandard(sonoConfig, recording.WavReader);
            int          rowCount = sonogram.Data.GetLength(0);
            int          colCount = sonogram.Data.GetLength(1);

            double[] lowerArray = MatrixTools.GetRowAveragesOfSubmatrix(sonogram.Data, 0, lowerBandMinBin, rowCount - 1, lowerBandMaxBin);
            double[] upperArray = MatrixTools.GetRowAveragesOfSubmatrix(sonogram.Data, 0, upperBandMinBin, rowCount - 1, upperBandMaxBin);

            //lowerArray = DataTools.filterMovingAverage(lowerArray, 3);
            //upperArray = DataTools.filterMovingAverage(upperArray, 3);

            double[] amplitudeScores  = DataTools.SumMinusDifference(lowerArray, upperArray);
            double[] differenceScores = DspFilters.PreEmphasis(amplitudeScores, 1.0);

            // Could smooth here rather than above. Above seemed slightly better?
            amplitudeScores  = DataTools.filterMovingAverage(amplitudeScores, 7);
            differenceScores = DataTools.filterMovingAverage(differenceScores, 7);

            //iii: CONVERT decibel sum-diff SCORES TO ACOUSTIC EVENTS
            var predictedEvents = AcousticEvent.ConvertScoreArray2Events(
                amplitudeScores,
                lbConfig.LowerBandMinHz,
                lbConfig.UpperBandMaxHz,
                sonogram.FramesPerSecond,
                freqBinWidth,
                decibelThreshold,
                lbConfig.MinDuration,
                lbConfig.MaxDuration,
                segmentStartOffset);

            for (int i = 0; i < differenceScores.Length; i++)
            {
                if (differenceScores[i] < 1.0)
                {
                    differenceScores[i] = 0.0;
                }
            }

            // init the score array
            double[] scores = new double[rowCount];

            //iii: CONVERT SCORES TO ACOUSTIC EVENTS
            // var hits = new double[rowCount, colCount];
            double[,] hits = null;

            // init confirmed events
            var confirmedEvents = new List <AcousticEvent>();

            // add names into the returned events
            foreach (var ae in predictedEvents)
            {
                //rowtop,  rowWidth
                int    eventStart       = ae.Oblong.RowTop;
                int    eventWidth       = ae.Oblong.RowWidth;
                int    step             = 2;
                double maximumIntensity = 0.0;

                // scan the event to get oscillation period and intensity
                for (int i = eventStart - (dctLength / 2); i < eventStart + eventWidth - (dctLength / 2); i += step)
                {
                    // Look for oscillations in the difference array
                    double[] differenceArray = DataTools.Subarray(differenceScores, i, dctLength);
                    Oscillations2014.GetOscillationUsingDct(differenceArray, framesPerSecond, cosines, out var oscilFreq, out var period, out var intensity);

                    bool periodWithinBounds = period > lbConfig.MinPeriod && period < lbConfig.MaxPeriod;

                    //Console.WriteLine($"step={i}    period={period:f4}");

                    if (!periodWithinBounds)
                    {
                        continue;
                    }

                    // lay down score for sample length
                    for (int j = 0; j < dctLength; j++)
                    {
                        if (scores[i + j] < intensity)
                        {
                            scores[i + j] = intensity;
                        }
                    }

                    if (maximumIntensity < intensity)
                    {
                        maximumIntensity = intensity;
                    }
                }

                // add abbreviatedSpeciesName into event
                if (maximumIntensity >= intensityThreshold)
                {
                    ae.Name             = "L.b";
                    ae.Score_MaxInEvent = maximumIntensity;
                    confirmedEvents.Add(ae);
                }
            }

            //######################################################################

            // calculate the cosine similarity scores
            var scorePlot = new Plot(lbConfig.SpeciesName, scores, intensityThreshold);

            //DEBUG IMAGE this recognizer only. MUST set false for deployment.
            Image debugImage = null;

            if (drawDebugImage)
            {
                // display a variety of debug score arrays

                //DataTools.Normalise(scores, eventDecibelThreshold, out normalisedScores, out normalisedThreshold);
                //var debugPlot = new Plot("Score", normalisedScores, normalisedThreshold);
                //DataTools.Normalise(upperArray, eventDecibelThreshold, out normalisedScores, out normalisedThreshold);
                //var upperPlot = new Plot("Upper", normalisedScores, normalisedThreshold);
                //DataTools.Normalise(lowerArray, eventDecibelThreshold, out normalisedScores, out normalisedThreshold);
                //var lowerPlot = new Plot("Lower", normalisedScores, normalisedThreshold);
                DataTools.Normalise(amplitudeScores, decibelThreshold, out var normalisedScores, out var normalisedThreshold);
                var sumDiffPlot = new Plot("SumMinusDifference", normalisedScores, normalisedThreshold);
                DataTools.Normalise(differenceScores, 3.0, out normalisedScores, out normalisedThreshold);
                var differencePlot = new Plot("Difference", normalisedScores, normalisedThreshold);

                var debugPlots = new List <Plot> {
                    scorePlot, sumDiffPlot, differencePlot
                };

                // other debug plots
                //var debugPlots = new List<Plot> { scorePlot, upperPlot, lowerPlot, sumDiffPlot, differencePlot };
                debugImage = DisplayDebugImage(sonogram, confirmedEvents, debugPlots, hits);
            }

            // return new sonogram because it makes for more easy interpretation of the image
            var returnSonoConfig = new SonogramConfig
            {
                SourceFName   = recording.BaseName,
                WindowSize    = 512,
                WindowOverlap = 0,

                // the default window is HAMMING
                //WindowFunction = WindowFunctions.HANNING.ToString(),
                //WindowFunction = WindowFunctions.NONE.ToString(),
                // if do not use noise reduction can get a more sensitive recogniser.
                //NoiseReductionType = NoiseReductionType.NONE,
                NoiseReductionType = SNR.KeyToNoiseReductionType("STANDARD"),
            };
            BaseSonogram returnSonogram = new SpectrogramStandard(returnSonoConfig, recording.WavReader);

            return(Tuple.Create(returnSonogram, hits, scores, confirmedEvents, debugImage));
        } //Analysis()
예제 #23
0
        public bool plantData()
        {
            bool   result;
            bool   found = false;
            string input;

            Console.WriteLine("Seleccione la parcela: ");
            printPlots();
            input = Console.ReadLine();
            stringValidate.Value = input;
            result = stringValidate.ValidateField();

            plotList.ForEach(newPlot =>
            {
                if (!(found))
                {
                    found = newPlot.id == input;
                    if (found)
                    {
                        argPlot = newPlot;
                    }
                }
            });

            if (argPlot.planted != null)
            {
                Console.WriteLine("Ya hay algo plantado en esta parcela");
                return(false);
            }

            if (result && found)
            {
                found = false;
                Console.WriteLine("Seleccione el robot: ");
                printRobots();
                input = Console.ReadLine();
                stringValidate.Value = input;
                result = result && stringValidate.ValidateField();

                robotList.ForEach(newRobot =>
                {
                    if (!(found))
                    {
                        found = newRobot.id == input;
                        if (found)
                        {
                            argRobot = newRobot;
                        }
                    }
                });

                if (result && found)
                {
                    if (!argRobot.enabled)
                    {
                        Console.WriteLine("Este robot no esta habilitado");
                        result = false;
                    }
                    else if (argRobot.battery < 1)
                    {
                        Console.WriteLine("Este robot no tiene bateria");
                        result = false;
                    }
                    else
                    {
                        found = false;
                        Console.WriteLine("Seleccione el cultivo: ");
                        printInventory();
                        input = Console.ReadLine();
                        stringValidate.Value = input;
                        result = result && stringValidate.ValidateField();

                        foreach (KeyValuePair <Crop, int[]> kvp in cropList)
                        {
                            if (!found)
                            {
                                found = kvp.Key.name == input;
                                if (found)
                                {
                                    argCrop = kvp.Key;
                                    kvp.Value[1]--;
                                }
                            }
                        }

                        if (!found)
                        {
                            Console.WriteLine("Cultivo no encontrado");
                            result = false;
                        }
                    }
                }
                else
                {
                    Console.WriteLine("Robot no encontrado");
                    result = false;
                }
            }
            else
            {
                Console.WriteLine("Parcela no encontrada");
                result = false;
            }
            return(result);
        }
예제 #24
0
            public void Render(Plot plt)
            {
                // create some sample data to represent test scores.
                Random rand = new Random(0);

                // Each class (A, B, C) is a series.
                // Each semester (fall, spring, summer A, summer B) is a group.

                double[] scoresAfall = DataGen.RandomNormal(rand, 35, 85, 5);
                double[] scoresBfall = DataGen.RandomNormal(rand, 42, 87, 5);
                double[] scoresCfall = DataGen.RandomNormal(rand, 23, 82, 5);

                double[] scoresAspring = DataGen.RandomNormal(rand, 35, 84, 3);
                double[] scoresBspring = DataGen.RandomNormal(rand, 42, 88, 3);
                double[] scoresCspring = DataGen.RandomNormal(rand, 23, 84, 3);

                double[] scoresAsumA = DataGen.RandomNormal(rand, 35, 80, 5);
                double[] scoresBsumA = DataGen.RandomNormal(rand, 42, 90, 5);
                double[] scoresCsumA = DataGen.RandomNormal(rand, 23, 85, 5);

                double[] scoresAsumB = DataGen.RandomNormal(rand, 35, 91, 2);
                double[] scoresBsumB = DataGen.RandomNormal(rand, 42, 93, 2);
                double[] scoresCsumB = DataGen.RandomNormal(rand, 23, 90, 2);

                // Collect multiple populations into a PopulationSeries.
                // All populations in a series will be styled the same and appear once in the legend.

                var popsA = new Statistics.Population[] {
                    new Statistics.Population(scoresAfall),
                    new Statistics.Population(scoresAspring),
                    new Statistics.Population(scoresAsumA),
                    new Statistics.Population(scoresAsumB)
                };

                var popsB = new Statistics.Population[] {
                    new Statistics.Population(scoresBfall),
                    new Statistics.Population(scoresBspring),
                    new Statistics.Population(scoresBsumA),
                    new Statistics.Population(scoresBsumB)
                };

                var popsC = new Statistics.Population[] {
                    new Statistics.Population(scoresCfall),
                    new Statistics.Population(scoresCspring),
                    new Statistics.Population(scoresCsumA),
                    new Statistics.Population(scoresCsumB)
                };

                var seriesA   = new Statistics.PopulationSeries(popsA, "Class A");
                var seriesB   = new Statistics.PopulationSeries(popsB, "Class B");
                var seriesC   = new Statistics.PopulationSeries(popsC, "Class C");
                var allSeries = new Statistics.PopulationSeries[] { seriesA, seriesB, seriesC };

                // create a MultiSeries from multiple population series and plot it
                var multiSeries = new Statistics.PopulationMultiSeries(allSeries);

                plt.PlotPopulations(multiSeries);

                // improve the style of the plot
                plt.Title($"Test Scores by Class");
                plt.YLabel("Score");
                plt.XTicks(new string[] { "Fall", "Spring", "Summer A", "Summer B" });
                plt.Legend();
                plt.Grid(lineStyle: LineStyle.Dot, enableVertical: false);
            }
예제 #25
0
        public bool gatherData()
        {
            bool   result;
            bool   found = false;
            string input;

            Console.WriteLine("Seleccione la parcela: ");
            printPlots();
            input = Console.ReadLine();
            stringValidate.Value = input;
            result = stringValidate.ValidateField();

            plotList.ForEach(newPlot =>
            {
                if (!(found))
                {
                    found = newPlot.id == input;
                    if (found)
                    {
                        argPlot = newPlot;
                    }
                }
            });

            if (argPlot.planted == null)
            {
                Console.WriteLine("No hay nada plantado en esta parcela");
                return(false);
            }

            if (!(argPlot.timePassed >= argPlot.planted.timeNeeded))
            {
                Console.WriteLine("Esta parcela no esta lista para recolectar");
                result = false;
            }

            if (result && found)
            {
                found = false;
                Console.WriteLine("Seleccione el robot: ");
                printRobots();
                input = Console.ReadLine();
                stringValidate.Value = input;
                result = result && stringValidate.ValidateField();

                robotList.ForEach(newRobot =>
                {
                    if (!(found))
                    {
                        found = newRobot.id == input;
                        if (found)
                        {
                            argRobot = newRobot;
                        }
                    }
                });

                if (result && found)
                {
                    if (!argRobot.enabled)
                    {
                        Console.WriteLine("Este robot no esta habilitado");
                        result = false;
                    }
                    else if (argRobot.battery < 1)
                    {
                        Console.WriteLine("Este robot no tiene bateria");
                        result = false;
                    }
                    else
                    {
                        cropList[argPlot.planted][0]++;
                        cropList[argPlot.planted][1]++;
                    }
                }
                else
                {
                    Console.WriteLine("Robot no encontrado");
                    result = false;
                }
            }
            else
            {
                Console.WriteLine("Parcela no encontrada");
                result = false;
            }
            return(result);
        }
예제 #26
0
파일: GDI.cs 프로젝트: zyhong/QuickPlot
        private static Settings.PlotLayout LayOut(Graphics gfx, Rectangle rect, Plot plt)
        {
            // create a layout for this plot
            Settings.PlotLayout layout = new Settings.PlotLayout(rect);

            // adjust the layout components based on:
            //  - whether they are null
            //  - how large things are

            if (plt.axes.labelTitle.IsValid)
            {
                SizeF labelSize = MeasureString(gfx, plt.axes.labelTitle);
                layout.title.Match(layout.plotArea);
                layout.title.ShrinkTo(top: (int)labelSize.Height);
            }

            if (plt.axes.labelX.IsValid)
            {
                SizeF labelSize = MeasureString(gfx, plt.axes.labelX);
                layout.labelX.Match(layout.plotArea);
                layout.labelX.ShrinkTo(bottom: (int)labelSize.Height);
            }

            if (plt.axes.labelY.IsValid)
            {
                SizeF labelSize = MeasureString(gfx, plt.axes.labelY);
                layout.labelY.Match(layout.plotArea);
                layout.labelY.ShrinkTo(left: (int)labelSize.Height);
            }

            if (plt.axes.labelY2.IsValid)
            {
                SizeF labelSize = MeasureString(gfx, plt.axes.labelY2);
                layout.labelY2.Match(layout.plotArea);
                layout.labelY2.ShrinkTo(right: (int)labelSize.Height);
            }

            if (plt.axes.enableX)
            {
                int scaleFontHeight = 20;
                layout.scaleX.Match(layout.plotArea);
                layout.scaleX.ShrinkTo(bottom: scaleFontHeight);
                layout.scaleX.Shift(up: layout.labelX.Height);
            }

            if (plt.axes.enableY)
            {
                int widestScaleTick = 35;
                layout.scaleY.Match(layout.plotArea);
                layout.scaleY.ShrinkTo(left: widestScaleTick);
                layout.scaleY.Shift(right: layout.labelY.Width);
            }

            if (plt.axes.enableY2)
            {
                int widestScaleTick = 35;
                layout.scaleY2.Match(layout.plotArea);
                layout.scaleY2.ShrinkTo(right: widestScaleTick);
                layout.scaleY2.Shift(left: layout.labelY2.Width);
            }

            layout.data.Match(layout.plotArea);
            layout.data.ShrinkBy(
                left: layout.labelY.Width + layout.scaleY.Width,
                right: layout.labelY2.Width + layout.scaleY2.Width,
                bottom: layout.labelX.Height + layout.scaleX.Height,
                top: layout.title.Height);
            layout.scaleY.Shift(left: 1);

            layout.ShrinkToRemoveOverlaps();

            return(layout);
        }
예제 #27
0
        public bool fixData()
        {
            bool   result;
            bool   found = false;
            string input;

            Console.WriteLine("Seleccione la parcela: ");
            printPlots();
            input = Console.ReadLine();
            stringValidate.Value = input;
            result = stringValidate.ValidateField();

            plotList.ForEach(newPlot =>
            {
                if (!(found))
                {
                    found = newPlot.id == input;
                    if (found)
                    {
                        argPlot = newPlot;
                    }
                }
            });

            if (!argPlot.tempProblem && !argPlot.plague)
            {
                Console.WriteLine("No hay ningun problema en esta parcela");
                result = false;
            }

            if (result && found)
            {
                found = false;
                Console.WriteLine("Seleccione el robot: ");
                printRobots();
                input = Console.ReadLine();
                stringValidate.Value = input;
                result = result && stringValidate.ValidateField();

                robotList.ForEach(newRobot =>
                {
                    if (!(found))
                    {
                        found = newRobot.id == input;
                        if (found)
                        {
                            argRobot = newRobot;
                        }
                    }
                });

                if (result && found)
                {
                    int batteryNeeded = (argPlot.plague ? 1 : 0) + (argPlot.tempProblem ? 1 : 0);
                    if (!argRobot.enabled)
                    {
                        Console.WriteLine("Este robot no esta habilitado");
                        result = false;
                    }
                    else if (argRobot.battery < batteryNeeded)
                    {
                        Console.WriteLine("Este robot no tiene bateria");
                        result = false;
                    }
                }
                else
                {
                    Console.WriteLine("Robot no encontrado");
                    result = false;
                }
            }
            else
            {
                Console.WriteLine("Parcela no encontrada");
                result = false;
            }
            return(result);
        }
예제 #28
0
        public WindowArchiveChart(List <string> colSelect, List <string> colTableName)
        {
            InitializeComponent();

            AppWPF app = (AppWPF)Application.Current;

            MainWindow window = (MainWindow)Application.Current.MainWindow;

            if (app.ConfigProgramBin.UseDatabase)
            {
                //SqlConnectionStringBuilder Sqlbuilder = new SqlConnectionStringBuilder();
                //Sqlbuilder.DataSource = app.ConfigProgramBin.SQLServerName;
                //Sqlbuilder.InitialCatalog = app.ConfigProgramBin.SQLDatabaseName;

                //if (((AppWPF)Application.Current).ConfigProgramBin.SQLSecuritySSPI)
                //{
                //    Sqlbuilder.IntegratedSecurity = true;
                //}
                //else
                //{
                //    Sqlbuilder.UserID = app.ConfigProgramBin.SQLUserName;
                //    Sqlbuilder.Password = app.ConfigProgramBin.SQLPassword;
                //}

                string connstring = String.Format("Server={0};Port={1};" +
                                                  "User Id={2};Password={3};Database={4};",
                                                  app.ConfigProgramBin.SQLServerName, 5432, app.ConfigProgramBin.SQLUserName,
                                                  app.ConfigProgramBin.SQLPassword, app.ConfigProgramBin.SQLDatabaseName);


                Npgsql.NpgsqlConnection conn = new Npgsql.NpgsqlConnection(connstring);

                try
                {
                    conn.Open();

                    PlotModel plotModel = new PlotModel();

                    if (colSelect.Count >= 2)
                    {
                        int count = 0;

                        while (true)
                        {
                            DataTable dataTable = new DataTable();

                            Npgsql.NpgsqlDataAdapter adapter = new Npgsql.NpgsqlDataAdapter(colSelect[count], conn);
                            adapter.Fill(dataTable);

                            adapter.Dispose();

                            OxyPlot.Series.LineSeries line = new OxyPlot.Series.LineSeries()
                            {
                                CanTrackerInterpolatePoints = false,
                                Title  = string.Format(colTableName[count]),
                                Smooth = false,
                                TrackerFormatString = "{0}" + Environment.NewLine + "{3} {4}" + Environment.NewLine + "{1} {2:dd/MM/yyyy HH:mm:ss}"
                            };

                            DataView data = dataTable.DefaultView;

                            foreach (DataRowView rowView in data)
                            {
                                DataRow row = rowView.Row;

                                DateTime dt = (DateTime)row.ItemArray[1];

                                double d = Convert.ToDouble(row.ItemArray[0]);

                                line.Points.Add(new DataPoint(OxyPlot.Axes.DateTimeAxis.ToDouble(dt), d));
                            }

                            plotModel.Series.Add(line);

                            count++;

                            if (count == colSelect.Count)
                            {
                                break;
                            }
                        }
                    }
                    else
                    {
                        DataTable dataTable = new DataTable();

                        Npgsql.NpgsqlDataAdapter adapter = new Npgsql.NpgsqlDataAdapter(colSelect[0], conn);
                        adapter.Fill(dataTable);

                        adapter.Dispose();

                        OxyPlot.Series.LineSeries line = new OxyPlot.Series.LineSeries()
                        {
                            CanTrackerInterpolatePoints = false,
                            Title  = string.Format(colTableName[0]),
                            Smooth = false,
                            TrackerFormatString = "{0}" + Environment.NewLine + "{3} {4}" + Environment.NewLine + "{1} {2:dd/MM/yyyy HH:mm:ss}"
                        };

                        DataView data = dataTable.DefaultView;

                        foreach (DataRowView rowView in data)
                        {
                            DataRow row = rowView.Row;

                            DateTime dt = (DateTime)row.ItemArray[1];

                            double d = Convert.ToDouble(row.ItemArray[0]);

                            line.Points.Add(new DataPoint(OxyPlot.Axes.DateTimeAxis.ToDouble(dt), d));
                        }

                        plotModel.Series.Add(line);
                    }

                    plotModel.LegendTitle       = "Легенда";
                    plotModel.LegendOrientation = LegendOrientation.Horizontal;
                    plotModel.LegendPlacement   = LegendPlacement.Outside;
                    plotModel.LegendPosition    = LegendPosition.TopRight;
                    plotModel.LegendBackground  = OxyColor.FromAColor(200, OxyColors.White);
                    plotModel.LegendBorder      = OxyColors.Black;

                    var dateAxis = new OxyPlot.Axes.DateTimeAxis(OxyPlot.Axes.AxisPosition.Bottom, "Дата", "dd/MM HH:mm")
                    {
                        MajorGridlineStyle = LineStyle.Solid, MinorGridlineStyle = LineStyle.Solid, IntervalLength = 65
                    };
                    plotModel.Axes.Add(dateAxis);
                    var valueAxis = new OxyPlot.Axes.LinearAxis(AxisPosition.Left)
                    {
                        MajorGridlineStyle = LineStyle.Solid, MinorGridlineStyle = LineStyle.Solid, Title = "Значение"
                    };
                    valueAxis.MaximumPadding = 0.3;
                    valueAxis.MinimumPadding = 0.3;
                    plotModel.Axes.Add(valueAxis);

                    Plot = new Plot();
                    Plot.SetValue(Grid.RowProperty, 1);
                    Plot.Model     = plotModel;
                    Plot.MinHeight = 100;
                    Plot.MinWidth  = 100;

                    GridMain.Children.Add(Plot);
                }
                catch (SystemException ex)
                {
                    if (window.CollectionMessage.Count > 300)
                    {
                        window.CollectionMessage.RemoveAt(0);

                        window.CollectionMessage.Insert(298, "Сообщение " + " : " + "Ошибка в окне Архива " + ex.Message + "  " + DateTime.Now);
                    }
                    else
                    {
                        window.CollectionMessage.Add("Сообщение " + " : " + "Ошибка в окне Архива " + ex.Message + "  " + DateTime.Now);
                    }

                    //if (ex is SqlException)
                    //{
                    //    SqlException sqlex = ex as SqlException;

                    //    foreach (SqlError er in sqlex.Errors)
                    //    {
                    //        if (window.WindowErrorMessages.LBMessageError.Text.Length > 0)
                    //        {
                    //            window.CountLineTextMessage++;
                    //            window.WindowErrorMessages.LBMessageError.Text += "\n" + "Сообщение " + window.CountLineTextMessage.ToString() + " : " + "Ошибка в окне Архива " + er.Message + "  " + DateTime.Now;
                    //        }
                    //        else
                    //        {
                    //            window.CountLineTextMessage++;
                    //            window.WindowErrorMessages.LBMessageError.Text = "Сообщение " + window.CountLineTextMessage.ToString() + " : " + "Ошибка в окне Архива " + er.Message + "  " + DateTime.Now;
                    //        }
                    //    }
                    //}
                }
                finally
                {
                    conn.Close();
                    conn.Dispose();
                }
            }
        }
예제 #29
0
 // Input: (time, strain) data points, one for each hit object
 // TODO: Optimize plot rendering:
 // When playing, only plot data in the interval [gameTime-windowSize, gameTime]
 // On pause, plot all data.
 public void InitAimStrainMeter(Plot aimStrainMeter)
 {
     aimStrainMeter.Frame(false);
     aimStrainMeter.Style(Style.Blue2);
 }
예제 #30
0
 public void ExecuteRecipe(Plot plt)
 {
     int[] data = { 2, 6, 3, 8, 5, 6, 1, 9, 7 };
     plt.AddSignalConst(data);
     plt.Title("SignalConst Displaying int[] Data");
 }
예제 #31
0
        public void PlotSortedPeaks(Plot sortedPeaksPlot, List <double> aimStrainPeakTimes, List <double> aimStrainPeaks, double gameTime)
        {
            // Mark 7 (50%), 22 (90%), and 28 (95%)
            sortedPeaksPlot.PlotVLine(7.5, color: Color.FromArgb(255, 121, 198), lineStyle: LineStyle.Dot);
            sortedPeaksPlot.PlotVLine(22.5, color: Color.FromArgb(255, 121, 198), lineStyle: LineStyle.Dot);
            sortedPeaksPlot.PlotVLine(28.5, color: Color.FromArgb(255, 121, 198), lineStyle: LineStyle.Dot);

            // get all aim strains before gameTime, limit view to only the first PEAKS_TO_DISPLAY peaks
            var sortedPeaks = Enumerable.Zip(aimStrainPeakTimes, aimStrainPeaks, (time, value) => (time, value))
                              .Where(peak => peak.time < gameTime)
                              .OrderBy(peak => peak.value)
                              .Reverse();
            var allRanks    = Enumerable.Range(0, sortedPeaks.Count()).Select(x => (double)x).ToArray();
            var rankedPeaks = sortedPeaks.Zip(allRanks, (p, rank) => (rank, p.time, p.value))
                              .Where(p => p.rank <= PEAKS_TO_DISPLAY);
            var limitedRanks = rankedPeaks.Select(p => p.rank).ToArray();

            // Plot old peaks
            var oldPeaks = rankedPeaks.Where(p => gameTime > p.time + OLD_THRESHOLD);

            if (oldPeaks.Count() > 0)
            {
                sortedPeaksPlot.PlotBar(
                    oldPeaks.Select(p => p.rank).ToArray(),
                    oldPeaks.Select(p => Math.Round(p.value)).ToArray(),
                    barWidth: 0.95,
                    fillColor: Color.FromArgb(70, 189, 147, 249),
                    outlineWidth: 0
                    );
            }

            // Plot recent peaks
            var newPeaks = rankedPeaks.Where(p => gameTime <= p.time + OLD_THRESHOLD);

            foreach ((double rank, double time, double value) in newPeaks)
            {
                var progress     = (gameTime - time) / OLD_THRESHOLD;
                int transparency = (int)(255 - progress * (255 - 70));
                sortedPeaksPlot.PlotBar(
                    new double[] { rank },
                    new double[] { Math.Round(value) },
                    barWidth: 0.95,
                    fillColor: Color.FromArgb(transparency, 189, 147, 249),
                    outlineWidth: 0
                    );
            }
            LastSortedPeaksPlotContainedNewPeaks = newPeaks.Count() > 0;

            // Plot weighted peaks
            var weightedPeaks = rankedPeaks
                                .Select(p => p.value * Math.Pow(0.90, p.rank))
                                .Select(x => Math.Round(x))
                                .ToArray();

            if (weightedPeaks.Length > 0)
            {
                sortedPeaksPlot.PlotBar(
                    limitedRanks,
                    weightedPeaks,
                    barWidth: 0.95,
                    fillColor: Color.FromArgb(70, 189, 147, 249),
                    outlineWidth: 0
                    );
            }
            //sortedPeaksPlot.AxisAuto(xExpandOnly: true, yExpandOnly: true);
            sortedPeaksPlot.Axis(x1: -0.5, x2: PEAKS_TO_DISPLAY + 0.5, y1: 0, y2: aimStrainPeaks.Max());
        }
예제 #32
0
파일: Program.cs 프로젝트: pivovard/ZCU
 static void Main(string[] args)
 {
     Plot plot = new Plot();
     plot.Vypocet(Vypocet, true);
     Console.ReadLine();
 }
예제 #33
0
파일: light5.cs 프로젝트: huangw10/ggj
 void Start()
 {
     useri     = userinterface.GetComponent <UI>();
     smallplot = mainplot.GetComponent <Plot>();
 }
예제 #34
0
        //-----metoda pro nakresleni a vytvoreni hraciho planu
        private void VytvorMapu(int sirka,int vyska)
        {
            int rozmer = Program.sizeOfSquare;

            //-----vytvoreni PictureBoxu
            Bitmap bmp = new Bitmap(sirka * rozmer, vyska * rozmer);
            pictureBox1.Image = bmp;
            pictureBox1.Size = bmp.Size;
            Graphics gr = Graphics.FromImage(bmp);

            //-----nakresleni mrizky-------------
            Pen pero = new Pen(Color.DarkSeaGreen, 1);
            for (int i = 0; i <= vyska; i++)
            {
                gr.DrawLine(pero, 0, i * rozmer, sirka * rozmer, i * rozmer);
            }
            for (int i = 0; i <= sirka; i++)
            {
                gr.DrawLine(pero, i * rozmer, 0, i * rozmer, vyska * rozmer);
            }

            pictureBox1.Refresh();//musime provest, pokud se zmenila bitmapa a zmenu chceme videt na obrazovce

            //stavba plotu a brany
            plot = new Plot(this);
            brana = new Brana(this);
        }
예제 #35
0
 public void Attach(Window owner, Plot plot)
 {
     this.Owner = owner;
     this.Plot = plot;
 }