public void TestFFT() { const int SIZE = 512; var re = new double[SIZE]; var im = new double[SIZE]; for (int i = 0; i < SIZE; i++) { re[i] = Math.Sin(2 * Math.PI / SIZE * i); im[i] = 0; } var fft = new FFT2(); var logN = (uint)Math.Log(SIZE, 2); fft.init(logN); var expected = new double[SIZE]; Array.Copy(re, expected, re.Length); fft.run(re, im); fft.run(re, im, true); for (int i = 0; i < SIZE; i++) { Assert.AreEqual(expected[i], re[i], 0.000000001); } }
public void AnalyzeData() { print("AnalyzeData"); total_Acc = new double[raw_data.Count]; textMesh.text = "Calculating total acceleration on " + raw_data.Count.ToString() + " values"; for (int i = 0; i < raw_data.Count; i++) { //calculate total acceleration of the 3 axis total_Acc[i] = Mathf.Sqrt(Mathf.Pow((raw_data.ElementAt(i).x), 2) + Mathf.Pow((raw_data.ElementAt(i).y), 2) + Mathf.Pow((raw_data.ElementAt(i).z), 2)); //print("\t" + total_Acc[i]); } FFT2 fft2 = new FFT2(); /** * Initialize class to perform FFT of specified size. * * @param logN Log2 of FFT length. e.g. for 512 pt FFT, logN = 9. */ textMesh.text = "starting FFT"; fft2.init((uint)Mathf.Log(total_Acc.Length)); //create array of double for Im part-----> array should be compsed by 0 y_fft = new double[total_Acc.Length]; for (int i = 0; i < total_Acc.Length; i++) { y_fft[i] = 0; } //run the fft fft2.run(total_Acc, y_fft); StartCoroutine(ShowResult()); }
private void FillDataSeries(WaterfallDataSeries3D <double> dataSeries, int sliceCount, int pointsPerSlice) { var count = pointsPerSlice * 2; var re = new double[count]; var im = new double[count]; for (int sliceIndex = 0; sliceIndex < sliceCount; ++sliceIndex) { for (var i = 0; i < count; i++) { re[i] = 2.0 * Math.Sin(2 * Math.PI * i / 20) + 5 * Math.Sin(2 * Math.PI * i / 10) + 2.0 * _random.NextDouble(); im[i] = -10; } _transform.run(re, im); var scaleCoef = Math.Pow(1.5, sliceIndex * 0.3) / Math.Pow(1.5, sliceCount * 0.3); for (var pointIndex = 0; pointIndex < pointsPerSlice; pointIndex++) { var mag = Math.Sqrt(re[pointIndex] * re[pointIndex] + im[pointIndex] * im[pointIndex]); var yVal = _random.Next(10, 20) * Math.Log10(mag / pointsPerSlice); yVal = (yVal <-25 || yVal> -5) ? (yVal < -25) ? -25 : _random.Next(-6, -3) : yVal; dataSeries[sliceIndex, pointIndex] = -yVal * scaleCoef; } } }
private static WaterfallDataSeries3D <double> GetWaterfallDataSeries() { var pointsPerSlice = 100; var sliceCount = 20; var logBase = 10; var slicePositions = new double[sliceCount]; for (int i = 0; i < sliceCount; ++i) { slicePositions[i] = i; } var dataSeries = new WaterfallDataSeries3D <double>(pointsPerSlice, slicePositions); dataSeries.StartX = 10; dataSeries.StepX = 1; _transform.init((uint)Math.Log(pointsPerSlice, 2)); var count = pointsPerSlice * 2; var re = new double[count]; var im = new double[count]; for (int sliceIndex = 0; sliceIndex < sliceCount; ++sliceIndex) { for (var i = 0; i < count; i++) { re[i] = 2.0 * Math.Sin(2 * Math.PI * i / 20) + 5 * Math.Sin(2 * Math.PI * i / 10) + 2.0 * _random.NextDouble(); im[i] = -10; } _transform.run(re, im); var scaleCoef = Math.Pow(1.5, sliceIndex * 0.3) / Math.Pow(1.5, sliceCount * 0.3); for (var pointIndex = 0; pointIndex < pointsPerSlice; pointIndex++) { var mag = Math.Sqrt(re[pointIndex] * re[pointIndex] + im[pointIndex] * im[pointIndex]); var yVal = _random.Next(10, 20) * Math.Log10(mag / pointsPerSlice); yVal = (yVal <-25 || yVal> -5) ? (yVal < -25) ? -25 : _random.Next(-6, -3) : yVal; dataSeries[sliceIndex, pointIndex] = -yVal * scaleCoef; } } return(dataSeries); }
private void LoadFile(string path, ArrayViewer waveViewer, ArrayViewer fftViewer) { FileStream fileStream = new FileStream(path, FileMode.Open); BinaryReader binaryReader = new BinaryReader(fileStream); short[] wave = new short[binaryReader.BaseStream.Length / 2]; int i = 0; while (binaryReader.BaseStream.Position < binaryReader.BaseStream.Length) { uint a = binaryReader.ReadByte(); uint b = binaryReader.ReadByte(); wave[i] = (short)((a << 8) | b); i++; } fileStream.Close(); fileStream.Dispose(); waveViewer.DrawWave(wave); Application.DoEvents(); FFT2 fft2 = new FFT2(); fft2.init((uint)Math.Log((double)wave.Length, 2.0)); double[] re = new double[wave.Length]; double[] img = new double[wave.Length]; for (int j = 0; j < wave.Length; j++) { re[j] = wave[j]; img[j] = 0.0F; } fft2.run(re, img); double[] modulo = new double[re.Length / 2]; for (int j = 0; j < modulo.Length; j++) { modulo[j] = Math.Sqrt((re[j] * re[j]) + (img[j] * img[j])); } int number = (int)(2048.0F*(float) modulo.Length/8000.0F); fftViewer.DrawWave(modulo.Take(number).ToArray()); }
// NOTE: The purpose of this function is to simply generate some random data to display in the waterfall chart // Each row is _pointsPerSlice wide and there are _maxSliceCount slices in the waterfall private double[] GenerateDataRow() { var generatedRow = new double[_pointsPerSlice]; // Randomly introduce changes in amplitude _tick++; if (_tick == 2) { _tick = 0; _step = _random.Next(10, 20); } for (int i = 0; i < _transformSize; i++) { double noise = _random.Next(-100, 100) * 0.002; // Compute a sinusoidal based waveform with some varying frequency and random amplitude double y = _step * 2 * Math.Sin(((2 * Math.PI) * 0.1) * t) + noise; y += Math.Sin(((2 * Math.PI) * 0.2) * t); _real[i] = y; _imaginary[i] = 0; t += dt; } // Do an FFT _transform.run(_real, _imaginary); // Convert FFT back to magnitude (required for a meaninful output in our test data) for (int i = 0; i < _pointsPerSlice; i++) { double magnitude = Math.Sqrt(_real[i] * _real[i] + _imaginary[i] * _imaginary[i]); generatedRow[i] = Math.Log10(magnitude); } return(generatedRow); }
//public int numPartitions = 10000; //public float overlapPercent = 0.5f; //public float threshold = 1 - 0.75f; //larger float values are more strict //public float beatDetectionOverlapPercent = 0.5f; /// <summary> /// Processes raw audio data to find average energy for overlapping partitions. /// </summary> /// <returns>The FFT data array.</returns> /// <param name="clip">Audio clip to process.</param> /// <param name="numPartitions">Number of pieces to split the song into for analysis</param> /// <param name="overlapPercent">The percentage which the partitions overlap each other</param> public double[] ProcessAudio(AudioClip clip, int numPartitions, float overlapPercent) { _averages = new double[(int)(numPartitions / overlapPercent) - 1]; int samplesPerPartition = (int)(clip.samples / numPartitions); int numDivisions = (int)(numPartitions / overlapPercent) - 1; //Because the partitions overlap, the number of iterations is the number of partitions multiplied by the inverse of the overlap percent for (int i = 0; i < numDivisions; i++) { float[] samples = new float[samplesPerPartition]; int input = i * ((int)(samples.Length * overlapPercent)); //the offset to start getting song data increases by overlapPercent as i is incremented clip.GetData(samples, input); //the raw partition data is run through the Blackman-Harris windowing function for (int n = 0; n < samples.Length; n++) { samples [n] *= _a0 - _a1 * Mathf.Cos((2 * Mathf.PI * n) / samples.Length - 1) + _a2 * Mathf.Cos((4 * Mathf.PI * n) / samples.Length - 1) - _a3 * Mathf.Cos((6 * Mathf.PI * n) / samples.Length - 1); } FFT2 FFT = new FFT2(); FFT.init((uint)Mathf.Log(samplesPerPartition, 2)); //our array of floats is converted to an array of doubles for use in the FFT function double[] double_samples = samples.ToList().ConvertAll <double> (new System.Converter <float, double> (F2D)).ToArray(); //runs our sample data through a Fast Fourier Transform to convert it to the frequency domain FFT.run(double_samples, new double[samples.Length], false); //gets the average value for this partition and adds it to an array. //when all of the partitions are completed, averages will contain data for the entire song double avg = double_samples.Average(); _averages[i] = avg; } return(_averages); }
//public int numPartitions = 10000; //public float overlapPercent = 0.5f; //public float threshold = 1 - 0.75f; //larger float values are more strict //public float beatDetectionOverlapPercent = 0.5f; /// <summary> /// Processes raw audio data to find average energy for overlapping partitions. /// </summary> /// <returns>The FFT data array.</returns> /// <param name="clip">Audio clip to process.</param> /// <param name="numPartitions">Number of pieces to split the song into for analysis</param> /// <param name="overlapPercent">The percentage which the partitions overlap each other</param> public double[] ProcessAudio(AudioClip clip, int numPartitions, float overlapPercent) { _averages = new double[(int)(numPartitions / overlapPercent) - 1]; int samplesPerPartition = (int)(clip.samples / numPartitions); int numDivisions = (int)(numPartitions / overlapPercent) - 1; //Because the partitions overlap, the number of iterations is the number of partitions multiplied by the inverse of the overlap percent for (int i = 0; i < numDivisions; i++) { float[] samples = new float[samplesPerPartition]; int input = i * ((int) (samples.Length * overlapPercent)); //the offset to start getting song data increases by overlapPercent as i is incremented clip.GetData(samples, input); //the raw partition data is run through the Blackman-Harris windowing function for (int n = 0; n < samples.Length; n++) { samples [n] *= _a0 - _a1 * Mathf.Cos ((2 * Mathf.PI * n) / samples.Length - 1) + _a2 * Mathf.Cos ((4 * Mathf.PI * n) / samples.Length - 1) - _a3 * Mathf.Cos ((6 * Mathf.PI * n) / samples.Length - 1); } FFT2 FFT = new FFT2 (); FFT.init ((uint)Mathf.Log(samplesPerPartition,2)); //our array of floats is converted to an array of doubles for use in the FFT function double[] double_samples = samples.ToList ().ConvertAll<double> (new System.Converter<float, double> (F2D)).ToArray (); //runs our sample data through a Fast Fourier Transform to convert it to the frequency domain FFT.run (double_samples, new double[samples.Length], false); //gets the average value for this partition and adds it to an array. //when all of the partitions are completed, averages will contain data for the entire song double avg = double_samples.Average (); _averages[i] = avg; } return _averages; }
double[] DoFFT(double[] values) { double[] real = new double[values.Length]; double[] imaginary = new double[values.Length]; for (int i = 0; i < values.Length; i++) { imaginary[i] = 0f; real[i] = values[i]; } FFT2 fft = new FFT2(); fft.init((uint)Mathf.Log ((float)values.Length)); fft.run (real, imaginary, false); return real; }