Exemplo n.º 1
0
            private void CalculateExpectedValueByFft(double[] data)
            {
                int length = data.Length;

                AllocateDoubleArray(ref _fftRe, length);
                AllocateDoubleArray(ref _fftIm, length);
                AllocateDoubleArray(ref _zeroArray, length);
                FftUtils.ComputeForwardFft(data, _zeroArray, _fftRe, _fftIm, length);

                for (int i = 0; i < length; ++i)
                {
                    if (i > (double)length * 3 / 8 && i < (double)length * 5 / 8)
                    {
                        _fftRe[i] = 0.0f;
                        _fftIm[i] = 0.0f;
                    }
                }

                AllocateDoubleArray(ref _ifftRe, length);
                AllocateDoubleArray(ref _ifftIm, length);
                FftUtils.ComputeBackwardFft(_fftRe, _fftIm, _ifftRe, _ifftIm, length);
            }
Exemplo n.º 2
0
            private void SpectralResidual(double[] values, double[][] results, double threshold)
            {
                // Step 1: Get backadd wave
                BackAdd(values);

                // Step 2: FFT transformation
                int length = _backAddArray.Length;

                AllocateDoubleArray(ref _fftRe, length);
                AllocateDoubleArray(ref _fftIm, length);

                AllocateDoubleArray(ref _zeroArray, length);
                FftUtils.ComputeForwardFft(_backAddArray, _zeroArray, _fftRe, _fftIm, length);

                // Step 3: Calculate mags of FFT
                AllocateDoubleArray(ref _magList, length);
                AllocateDoubleArray(ref _magLogList, length);
                for (int i = 0; i < length; ++i)
                {
                    _magList[i] = Math.Sqrt((Math.Pow(_fftRe[i], 2) + Math.Pow(_fftIm[i], 2)));
                    if (_magList[i] > _eps)
                    {
                        _magLogList[i] = Math.Log(_magList[i]);
                    }
                    else
                    {
                        _magLogList[i] = 0;
                    }
                }

                // Step 4: Calculate spectral
                AverageFilter(_magLogList, _averagingWindowSize);
                AllocateDoubleArray(ref _spectralList, length);
                for (int i = 0; i < length; ++i)
                {
                    _spectralList[i] = Math.Exp(_magLogList[i] - _cumSumList[i]);
                }

                // Step 5: IFFT transformation
                AllocateDoubleArray(ref _transRe, length);
                AllocateDoubleArray(ref _transIm, length);
                for (int i = 0; i < length; ++i)
                {
                    if (_magLogList[i] != 0)
                    {
                        _transRe[i] = _fftRe[i] * _spectralList[i] / _magList[i];
                        _transIm[i] = _fftIm[i] * _spectralList[i] / _magList[i];
                    }
                    else
                    {
                        _transRe[i] = 0;
                        _transIm[i] = 0;
                    }
                }

                AllocateDoubleArray(ref _ifftRe, length);
                AllocateDoubleArray(ref _ifftIm, length);
                FftUtils.ComputeBackwardFft(_transRe, _transIm, _ifftRe, _ifftIm, length);

                // Step 6: Calculate mag and ave_mag of IFFT
                AllocateDoubleArray(ref _ifftMagList, length);
                for (int i = 0; i < length; ++i)
                {
                    _ifftMagList[i] = Math.Sqrt((Math.Pow(_ifftRe[i], 2) + Math.Pow(_ifftIm[i], 2)));
                }
                AverageFilter(_ifftMagList, Math.Min(_ifftMagList.Length, _judgementWindowSize));

                // Step 7: Calculate raw score and set result
                for (int i = 0; i < results.GetLength(0); ++i)
                {
                    var score = CalculateScore(_ifftMagList[i], _cumSumList[i]);
                    score /= 10.0f;
                    score  = Math.Min(score, 1);
                    score  = Math.Max(score, 0);

                    var detres = score > threshold ? 1 : 0;

                    results[i][0] = detres;
                    results[i][1] = score;
                    results[i][2] = _ifftMagList[i];
                }
            }
        /// <summary>
        /// This method detects this predictable interval (or period) by adopting techniques of fourier analysis.
        /// Returns -1 if no such pattern is found, that is, the input values do not follow a seasonal fluctuation.
        /// </summary>
        /// <param name="host">The detect seasonality host environment.</param>
        /// <param name="input">Input DataView.The data is an instance of <see cref="Microsoft.ML.IDataView"/>.</param>
        /// <param name="inputColumnName">Name of column to process. The column data must be <see cref="System.Double"/>.</param>
        /// <param name="seasonalityWindowSize">An upper bound on the number of values to be considered in the input values.
        /// When set to -1, use the whole input to fit model; when set to a positive integer, use this number as batch size.
        /// Default value is -1.</param>
        /// <param name="randomessThreshold">Randomness threshold, ranging from [0, 1]. It specifies how confidence the input
        /// follows a predictable pattern recurring as seasonal data. By default, it is set as 0.95.
        /// </param>
        /// <returns>The detected period if seasonality period exists, otherwise return -1.</returns>
        public int DetectSeasonality(
            IHostEnvironment host,
            IDataView input,
            string inputColumnName,
            int seasonalityWindowSize,
            double randomessThreshold)
        {
            host.CheckValue(input, nameof(input));
            host.CheckValue(inputColumnName, nameof(inputColumnName));
            host.CheckUserArg(seasonalityWindowSize == -1 || seasonalityWindowSize >= 0, nameof(seasonalityWindowSize));

            var column = input.Schema.GetColumnOrNull(inputColumnName);

            host.CheckUserArg(column.HasValue, nameof(inputColumnName));

            var rowCursor = input.GetRowCursor(new List <DataViewSchema.Column>()
            {
                column.Value
            });
            var valueDelegate = rowCursor.GetGetter <double>(column.Value);

            int    length     = 0;
            double valueRef   = 0;
            var    valueCache = seasonalityWindowSize == -1 ? new List <double>() : new List <double>(seasonalityWindowSize);

            while (rowCursor.MoveNext())
            {
                valueDelegate.Invoke(ref valueRef);
                length++;
                valueCache.Add(valueRef);
                if (seasonalityWindowSize != -1 && length >= seasonalityWindowSize)
                {
                    break;
                }
            }

            double[] fftRe   = new double[length];
            double[] fftIm   = new double[length];
            double[] inputRe = valueCache.ToArray();

            FftUtils.ComputeForwardFft(inputRe, Enumerable.Repeat(0.0, length).ToArray(), fftRe, fftIm, length);

            var energies = fftRe.Select((m, i) => new Complex(m, fftIm[i])).ToArray();

            /* Periodogram indicates the square of "energy" on the  frequency domain.
             * Specifically, periodogram[j] = a[j]^2+b[j]^2, where a and b are Fourier Coefficients for cosine and sine,
             * x(t) = a0+sum(a[j]cos(2Pi * f[j]t)+b[j]sin(2Pi * f[j]t)
             */
            var periodogram = energies.Select((t, i) => t * Complex.Conjugate(t)).ToArray();

            FindBestTwoFrequencies(periodogram, length, out var bestFreq, out var secondFreq);

            double[] ifftRe = new double[length];
            double[] ifftIm = new double[length];
            FftUtils.ComputeBackwardFft(
                periodogram.Select(t => t.Real).ToArray(),
                periodogram.Select(t => t.Imaginary).ToArray(),
                ifftRe,
                ifftIm,
                length);
            var values = ifftRe.Select((t, i) => new Complex(t, ifftIm[i])).ToArray();

            int period = FindActualPeriod(values, bestFreq, secondFreq, length, randomessThreshold);

            return(period < 0 ? -1 : period);
        }