/// <summary> /// This function computes the the multiplication of the transpose of the trajectory matrix H by an arbitrary vector v, i.e. H' * v. /// Since the trajectory matrix is a Hankel matrix, using the Discrete Fourier Transform, /// the multiplication is carried out in O(N.log(N)) instead of O(N^2), wheere N is the series length. /// For details, refer to Algorithm 3 in http://arxiv.org/pdf/0911.4498.pdf. /// </summary> /// <param name="vector">The input vector</param> /// <param name="result">The output vector allocated by the caller</param> /// <param name="add">Whether the multiplication result should be added to the current value in result</param> /// <param name="srcIndex">The starting index for the vector argument</param> /// <param name="dstIndex">The starting index for the result</param> private void FftMultiplyTranspose(Single[] vector, Single[] result, bool add = false, int srcIndex = 0, int dstIndex = 0) { _ectx.Assert(srcIndex >= 0); _ectx.Assert(dstIndex >= 0); _ectx.Assert(Utils.Size(vector) >= _windowSize + srcIndex); _ectx.Assert(Utils.Size(result) >= _k + dstIndex); int i; // Computing the FFT of the trajectory matrix if (!_isSeriesFftCached) { CacheInputSeriesFft(); } // Computing the FFT of the input vector for (i = 0; i < _k - 1; ++i) { _inputRe[i] = 0; } for (i = _k - 1; i < _seriesLength; ++i) { _inputRe[i] = vector[_seriesLength - i - 1 + srcIndex]; } FftUtils.ComputeForwardFft(_inputRe, _allZerosIm, _outputRe, _outputIm, _inputRe.Length); // Computing the element-by-element product in the Fourier space double re; double im; for (i = 0; i < _seriesLength; ++i) { re = _outputRe[i]; im = _outputIm[i]; _outputRe[i] = _cachedSeriesFftRe[i] * re - _cachedSeriesFftIm[i] * im; _outputIm[i] = _cachedSeriesFftRe[i] * im + _cachedSeriesFftIm[i] * re; } // Computing the inverse FFT of the result FftUtils.ComputeBackwardFft(_outputRe, _outputIm, _outputRe, _outputIm, _inputRe.Length); // Generating the output if (add) { for (i = 0; i < _k; ++i) { result[i + dstIndex] += RoundUpToReal(_outputRe[_windowSize - 1 + i], _outputIm[_windowSize - 1 + i]); } } else { for (i = 0; i < _k; ++i) { result[i + dstIndex] = RoundUpToReal(_outputRe[_windowSize - 1 + i], _outputIm[_windowSize - 1 + i]); } } }
private protected override sealed void SpectralResidual(Single input, FixedSizeQueue <Single> data, ref VBufferEditor <double> result) { // Step 1: Get backadd wave List <Single> backAddList = BackAdd(data); // Step 2: FFT transformation int length = backAddList.Count; float[] fftRe = new float[length]; float[] fftIm = new float[length]; FftUtils.ComputeForwardFft(backAddList.ToArray(), Enumerable.Repeat(0.0f, length).ToArray(), fftRe, fftIm, length); // Step 3: Calculate mags of FFT List <Single> magList = new List <Single>(); for (int i = 0; i < length; ++i) { magList.Add(MathUtils.Sqrt((fftRe[i] * fftRe[i] + fftIm[i] * fftIm[i]))); } // Step 4: Calculate spectral List <Single> magLogList = magList.Select(x => x != 0 ? MathUtils.Log(x) : 0).ToList(); List <Single> filteredLogList = AverageFilter(magLogList, Parent.AvergingWindowSize); List <Single> spectralList = new List <Single>(); for (int i = 0; i < magLogList.Count; ++i) { spectralList.Add(MathUtils.ExpSlow(magLogList[i] - filteredLogList[i])); } // Step 5: IFFT transformation float[] transRe = new float[length]; float[] transIm = new float[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; } } float[] ifftRe = new float[length]; float[] ifftIm = new float[length]; FftUtils.ComputeBackwardFft(transRe, transIm, ifftRe, ifftIm, length); // Step 6: Calculate mag and ave_mag of IFFT List <Single> ifftMagList = new List <Single>(); for (int i = 0; i < length; ++i) { ifftMagList.Add(MathUtils.Sqrt((ifftRe[i] * ifftRe[i] + ifftIm[i] * ifftIm[i]))); } List <Single> filteredIfftMagList = AverageFilter(ifftMagList, Parent.JudgementWindowSize); // Step 7: Calculate score and set result var score = CalculateSocre(ifftMagList[data.Count - 1], filteredIfftMagList[data.Count - 1]); score /= 10.0f; result.Values[1] = score; score = Math.Min(score, 1); score = Math.Max(score, 0); var detres = score > Parent.AlertThreshold ? 1 : 0; result.Values[0] = detres; var mag = ifftMagList[data.Count - 1]; result.Values[2] = mag; }
/// <summary> /// This function computes the efficient Hankelization of the matrix sigma * u * v' using Fast Fourier Transform in in O((L + K) * log(L + K)). /// For details, refer to Algorithm 4 in http://arxiv.org/pdf/0911.4498.pdf. /// </summary> /// <param name="u">The u vector</param> /// <param name="v">The v vector</param> /// <param name="sigma">The scalar coefficient</param> /// <param name="result">The output series</param> /// <param name="add">Whether the hankelization result should be added to the current value in result</param> /// <param name="uIndex">The starting index for the u vector argument</param> /// <param name="vIndex">The starting index for the v vector argument</param> /// <param name="dstIndex">The starting index for the result</param> /// <param name="start">The staring index of the series to be reconstructed (by default zero)</param> /// <param name="end">The ending index of the series to be reconstructed (by default series length)</param> private void FftRankOneHankelization(Single[] u, Single[] v, Single sigma, Single[] result, bool add = false, int uIndex = 0, int vIndex = 0, int dstIndex = 0, int?start = null, int?end = null) { int s; int e; int us; int ue; int vs; int ve; int i; s = start ?? 0; e = end ?? _seriesLength - 1; ComputeBoundryIndices(s, e, out us, out ue, out vs, out ve); _ectx.Assert(0 <= ue && ue < _windowSize); _ectx.Assert(0 <= us && us <= ue); _ectx.Assert(0 <= ve && ve < _k); _ectx.Assert(0 <= vs && vs <= ve); var len = e - s + 1; _ectx.Assert(uIndex >= 0); _ectx.Assert(vIndex >= 0); _ectx.Assert(dstIndex >= 0); _ectx.Assert(Utils.Size(u) >= _windowSize + uIndex); _ectx.Assert(Utils.Size(v) >= _k + vIndex); _ectx.Assert(Utils.Size(result) >= len + dstIndex); _ectx.Assert(!Single.IsNaN(sigma)); _ectx.Assert(!Single.IsInfinity(sigma)); if (!_isSeriesFftCached) { CacheInputSeriesFft(); } // Computing the FFT of u for (i = us; i <= ue; ++i) { _inputRe[i - us] = u[i + uIndex]; } for (i = ue + 1; i < len + us; ++i) { _inputRe[i - us] = 0; } FftUtils.ComputeForwardFft(_inputRe, _allZerosIm, _outputRe, _outputIm, len); // Computing the FFT of v for (i = vs; i <= ve; ++i) { _inputRe[i - vs] = v[i + vIndex]; } for (i = ve + 1; i < len + vs; ++i) { _inputRe[i - vs] = 0; } FftUtils.ComputeForwardFft(_inputRe, _allZerosIm, _inputRe, _allZerosIm, len); // Computing the element-by-element product in the Fourier space double re; double im; for (i = 0; i < len; ++i) { re = _outputRe[i]; im = _outputIm[i]; _outputRe[i] = _inputRe[i] * re - _allZerosIm[i] * im; _outputIm[i] = _inputRe[i] * im + _allZerosIm[i] * re; } // Setting _allZerosIm to 0's again for (i = 0; i < _seriesLength; ++i) { _allZerosIm[i] = 0; } // Computing the inverse FFT of the result FftUtils.ComputeBackwardFft(_outputRe, _outputIm, _outputRe, _outputIm, len); // Generating the output int a = Math.Min(ue - us + 1, ve - vs + 1); if (add) { for (i = 0; i < a; ++i) { result[i + dstIndex] += RoundUpToReal(_outputRe[i], _outputIm[i], sigma / (i + 1)); } for (i = a; i < len - a + 1; ++i) { result[i + dstIndex] += RoundUpToReal(_outputRe[i], _outputIm[i], sigma / a); } for (i = len - a + 1; i < len; ++i) { result[i + dstIndex] += RoundUpToReal(_outputRe[i], _outputIm[i], sigma / (len - i)); } } else { for (i = 0; i < a; ++i) { result[i + dstIndex] = RoundUpToReal(_outputRe[i], _outputIm[i], sigma / (i + 1)); } for (i = a; i < len - a + 1; ++i) { result[i + dstIndex] = RoundUpToReal(_outputRe[i], _outputIm[i], sigma / a); } for (i = len - a + 1; i < len; ++i) { result[i + dstIndex] = RoundUpToReal(_outputRe[i], _outputIm[i], sigma / (len - i)); } } }