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);
            }
        }
예제 #2
0
    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;
                }
            }
        }
예제 #4
0
        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);
        }
예제 #5
0
        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());
        }
예제 #6
0
        // 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);
        }
예제 #7
0
        //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);
        }
예제 #8
0
        //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;
        }
예제 #9
0
	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;
	}