/// <summary> /// Method for computing inverse cepstrum /// </summary> /// <param name="cepstrum"></param> /// <param name="samples"></param> /// <param name="power"></param> /// <returns></returns> public void Inverse(float[] cepstrum, float[] samples, bool power = false) { Guard.AgainstInequality(cepstrum.Length, _realSpectrum.Length, "Cepstrum length", "Size of FFT"); for (var i = 0; i < _realSpectrum.Length; i++) { _realSpectrum[i] = cepstrum[i]; _imagSpectrum[i] = 0.0f; } if (power) { for (var i = 0; i < _realSpectrum.Length; i++) { _realSpectrum[i] = (float)Math.Sqrt(_realSpectrum[i]) * _realSpectrum.Length; } } // FFT _fft.Direct(_realSpectrum, _imagSpectrum); // Pow ("inverse" logarithm) for (var i = 0; i < _realSpectrum.Length; i++) { samples[i] = (float)Math.Sqrt(Math.Pow(_realSpectrum[i], 10)); _imagSpectrum[i] = 0.0f; } // IFFT _fft.Inverse(samples, _imagSpectrum); }
/// <summary> /// Compute complex analytic signal, single precision /// </summary> /// <param name="samples">Array of samples</param> /// <param name="norm">Normalize by fft size</param> /// <returns>Complex analytic signal</returns> public Tuple <float[], float[]> AnalyticSignal(float[] samples, bool norm = true) { var sre = new DiscreteSignal(1, samples, allocateNew: true); var sim = new DiscreteSignal(1, samples.Length); var re = sre.Samples; var im = sim.Samples; _fft32.Direct(re, im); for (var i = 1; i < re.Length / 2; i++) { re[i] *= 2; im[i] *= 2; } for (var i = re.Length / 2 + 1; i < re.Length; i++) { re[i] = 0.0f; im[i] = 0.0f; } _fft32.Inverse(re, im); if (norm) { sre.Attenuate(re.Length); sim.Attenuate(im.Length); } return(new Tuple <float[], float[]>(re, im)); }
/// <summary> /// Direct Fast Mellin Transform /// </summary> /// <param name="input"></param> /// <param name="outputRe"></param> /// <param name="outputIm"></param> /// <param name="normalize"></param> public void Direct(float[] input, float[] outputRe, float[] outputIm, bool normalize = true) { MathUtils.InterpolateLinear(_linScale, input, _expScale, outputRe); for (var i = 0; i < outputRe.Length; i++) { outputRe[i] *= (float)Math.Pow(_expScale[i], 0.5); outputIm[i] = 0; } _fft.Direct(outputRe, outputIm); if (!normalize) { return; } var norm = (float)(1 / Math.Sqrt(outputRe.Length)); for (var i = 0; i < outputRe.Length; i++) { outputRe[i] *= norm; outputIm[i] *= norm; } }
/// <summary> /// Does Fast Hilbert Transform. /// </summary> /// <param name="input">Input data</param> /// <param name="output">Output data</param> public void Direct(float[] input, float[] output) { // just here, for code brevity, use alias _im for output (i.e. it's not internal _im) var _im = output; Array.Clear(_re, 0, _re.Length); Array.Clear(_im, 0, _im.Length); input.FastCopyTo(_re, input.Length); _fft.Direct(_re, _im); for (var i = 1; i < _re.Length / 2; i++) { _re[i] *= 2; _im[i] *= 2; } for (var i = _re.Length / 2 + 1; i < _re.Length; i++) { _re[i] = 0.0f; _im[i] = 0.0f; } _fft.Inverse(_re, _im); }
/// <summary> /// Does Fast Hartley Transform in-place. /// </summary> /// <param name="re">Input/output data</param> public void Direct(float[] re) { Array.Clear(_im, 0, _im.Length); _fft.Direct(re, _im); for (var i = 0; i < re.Length; i++) { re[i] -= _im[i]; } }
/// <summary> /// Direct DCT-II via FFT /// </summary> /// <param name="input"></param> /// <param name="output"></param> public void Direct(float[] input, float[] output) { Array.Clear(output, 0, output.Length); for (int m = 0; m < _temp.Length / 2; m++) { _temp[m] = input[2 * m]; _temp[_temp.Length - 1 - m] = input[2 * m + 1]; } _fft.Direct(_temp, output); // mutiply by exp(-j * pi * n / 2N): int N = _fft.Size; for (int i = 0; i < N; i++) { output[i] = 2 * (float)(_temp[i] * Math.Cos(0.5 * Math.PI * i / N) - output[i] * Math.Sin(-0.5 * Math.PI * i / N)); } }
/// <summary> /// Method for computing real cepstrum from array of samples /// </summary> /// <param name="samples"></param> /// <param name="cepstrum"></param> /// <param name="power"></param> /// <returns></returns> public void Direct(float[] samples, float[] cepstrum, bool power = false) { samples.FastCopyTo(_realSpectrum, _realSpectrum.Length); Array.Clear(_imagSpectrum, 0, _imagSpectrum.Length); // complex fft _fft.Direct(_realSpectrum, _imagSpectrum); // logarithm of power spectrum for (var i = 0; i < _realSpectrum.Length; i++) { var ps = _realSpectrum[i] * _realSpectrum[i] + _imagSpectrum[i] * _imagSpectrum[i]; _realSpectrum[i] = (float)Math.Log10(ps + float.Epsilon); _imagSpectrum[i] = 0.0f; } // complex ifft _fft.Inverse(_realSpectrum, _imagSpectrum); // take truncated part if (power) { for (var i = 0; i < Size; i++) { cepstrum[i] = (_realSpectrum[i] * _realSpectrum[i] + _imagSpectrum[i] * _imagSpectrum[i]) / _realSpectrum.Length; } } else { _realSpectrum.FastCopyTo(cepstrum, Size); } }
public void Direct(float[] input, float[] output) { Array.Clear(output, 0, output.Length); var N = Size; // mutiply by exp(-j * pi * n / N): for (var m = 0; m < _temp.Length; m++) { var re = input[2 * m]; var im = input[N - 1 - 2 * m]; var cos = Math.Cos(Math.PI * m / N); var sin = Math.Sin(-Math.PI * m / N); _temp[m] = 2 * (float)(re * cos - im * sin); output[m] = 2 * (float)(re * sin + im * cos); } ; _fft.Direct(_temp, output); // mutiply by exp(-j * pi * (2n + 0.5) / 2N): for (var m = 0; m < _temp.Length; m++) { var re = _temp[m]; var im = output[m]; var cos = Math.Cos(0.5 * Math.PI * (2 * m + 0.5) / N); var sin = Math.Sin(-0.5 * Math.PI * (2 * m + 0.5) / N); _tempRe[m] = (float)(re * cos - im * sin); _tempIm[m] = (float)(re * sin + im * cos); } ; for (int m = 0, k = 0; m < N; m += 2, k++) { output[m] = _tempRe[k]; } for (int m = 1, k = (N - 2) / 2; m < N; m += 2, k--) { output[m] = -_tempIm[k]; } }
/// <summary> /// Method for computing direct STFT of a signal block. /// STFT (spectrogram) is essentially the list of spectra in time. /// </summary> /// <param name="samples">The samples of signal</param> /// <returns>STFT of the signal</returns> public List <Tuple <float[], float[]> > Direct(float[] samples) { var stft = new List <Tuple <float[], float[]> >(); for (var pos = 0; pos + _windowSize < samples.Length; pos += _hopSize) { var re = new float[_fftSize]; var im = new float[_fftSize]; samples.FastCopyTo(re, _windowSize, pos); if (_window != WindowTypes.Rectangular) { re.ApplyWindow(_windowSamples); } _fft.Direct(re, im); stft.Add(new Tuple <float[], float[]>(re, im)); } return(stft); }
/// <summary> /// Method for computing inverse cepstrum /// </summary> /// <param name="cepstrum"></param> /// <param name="samples"></param> /// <param name="power"></param> /// <returns></returns> public void Inverse(float[] cepstrum, float[] samples, bool power = false) { if (cepstrum.Length != _realSpectrum.Length) { throw new ArgumentException(""); } for (var i = 0; i < _realSpectrum.Length; i++) { _realSpectrum[i] = cepstrum[i]; _imagSpectrum[i] = 0.0f; } if (power) { for (var i = 0; i < _realSpectrum.Length; i++) { _realSpectrum[i] = (float)Math.Sqrt(_realSpectrum[i]) * _realSpectrum.Length; } } // FFT _fft.Direct(_realSpectrum, _imagSpectrum); // Pow ("inverse" logarithm) for (var i = 0; i < _realSpectrum.Length; i++) { samples[i] = (float)Math.Sqrt(Math.Pow(_realSpectrum[i], 10)); _imagSpectrum[i] = 0.0f; } // IFFT _fft.Inverse(samples, _imagSpectrum); }
/// <summary> /// Evaluates complex cepstrum as: /// <code> /// Real{IFFT(log(abs(FFT(x)) + unwrapped_phase))} /// </code> /// </summary> /// <param name="input">Input data</param> /// <param name="cepstrum">Complex cepstrum</param> /// <param name="normalize">Normalize cepstrum by FFT size</param> /// <returns>Circular delay (number of samples) added to <paramref name="input"/></returns> public double ComplexCepstrum(float[] input, float[] cepstrum, bool normalize = true) { Array.Clear(_re, 0, _re.Length); Array.Clear(_im, 0, _im.Length); input.FastCopyTo(_re, input.Length); // complex fft _fft.Direct(_re, _im); // complex logarithm of magnitude spectrum // the most difficult part is phase unwrapping which is slightly different from MathUtils.Unwrap var offset = 0.0; _unwrapped[0] = 0.0; var prevPhase = Math.Atan2(_im[0], _re[0]); for (var n = 1; n < _unwrapped.Length; n++) { var phase = Math.Atan2(_im[n], _re[n]); var delta = phase - prevPhase; if (delta > Math.PI) { offset -= 2 * Math.PI; } else if (delta < -Math.PI) { offset += 2 * Math.PI; } _unwrapped[n] = phase + offset; prevPhase = phase; } var mid = _re.Length / 2; var delay = Math.Round(_unwrapped[mid] / Math.PI); for (var i = 0; i < _re.Length; i++) { _unwrapped[i] -= Math.PI * delay * i / mid; var mag = Math.Sqrt(_re[i] * _re[i] + _im[i] * _im[i]); _re[i] = (float)Math.Log(mag + float.Epsilon, _logBase); _im[i] = (float)_unwrapped[i]; } // complex ifft _fft.Inverse(_re, _im); // take truncated part _re.FastCopyTo(cepstrum, Size); if (normalize) { for (var i = 0; i < cepstrum.Length; i++) { cepstrum[i] /= _fft.Size; } } return(delay); }