protected override void _Initialize() { int fftBufferSize = _channelSamples.CeilingToPowerOfTwo(); fftBuffer = new Complex64[fftBufferSize]; sideBandAmplitudes.Clear(); double spectralModulatorTerm = -2.0 * Math.PI * spectralModulationRate / Math.Log(2.0); double spectralStartingPhase = 2.0 * Math.PI * randomizer.NextDouble(); foreach (ComplexCarrierTone carrierBaseTone in carrierToneGenerator) { foreach (ComplexCarrierTone sideBand in sideBandGenerator( modulationDepth: modulationDepth, carrierTone: carrierBaseTone, sidebandAmplitudeCache: sideBandAmplitudes, modulationRate: temporalModulationRate, spectralPhase: spectralStartingPhase + spectralModulatorTerm * Math.Log(carrierBaseTone.frequency))) { FrequencyDomain.Populate( buffer: fftBuffer, frequency: sideBand.frequency, amplitude: sideBand.amplitude); } } Fourier.Inverse(fftBuffer); }
public void PlotSignals() { Signal workbookSourceSignal = workBookManager.ActiveWorkBook().SumOfSources(); SignalWaveFile = null; PlotPoints = new List <DataPoint>(512); FrequencyViewModel = null; // Return empty set, this clears the display when all signals are off if (workbookSourceSignal == null) { NotifyPropertyChanged(nameof(PlotPoints)); NotifyPropertyChanged(nameof(FrequencyViewModel)); return; } CreateWavFile(workbookSourceSignal); for (int idx = 0; idx < workbookSourceSignal.Samples.Count; idx++) { PlotPoints.Add(new DataPoint(idx, workbookSourceSignal.Samples[idx])); } //IDFT cmplxFFT = new ComplexFastFourierTransform(); IDFT cmplxFFT = new DSPGuideComplexDiscreteFourierTransform(); FrequencyDomain frequencyDomain = cmplxFFT.Transform(workbookSourceSignal.Samples, workbookSourceSignal.SamplingHZ); FrequencyViewModel = new FrequencyHistogramViewModel(frequencyDomain); NotifyPropertyChanged(nameof(PlotPoints)); NotifyPropertyChanged(nameof(FrequencyViewModel)); }
protected override void _Initialize() { int fftBufferSize = _channelSamples.CeilingToPowerOfTwo(); fftBuffer = new Complex64[fftBufferSize]; foreach (ComplexCarrierTone carrierTone in CreateSideBands(freqLB, freqUB, frequencyCount, distribution)) { FrequencyDomain.Populate( buffer: fftBuffer, frequency: carrierTone.frequency, amplitude: carrierTone.amplitude); } Fourier.Inverse(fftBuffer); double currentRMS = 0.0; for (int i = 0; i < fftBufferSize; i++) { currentRMS += fftBuffer[i].Real * fftBuffer[i].Real; } currentRMS = Math.Sqrt(currentRMS / fftBufferSize); double factor = rms / currentRMS; for (int i = 0; i < fftBufferSize; i++) { fftBuffer[i] *= factor; } }
public ActionResult <FrequencyDomain> FFT([FromBody] List <Double> value) { ComplexFastFourierTransform fft = new ComplexFastFourierTransform(); FrequencyDomain transform = fft.Transform(value); return(Ok(transform)); }
private void ExportButton_Click(object sender, RoutedEventArgs e) { SaveFileDialog saveFileDialog = new SaveFileDialog(); saveFileDialog.Filter = $"{Properties.Resources.FILTER_IMPORT_EXPORT_FILE_EXTENSION} (*{Properties.Resources.FILTER_IMPORT_EXPORT_FILE_EXTENSION})|*{Properties.Resources.FILTER_IMPORT_EXPORT_FILE_EXTENSION}|{Properties.Resources.ALL_FILES} (*.*)|*.*"; if (saveFileDialog.ShowDialog() == true) { try { using (StreamWriter fileWriter = File.CreateText(saveFileDialog.FileName)) { fileWriter.WriteLine(Properties.Resources.FILTER_CSV_HEADER); List <double> summedFilterData = manager.ActiveWorkBook().CombinedFilterImpulseResponse(true); ComplexFastFourierTransform cmplxFFT = new ComplexFastFourierTransform(); FrequencyDomain frequencyDomain = cmplxFFT.Transform(summedFilterData, manager.ActiveWorkBook().WindowedSyncFilters.Values.First().FilterLength); var magPhaseList = ComplexFastFourierTransform.ToMagnitudePhaseList(frequencyDomain); foreach (Tuple <double, double> coefficientMagPhase in magPhaseList) { fileWriter.WriteLine($"{coefficientMagPhase.Item1},{coefficientMagPhase.Item2}"); } } } catch (Exception ex) { Log.Warning(ex, ex.Message); // TODO warn user } } }
/// <summary> /// Create a CustomFilter from a list of magnitudes and phases /// </summary> /// <param name="magPhaseList"></param> public CustomFilter(List <Tuple <double, double> > magPhaseList) { FreqDomain = new FrequencyDomain(); foreach (Tuple <double, double> magPhase in magPhaseList) { Complex coefficient = Complex.FromPolarCoordinates(magPhase.Item1, magPhase.Item2); FreqDomain.FourierCoefficients.Add(coefficient); } }
public override int Read(float[] data, int offset, int count) { int samplesWritten = ReadBody(data, offset, count); while (samplesWritten < count) { bufferIndex = 0; bufferCount = STEP_SIZE; //Clear IFFT Buffer Array.Clear(ifftBuffer, 0, ifftBuffer.Length); foreach (ComplexCarrierTone carrierTone in carrierTones) { FrequencyDomain.Populate( buffer: ifftBuffer, carrierTone: carrierTone.TimeShift(frame * timePerFrame)); } //IFFT Fourier.Inverse(ifftBuffer); //Accumualte the window samples for (int i = 0; i < FRAME_SIZE; i++) { outputAccumulation[i] += (float)(outputScalar * window[i] * ifftBuffer[i].Real); } //Advance Frame frame++; //Copy output samples to output buffer Array.Copy( sourceArray: outputAccumulation, destinationArray: cachedSampleBuffer, length: STEP_SIZE); //Slide down output accumulation Array.Copy( sourceArray: outputAccumulation, sourceIndex: STEP_SIZE, destinationArray: outputAccumulation, destinationIndex: 0, length: OVERLAP); //Clear empty output accumulation region Array.Clear( array: outputAccumulation, index: OVERLAP, length: STEP_SIZE); samplesWritten += ReadBody(data, offset + samplesWritten, count - samplesWritten); } return(count); }
/// <summary> /// Export the supplied frequency domain to the supplied outputStream /// Writes the frequency domain data as a CSV format of magnitude,phase for each entry /// Note this does not stamp the header on the data, callers should do that on the stream before calling this /// </summary> /// <param name="frequencyDomain">Frequency Domain to serialize</param> /// <param name="outputStream">Output stream to write data to</param> /// <returns></returns> public static async Task <bool> SerializeFrequencyDomain(FrequencyDomain frequencyDomain, StreamWriter outputStream) { bool success = true; foreach (Complex coefficient in frequencyDomain.FourierCoefficients) { await outputStream.WriteLineAsync($"{coefficient.Magnitude},{coefficient.Phase}"); } return(success); }
private IList <HistogramItem> GetFrequencyBins(FrequencyDomain frequencyDomain) { int binCount = (int)Math.Ceiling(frequencyDomain.SampleRateHz / 2); List <HistogramItem> histogramItems = new List <HistogramItem>(binCount); foreach (var amplitude in frequencyDomain.FrequencyAmplitudes) { HistogramItem item = new HistogramItem(amplitude.Key - 0.25, amplitude.Key + 0.25, amplitude.Value, 1); histogramItems.Add(item); } return(histogramItems); }
public void PlotData() { List <double> summedFilterData = manager.ActiveWorkBook().CombinedFilterImpulseResponse(); if (null == summedFilterData) { return; } Signal workbookSourceSignal = manager.ActiveWorkBook().SumOfSources(); if (workbookSourceSignal == null) { return; } SignalPlotPoints = new List <DataPoint>(workbookSourceSignal.Samples.Count); for (int idx = 0; idx < workbookSourceSignal.Samples.Count; idx++) { SignalPlotPoints.Add(new DataPoint(idx, workbookSourceSignal.Samples[idx])); } ConvolutionPlotPoints = new List <DataPoint>(summedFilterData.Count); for (int idx = 0; idx < summedFilterData.Count; idx++) { ConvolutionPlotPoints.Add(new DataPoint(idx, summedFilterData[idx])); } List <double> convolutionResult = convolver.Convolve(summedFilterData, workbookSourceSignal.Samples, ConvolutionType.INPUTSIDE); ResultPlotPoints = new List <DataPoint>(convolutionResult.Count); for (int idx = 0; idx < convolutionResult.Count; idx++) { ResultPlotPoints.Add(new DataPoint(idx, convolutionResult[idx])); } //IDFT cmplxFFT = new ComplexFastFourierTransform(); IDFT cmplxFFT = new DSPGuideComplexDiscreteFourierTransform(); FrequencyDomain frequencyDomain = cmplxFFT.Transform(convolutionResult, workbookSourceSignal.SamplingHZ); ResultFrequencyHistogram = new FrequencyHistogramViewModel(frequencyDomain); NotifyPropertyChanged(nameof(SignalPlotPoints)); NotifyPropertyChanged(nameof(ConvolutionPlotPoints)); NotifyPropertyChanged(nameof(ResultPlotPoints)); NotifyPropertyChanged(nameof(ResultFrequencyHistogram)); }
static void Main(string[] args) { // ISignalGenerator sinusoid = new Sinusoid(); // Sample sinusoidSamp = new Sample(1000, 1, 200, sinusoid); // List<double> signal = sinusoidSamp.GetNextSamplesForTimeSlice(64); // IDFT transform = new FastFourierTransform(); // FrequencyDomain frequencyDomain = transform.Transform(signal); // List<double> synthesis = transform.Synthesize(frequencyDomain); try { StreamReader input = new StreamReader(args[0]); List <double> signal = new List <double>(64); while (input.Peek() > 0) { double value; if (Double.TryParse(input.ReadLine(), out value)) { signal.Add(value); } } IDFT transform = new RealFastFourierTransform(); FrequencyDomain frequencyDomain = transform.Transform(signal); //List<double> synthesis = transform.Synthesize(frequencyDomain); FileStream output = new FileStream("FourierTransformResults.csv", FileMode.Create); if (output.CanWrite) { StreamWriter writer = new StreamWriter(output); // Write header row writer.WriteLine("Index, Signal, Synthesis, Real, Imaginary"); for (int idx = 0; idx < signal.Count; idx++) { double sampleVal = signal[idx]; double synthVal = 0.0f; writer.WriteLine(idx + "," + sampleVal + "," + synthVal + "," + frequencyDomain.RealComponent[idx] + "," + frequencyDomain.ImaginaryComponent[idx]); } writer.Close(); } output.Close(); } catch (Exception ex) { Console.WriteLine(ex.Message); } }
private unsafe void GenerateFrequencyDomainImages() { FFT.SwapQuadrants(FrequencyDomain); Bitmap magnitude = SpatialDomain.Clone(new Rectangle(0, 0, SpatialDomain.Width, SpatialDomain.Height), SpatialDomain.PixelFormat); Bitmap phase = SpatialDomain.Clone(new Rectangle(0, 0, SpatialDomain.Width, SpatialDomain.Height), SpatialDomain.PixelFormat); BitmapData bDataMagnitude = magnitude.LockBits(new Rectangle(0, 0, magnitude.Width, magnitude.Height), ImageLockMode.ReadWrite, magnitude.PixelFormat); byte * scan0Magnitude = (byte *)bDataMagnitude.Scan0.ToPointer(); BitmapData bDataPhase = phase.LockBits(new Rectangle(0, 0, phase.Width, phase.Height), ImageLockMode.ReadWrite, phase.PixelFormat); byte * scan0Phase = (byte *)bDataPhase.Scan0.ToPointer(); byte bitsPerPixel = ImageHelper.GetBitsPerPixel(bDataMagnitude.PixelFormat); List <double> phaseValues = new List <double>(); List <double> magnitudeValues = new List <double>(); for (int i = 0; i < FrequencyDomain.GetUpperBound(0) + 1; i++) { for (int j = 0; j < FrequencyDomain.GetUpperBound(1) + 1; j++) { phaseValues.Add(FrequencyDomain[i, j].Phase); magnitudeValues.Add(FrequencyDomain[i, j].Magnitude); } } double phaseMax = phaseValues.Max(); double magnitudeMax = magnitudeValues.Max(); for (int i = 0; i < bDataMagnitude.Height; ++i) { for (int j = 0; j < bDataMagnitude.Width; ++j) { byte *dataMagnitude = scan0Magnitude + i * bDataMagnitude.Stride + j * bitsPerPixel / 8; byte *dataPhase = scan0Phase + i * bDataPhase.Stride + j * bitsPerPixel / 8; dataMagnitude[0] = (byte)FFT.LogNormalize(FrequencyDomain[i, j].Magnitude, magnitudeMax, 255); dataPhase[0] = (byte)FFT.LogNormalize(FrequencyDomain[i, j].Phase, phaseMax, 255); } } magnitude.UnlockBits(bDataMagnitude); phase.UnlockBits(bDataPhase); MagnitudeImage = magnitude; PhaseImage = phase; FFT.SwapQuadrants(FrequencyDomain); }
public SpectralDecomp(double minFreq, double maxFreq, int windowSize, int windowCount) { fftMinFreqBin = FrequencyDomain.GetComplexFrequencyBin(windowSize, minFreq); //+2 to round outward AND to act as an exclusive upperbound fftMaxFreqBin = FrequencyDomain.GetComplexFrequencyBin(windowSize, maxFreq) + 2; fftMaxFreqBin = Math.Min(fftMaxFreqBin, windowSize / 2); spectralValues = new double[windowCount, fftMaxFreqBin - fftMinFreqBin]; freqs = new double[fftMaxFreqBin - fftMinFreqBin]; for (int i = 0; i < freqs.Length; i++) { freqs[i] = FrequencyDomain.GetComplexSampleFrequency(windowSize, fftMinFreqBin + i); } }
public FrequencyHistogramViewModel(FrequencyDomain frequencyDomain) { Title = Properties.Resources.PLOT_FREQUENCY_HISTOGRAM_TITLE; Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = Properties.Resources.PLOT_FREQUENCY_HISTOGRAM_LEFT_AXIS }); Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = Properties.Resources.PLOT_FREQUENCY_HISTOGRAM_BOTTOM_AXIS }); if (frequencyDomain != null) { HistogramSeries chs = new HistogramSeries(); chs.Items.AddRange(GetFrequencyBins(frequencyDomain)); Series.Add(chs); } }
protected override void _Initialize() { int frameSize = Samples.Length.CeilingToPowerOfTwo(); double outputScalar = 2.0 / Math.Sqrt(frameSize); Complex64[] ifftBuffer = new Complex64[frameSize]; foreach (ComplexCarrierTone carrierTone in carrierTones) { FrequencyDomain.Populate(ifftBuffer, carrierTone); } Fourier.Inverse(ifftBuffer); for (int i = 0; i < Samples.Length; i++) { Samples[i] = (float)(outputScalar * ifftBuffer[i].Real); } }
protected override void _Initialize() { Complex64[] samples = stream.ComplexSamples(); int bufferLength = samples.Length; Fourier.Forward(samples); IEnumerator <double> distribution = frequencyDistribution.GetEnumerator(); distribution.MoveNext(); int lowerBound = FrequencyDomain.GetComplexFrequencyBin(bufferLength, distribution.Current); while (distribution.MoveNext()) { int upperBound = FrequencyDomain.GetComplexFrequencyBin(bufferLength, distribution.Current); //Generate random offset for the range double offset = 2 * Math.PI * randomizer.NextDouble(); for (int i = lowerBound; i < upperBound; i++) { samples[i] *= Complex64.FromPolarCoordinates(2.0, i * offset); } lowerBound = upperBound; } for (int i = bufferLength / 2; i < bufferLength; i++) { samples[i] = 0.0; } Fourier.Inverse(samples); Samples = new float[bufferLength]; for (int i = 0; i < bufferLength; i++) { Samples[i] = (float)samples[i].Real; } }
public void TestLoadFromFrequencyAmplitudes() { // low pass amplitude array double[] amplitudes = { 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; List <double> frequencyDomain = new List <double>(amplitudes); //FrequencyDomain frequencyDomain = ComplexFastFourierTransform.LoadFourierCoefficients(new List<double>(amplitudes)); ComplexFastFourierTransform synth = new ComplexFastFourierTransform(); FrequencyDomain timeDomain = synth.Transform(frequencyDomain, 2 * frequencyDomain.Count()); foreach (var value in timeDomain.FrequencyAmplitudes) { Console.WriteLine(value); } }
public void Initialize() { if (initialized) { return; } initialized = true; //Min of 10 periods of lowest frequency int bufferSizeLowerBound = (int)Math.Ceiling(SamplingRate * 10.0 / freqLB); fftBufferSize = bufferSizeLowerBound.CeilingToPowerOfTwo(); fftBuffer = new Complex64[fftBufferSize]; foreach (ComplexCarrierTone carrierTone in CreateSideBands(freqLB, freqUB, frequencyCount, distribution)) { FrequencyDomain.Populate( buffer: fftBuffer, frequency: carrierTone.frequency, amplitude: carrierTone.amplitude); } Fourier.Inverse(fftBuffer); double currentRMS = 0.0; for (int i = 0; i < fftBufferSize; i++) { currentRMS += fftBuffer[i].Real * fftBuffer[i].Real; } currentRMS = Math.Sqrt(currentRMS / fftBufferSize); double factor = rms / currentRMS; for (int i = 0; i < fftBufferSize; i++) { fftBuffer[i] *= factor; } }
public SpectralDecomp(double minFreq, double maxFreq, int windowSize, int windowCount) { fftMinFreqBin = FrequencyDomain.GetComplexFrequencyBin(windowSize, minFreq); //+2 to round outward AND to act as an exclusive upperbound fftMaxFreqBin = FrequencyDomain.GetComplexFrequencyBin(windowSize, maxFreq) + 2; fftMaxFreqBin = Math.Min(fftMaxFreqBin, windowSize / 2); spectralValues = new double[windowCount, fftMaxFreqBin - fftMinFreqBin]; freqs = new double[fftMaxFreqBin - fftMinFreqBin]; for (int i = 0; i < freqs.Length; i++) { freqs[i] = FrequencyDomain.GetComplexSampleFrequency(windowSize, fftMinFreqBin + i); } amplitudeAdjustant = 10.0 * Math.Log10(windowSize); minAmplitude = double.PositiveInfinity; maxAmplitude = double.NegativeInfinity; }
// 64 channel sample with padCount zeros padded right public List <double> GetPaddedChannelSample(int sampleCount, int padCount) { int numSamplesToGet = (sampleCount - padCount); int curIDX = _sampleIDX; if (curIDX + numSamplesToGet >= _samples.Count) { numSamplesToGet = _samples.Count - curIDX; if (numSamplesToGet <= 0) { // Roll over to the beginning _sampleIDX = 0; return(GetPaddedChannelSample(sampleCount, padCount)); } } _sampleIDX += numSamplesToGet; _sliceSignal = _samples.GetRange(curIDX, numSamplesToGet); List <double> paddedSignal = new List <double>(sampleCount); paddedSignal.AddRange(_sliceSignal); // Pad int padLen = (sampleCount - numSamplesToGet); for (int cnt = 0; cnt < padLen; cnt++) { paddedSignal.Add(0.0); } IDFT ff_transform = new ComplexFastFourierTransform(); IDFT cdf_tranform = new CorrelationFourierTransform(); //_frequencyDomain = DFT.CorrelationTransform(paddedSignal); _frequencyDomain = ff_transform.Transform(paddedSignal); return(_sliceSignal); }
public List <double> GetNextSamplesForTimeSlice(double milliseconds) { int numSamplesToGet = (int)Math.Floor((milliseconds / 1000) * _sampleRate); int curIDX = _sampleIDX; if (curIDX + numSamplesToGet >= _samples.Count) { numSamplesToGet = _samples.Count - curIDX - 1; if (numSamplesToGet <= 0) { // Roll over to the beginning _sampleIDX = 0; return(GetNextSamplesForTimeSlice(milliseconds)); } } _sampleIDX += numSamplesToGet; _sliceSignal = _samples.GetRange(curIDX, numSamplesToGet); //_frequencyDomain = DFT.CorrelationTransform(_sliceSignal); //IDFT transform = new FastFourierTransform(); IDFT transform = new CorrelationFourierTransform(); _frequencyDomain = transform.Transform(_sliceSignal); return(_sliceSignal); }
public static SpectralDecomp Decompose( IBGCStream stream, int windowCount = 400, int windowOrder = 12, int targetChannel = 0, double minFreq = 0.0, double maxFreq = double.PositiveInfinity) { //WindowSize is 2 ^ windowOrder int windowSize = 1 << windowOrder; if (stream.Channels <= targetChannel) { throw new ArgumentException( $"TargetChannel ({targetChannel}) exceeded stream channels ({stream.Channels})", nameof(targetChannel)); } float[] samples = stream.IsolateChannel(targetChannel).HardClip().Cache().Samples; int sampleOffset = (int)((samples.Length - windowSize) / (double)(windowCount - 1)); //Adjust windowSize to conform to sample size and requirements while (sampleOffset <= 0 && windowOrder > 4) { --windowOrder; windowSize = 1 << windowOrder; windowCount /= 2; sampleOffset = (int)((samples.Length - windowSize) / (double)(windowCount - 1)); } if (windowOrder == 4) { throw new ArgumentException("Clip too short to evaluate"); } //Limit Max Frquency by the size of the window maxFreq = Math.Min(maxFreq, FrequencyDomain.GetComplexSampleFrequency(windowSize, windowSize / 2)); //Limit Min Frequency by the minFreq = Math.Max(minFreq, FrequencyDomain.GetComplexSampleFrequency(windowSize, 1)); //Our output will be just the real-valued amplitudes SpectralDecomp decomp = new SpectralDecomp(minFreq, maxFreq, windowSize, windowCount); Complex64[] fftBuffer = new Complex64[windowSize]; IBGCEnvelopeStream windowStream = new BlackmanHarrisEnvelope(windowSize); for (int window = 0; window < windowCount; window++) { int specificOffset = sampleOffset * window; windowStream.Reset(); //Copy samples into buffer for (int i = 0; i < windowSize; i++) { //Set real value fftBuffer[i] = samples[specificOffset + i] * windowStream.ReadNextSample(); } Fourier.Forward(fftBuffer); decomp.Add(window, fftBuffer); } decomp.Rescale(); return(decomp); }
public ActionResult <List <Double> > InverseFFT([FromBody] FrequencyDomain fd) { ComplexFastFourierTransform transformer = new ComplexFastFourierTransform(); return(Ok(transformer.Synthesize(fd))); }
public override int Read(float[] data, int offset, int count) { if (!initialized) { Initialize(); } int samplesWritten = ReadBody(data, offset, count); while (samplesWritten < count) { //Slide over noise samples Array.Copy( sourceArray: noiseBuffer, sourceIndex: stepSize, destinationArray: noiseBuffer, destinationIndex: 0, length: overlapSize); int read = stream.Read(inputBuffer, overlapSize, stepSize); if (read <= 0 && samplesHandled <= 0) { //Done, No samples left to work with break; } else if (read <= 0) { //We are in buffer-dumping window //Set rest of inputBuffer to zero Array.Clear(inputBuffer, overlapSize, stepSize); } else if (read < stepSize) { //Near or at the end //Set rest of inputBuffer to zero Array.Clear(inputBuffer, overlapSize + read, inputBuffer.Length - overlapSize - read); } //Generate new noise for (int i = 0; i < stepSize; i++) { noiseBuffer[overlapSize + i] = noiseScalarA - noiseScalarB * randomizer.NextDouble(); } //Copy in the input data for (int i = 0; i < fftSize; i++) { signalFFTBuffer[i] = inputBuffer[i] * window[i]; noiseFFTBuffer[i] = noiseBuffer[i]; } //FFT Task.WaitAll( Task.Run(() => Fourier.Forward(signalFFTBuffer)), Task.Run(() => Fourier.Forward(noiseFFTBuffer))); //For each band... Parallel.For( fromInclusive: 0, toExclusive: bandFrequencies.Length - 1, body: (int band) => { int lowerBound = FrequencyDomain.GetComplexFrequencyBin(fftSize, bandFrequencies[band]); int upperBound = FrequencyDomain.GetComplexFrequencyBin(fftSize, bandFrequencies[band + 1]); Complex64[] amplitudeBuffer = amplitudeBuffers[band]; Complex64[] noiseBandBuffer = noiseBandBuffers[band]; //Copy over band just the relevant frequency band for (int i = lowerBound; i < upperBound; i++) { amplitudeBuffer[i] = 2.0 * signalFFTBuffer[i]; noiseBandBuffer[i] = 2.0 * noiseFFTBuffer[i]; } Complex64 zero = Complex64.Zero; //Clear rest of buffers for (int i = 0; i < lowerBound; i++) { amplitudeBuffer[i] = zero; noiseBandBuffer[i] = zero; } for (int i = upperBound; i < amplitudeBuffer.Length; i++) { amplitudeBuffer[i] = zero; noiseBandBuffer[i] = zero; } //IFFT Task.WaitAll( Task.Run(() => Fourier.Inverse(amplitudeBuffer)), Task.Run(() => Fourier.Inverse(noiseBandBuffer))); for (int i = 0; i < amplitudeBuffer.Length; i++) { outputAccumulation[i] += outputFactor * window[i] * noiseBandBuffer[i].Real * amplitudeBuffer[i].Magnitude; } }); samplesHandled += read; if (--frameLag <= 0) { bufferIndex = 0; bufferCount = Math.Min(stepSize, samplesHandled); samplesHandled -= bufferCount; //Copy output samples to output buffer for (int sample = 0; sample < bufferCount; sample++) { cachedSampleBuffer[sample] = (float)outputAccumulation[sample]; } } //Slide over input samples Array.Copy( sourceArray: inputBuffer, sourceIndex: stepSize, destinationArray: inputBuffer, destinationIndex: 0, length: overlapSize); //Slide output samples Array.Copy( sourceArray: outputAccumulation, sourceIndex: stepSize, destinationArray: outputAccumulation, destinationIndex: 0, length: overlapSize); //Clear empty output accumulation region Array.Clear(outputAccumulation, overlapSize, stepSize); samplesWritten += ReadBody(data, offset + samplesWritten, count - samplesWritten); } return(samplesWritten); }
public override int Read(float[] data, int offset, int count) { int samplesWritten = ReadBody(data, offset, count); while (samplesWritten < count) { bufferIndex = 0; bufferCount = stepSize; //Clear IFFT Buffer Array.Clear(ifftBuffer, 0, ifftBuffer.Length); //If there are any leading frames... double timeShiftDeltaT = (frame + leadingFrames) * timePerStep; bool isLeadingFrame = leadingFrames < 0; foreach (ComplexCarrierTone carrierTone in carrierTones) { FrequencyDomain.Populate( buffer: ifftBuffer, carrierTone: carrierTone.TimeShift(timeShiftDeltaT)); } //IFFT Fourier.Inverse(ifftBuffer); //Accumualte the window samples for (int i = 0; i < frameSize; i++) { outputAccumulation[i] += (float)(outputScalar * window[i] * ifftBuffer[i].Real); } //Advance Frame if (isLeadingFrame) { leadingFrames++; } else { frame++; } //Copy output samples to output buffer Array.Copy( sourceArray: outputAccumulation, destinationArray: cachedSampleBuffer, length: stepSize); //Slide down output accumulation Array.Copy( sourceArray: outputAccumulation, sourceIndex: stepSize, destinationArray: outputAccumulation, destinationIndex: 0, length: overlap); //Clear empty output accumulation region Array.Clear( array: outputAccumulation, index: overlap, length: stepSize); if (!isLeadingFrame) { samplesWritten += ReadBody(data, offset + samplesWritten, count - samplesWritten); } } return(count); }
private void LoadFilterData() { List <double> summedFilterData = manager.ActiveWorkBook().CombinedFilterImpulseResponse(true); // Return an empty set if (summedFilterData == null || summedFilterData.Count == 0) { ImpulseResponsePoints = new List <DataPoint>(); StepResponsePoints = new List <DataPoint>(); FrequencyResponsePoints = new List <DataPoint>(); DecibelResponsePoints = new List <DataPoint>(); Filters = new ObservableCollection <UserControl>(); NotifyPropertyChanged(nameof(ImpulseResponsePoints)); NotifyPropertyChanged(nameof(FrequencyResponsePoints)); NotifyPropertyChanged(nameof(DecibelResponsePoints)); NotifyPropertyChanged(nameof(StepResponsePoints)); NotifyPropertyChanged(nameof(SumModeActive)); NotifyPropertyChanged(nameof(ConvolveModeActive)); NotifyPropertyChanged(nameof(Filters)); return; } ImpulseResponsePoints = new List <DataPoint>(summedFilterData.Count); StepResponsePoints = new List <DataPoint>(summedFilterData.Count); Filters = new ObservableCollection <UserControl>(); for (int idx = 0; idx < summedFilterData.Count; idx++) { ImpulseResponsePoints.Add(new DataPoint(idx, summedFilterData[idx])); } //IDFT cmplxFFT = new ComplexFastFourierTransform(); IDFT cmplxFFT = new DSPGuideComplexDiscreteFourierTransform(); int filterLength = 0; if (manager.ActiveWorkBook().WindowedSyncFilters.Count > 0) { filterLength = manager.ActiveWorkBook().WindowedSyncFilters.Values.First().FilterLength; } else if (manager.ActiveWorkBook().CustomFilters.Count > 0) { filterLength = manager.ActiveWorkBook().CustomFilters.Values.First().FilterLength; } else { return; // Count not find any filters to set length with } FrequencyDomain frequencyDomain = cmplxFFT.Transform(summedFilterData, filterLength); Convolution convolver = new Convolution(); List <double> stepResponse = convolver.Convolve(summedFilterData, GetStepData(summedFilterData.Count + 16), ConvolutionType.INPUTSIDE); FrequencyResponsePoints = new List <DataPoint>(frequencyDomain.FrequencyAmplitudes.Count); DecibelResponsePoints = new List <DataPoint>(FrequencyResponsePoints.Count); // Load the frequency response graph data // Only scan the first half of the coefficients (up to the Nyquist frequency) int coefficientMax = (frequencyDomain.FourierCoefficients.Count / 2); for (int idx = 0; idx < coefficientMax; idx++) { double coeffLen = Complex.Abs(frequencyDomain.FourierCoefficients[idx]); double cuttoffFrequencyPercent = (((double)idx + 1.0) / summedFilterData.Count); FrequencyResponsePoints.Add(new DataPoint(cuttoffFrequencyPercent, coeffLen)); DecibelResponsePoints.Add(new DataPoint(cuttoffFrequencyPercent, 20 * Math.Log10(coeffLen))); } int startingOffset = (summedFilterData.Count / 2); int endingOffset = startingOffset + summedFilterData.Count; int graphX = 0; // Load the step response graph data for (int idx = (startingOffset - 1); idx < endingOffset; idx++) { StepResponsePoints.Add(new DataPoint(graphX, stepResponse[idx])); graphX++; } foreach (var filter in manager.ActiveWorkBook().WindowedSyncFilters.Values) { filter.PropertyChanged -= handleFilterUpdate; WindowedSyncFilterItemView viewItem = new WindowedSyncFilterItemView(); viewItem.DataContext = filter; Filters.Add(viewItem); filter.PropertyChanged += handleFilterUpdate; // Remove/re-add to avoid leaks in event handlers } foreach (var filter in manager.ActiveWorkBook().CustomFilters.Values) { filter.PropertyChanged -= handleFilterUpdate; CustomFilterViewItem viewItem = new CustomFilterViewItem(); viewItem.DataContext = filter; Filters.Add(viewItem); filter.PropertyChanged += handleFilterUpdate; // Remove/re-add to avoid leaks in event handlers } NotifyPropertyChanged(nameof(ImpulseResponsePoints)); NotifyPropertyChanged(nameof(FrequencyResponsePoints)); NotifyPropertyChanged(nameof(DecibelResponsePoints)); NotifyPropertyChanged(nameof(StepResponsePoints)); NotifyPropertyChanged(nameof(Filters)); }
public void TestComplexTransform() { //IDFT complexFourierTransform = new ComplexFastFourierTransform(); IDFT complexFourierTransform = new DSPGuideComplexDiscreteFourierTransform(); FrequencyDomain result; List <double> recreatedSignal; int sampleRate = 1000; // hz List <double> timePoints = new List <double>(2 * sampleRate); for (double timePointVal = 0; timePointVal < 2.0; timePointVal += (1.0 / sampleRate)) { timePoints.Add(timePointVal); } List <double> signal = new List <double>(timePoints.Count); foreach (double timePointVal in timePoints) { double signalValue = (2.5 * Math.Sin(2 * Math.PI * 4 * timePointVal)) + (1.5 * Math.Sin(2 * Math.PI * 6.5 * timePointVal)); signal.Add(signalValue); } result = complexFourierTransform.Transform(signal, sampleRate); List <Tuple <double, double> > magPhaseList = ComplexFastFourierTransform.ToMagnitudePhaseList(result); FrequencyDomain fromMagPhaseList = ComplexFastFourierTransform.FromMagnitudePhaseList(magPhaseList); for (int idx = 0; idx < result.FourierCoefficients.Count; idx++) { double absDifference = Complex.Abs(result.FourierCoefficients[idx] - fromMagPhaseList.FourierCoefficients[idx]); // Check that they are close, rounding error occurs, they wont be equal Assert.IsTrue(absDifference < 1.0E-10); } // This file can be viewed in Excel for plotting of hz and amplitudes StreamWriter amplitudeFile = new StreamWriter("frequencyAmplitudes.csv"); if (amplitudeFile != null) { amplitudeFile.WriteLine("HZ, Amplitude"); foreach (var frequencyAmplitude in result.FrequencyAmplitudes) { amplitudeFile.WriteLine($"{frequencyAmplitude.Key}, {frequencyAmplitude.Value}"); } } amplitudeFile.Close(); recreatedSignal = complexFourierTransform.Synthesize(result); Assert.IsNotNull(result); Assert.IsNotNull(recreatedSignal); //double amplitude40 = result.FrequencyAmplitudes[4.0]; //double amplitude65 = result.FrequencyAmplitudes[6.5]; //Assert.IsTrue(Math.Abs(amplitude40 - 2.5) <= MaxAmplitudeDifference); //Assert.IsTrue(Math.Abs(amplitude65 - 1.5) <= MaxAmplitudeDifference); double maxDifference = 0.0; for (int idx = 0; idx < recreatedSignal.Count; idx++) { double calculateDifference = Math.Abs(recreatedSignal[idx] - signal[idx]); if (maxDifference < calculateDifference) { maxDifference = calculateDifference; } } for (int idx = 0; idx < recreatedSignal.Count; idx++) { double calculateDifference = Math.Abs(recreatedSignal[idx] - signal[idx]); Assert.IsTrue(calculateDifference <= MaxSignalDifference); } }