*
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public static class Drawing
|
||||
{
|
||||
//transform parameters to draw the chart;
|
||||
public static double a, b, x0, y0;
|
||||
public static LineRenderer linR;
|
||||
|
||||
public static void drawChart(Transform tf, double[] X_inputValues, double[]Y_inputValues, string type, float? customYScale = null)
|
||||
{
|
||||
linR =tf.GetComponent<LineRenderer>();
|
||||
|
||||
|
||||
//transform parameters to draw the heart rate
|
||||
a = tf.localScale.x;
|
||||
b = tf.localScale.y;
|
||||
x0 = tf.position.x;
|
||||
y0 = tf.position.y;
|
||||
|
||||
|
||||
//do not resize array
|
||||
if (type=="time")
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
//resize array
|
||||
else if(type=="frequency")
|
||||
{
|
||||
X_inputValues=ArrayResize(X_inputValues, (int)X_inputValues.Length/2);
|
||||
Y_inputValues=ArrayResize(Y_inputValues, (int)Y_inputValues.Length/2);
|
||||
}
|
||||
|
||||
linR.positionCount = X_inputValues.Length;
|
||||
|
||||
double max_X = FastFourierTransform.MaxD(X_inputValues);
|
||||
double min_X = FastFourierTransform.MinD(X_inputValues);
|
||||
double max_Y = FastFourierTransform.MaxD(Y_inputValues);
|
||||
double min_Y = FastFourierTransform.MinD(Y_inputValues);
|
||||
|
||||
double dY = max_Y - min_Y;
|
||||
if (customYScale.HasValue) {
|
||||
dY = customYScale.Value;
|
||||
}
|
||||
|
||||
|
||||
//drawing factors
|
||||
double factorA_X = (x0 + a / 2 - (x0 - a / 2)) / (max_X - min_X + 0.01f);
|
||||
double factorB_X = factorA_X * (-min_X) + (x0 - a / 2);
|
||||
double factorA_Y = (y0 + b / 2 - (y0 - b / 2)) / (dY + 0.01f);
|
||||
double factorB_Y = factorA_Y * (-min_Y) + (y0 - b / 2);
|
||||
|
||||
|
||||
//draw using the lineRender
|
||||
for (int ii = 0; ii < linR.positionCount; ii++)
|
||||
{
|
||||
// Debug.Log(ii);
|
||||
double xt = X_inputValues[ii] * factorA_X + factorB_X;
|
||||
double yt = Y_inputValues[ii] * factorA_Y + factorB_Y;
|
||||
|
||||
linR.SetPosition(ii, new UnityEngine.Vector3((float)xt, (float)yt, tf.position.z));
|
||||
}
|
||||
}
|
||||
|
||||
//gets an array and resizes it to a fixed value
|
||||
public static double[] ArrayResize(double[] a, int Size)
|
||||
{
|
||||
|
||||
double[] temp = new double[Size];
|
||||
for (int c = 1; c < Mathf.Min(Size, a.Length); c++)
|
||||
{
|
||||
temp[c] = a[c];
|
||||
}
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 48b69030bca8c794da64aa2cbef70bd3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 152492
|
||||
packageName: FFT Fast Fourrier Transform
|
||||
packageVersion: 1.0
|
||||
assetPath: Assets/FFT fast fourrier transform/Scripts/Drawing.cs
|
||||
uploadId: 325757
|
||||
@@ -0,0 +1,174 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using System.Numerics;
|
||||
|
||||
public class Example01_time_to_frequency : MonoBehaviour
|
||||
{
|
||||
[Space]
|
||||
[Header("[!] set fixed time to 0.01f [!]")]
|
||||
[Header("TIME SIGNAL TO FREQUENCY FFT")]
|
||||
[Space]
|
||||
|
||||
//samplingfrequency
|
||||
public int samplingFrequency;
|
||||
|
||||
//input-output values for the FFT
|
||||
double[] X_inputValues;
|
||||
double[] Y_inputValues;
|
||||
double[] Y_output;
|
||||
|
||||
//list with the input values
|
||||
public List<double> Y_values;
|
||||
|
||||
//these are the frequencies, amplitude and phase of the sinus added to the signal
|
||||
[Space(10)]
|
||||
[Header("F,A and P must be same lenght")]
|
||||
[Tooltip("Add different values of amplitude/frequency to change the time response")]
|
||||
[Space]
|
||||
public double[] freq;
|
||||
public double[] Amp;
|
||||
public double[] phase;
|
||||
|
||||
|
||||
//this is the size of the window of data
|
||||
public int windowSize = 1024;
|
||||
|
||||
//this is used to obtain the frequency with a peak
|
||||
[Space(10)]
|
||||
[Header("MOST IMPORTANT FREQUENCY")]
|
||||
[Tooltip("This corresponds to the peak on the FFT")]
|
||||
[Space]
|
||||
public double maxf_obtained;
|
||||
|
||||
//counts the steps taken
|
||||
long count = 0;
|
||||
|
||||
//the chart transforms for the time and frequency
|
||||
[Space(10)]
|
||||
[Header("CHARTS FOR DRAWING")]
|
||||
[Space]
|
||||
public Transform tfTime;
|
||||
public Transform tfFreq;
|
||||
|
||||
|
||||
void Start()
|
||||
{
|
||||
X_inputValues = new double[windowSize];
|
||||
Y_inputValues = new double[windowSize];
|
||||
|
||||
samplingFrequency = (int)(1 / Time.fixedDeltaTime);
|
||||
|
||||
for (int ii = 0; ii < windowSize; ii++)
|
||||
{
|
||||
Y_values.Add(0);
|
||||
}
|
||||
|
||||
StartCoroutine(time_to_frequency());
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This corrutine obtains these steps in order:
|
||||
/// 1) generates a time response using SIN() signals
|
||||
/// 2) obtains a window of the signal
|
||||
/// 3) applies the FFT
|
||||
/// </summary>
|
||||
|
||||
IEnumerator time_to_frequency()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
|
||||
// add point to the time chart
|
||||
double signal = 0;
|
||||
for (int jj = 0; jj < Amp.Length; jj++)
|
||||
{
|
||||
signal+= (double)( Amp[jj] * Mathf.Sin(2 * Mathf.PI * (float)freq[jj] * (float)count *1/(float)samplingFrequency + (float)phase[jj]) );
|
||||
}
|
||||
count++;
|
||||
|
||||
Y_values.Add(signal);
|
||||
|
||||
|
||||
if (Y_values.Count >= windowSize)
|
||||
{
|
||||
//ONE IS THE INPUT VALUES
|
||||
|
||||
//this is the window size
|
||||
for (int ii = 0; ii < windowSize; ii++)
|
||||
{
|
||||
X_inputValues[ii] = ii;
|
||||
|
||||
|
||||
X_inputValues[ii] = ii;
|
||||
Y_inputValues[ii] = (Y_values[ii + Y_values.Count - 1 - windowSize]);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//perform complex opterations and set up the arrays
|
||||
Complex[] inputSignal_Time = new Complex[windowSize];
|
||||
Complex[] outputSignal_Freq = new Complex[windowSize];
|
||||
|
||||
|
||||
inputSignal_Time = FastFourierTransform.doubleToComplex(Y_inputValues);
|
||||
|
||||
|
||||
//result is the iutput values once DFT has been applied
|
||||
outputSignal_Freq = FastFourierTransform.FFT(inputSignal_Time,false);
|
||||
|
||||
|
||||
|
||||
Y_output = new double[windowSize];
|
||||
//get module of complex number
|
||||
for (int ii = 0; ii < windowSize; ii++)
|
||||
{
|
||||
//Debug.Log(ii);
|
||||
Y_output[ii] = (double)Complex.Abs(outputSignal_Freq[ii]);
|
||||
}
|
||||
|
||||
|
||||
// find peak VALUES on the FFT
|
||||
double MaxPeak = -1000;
|
||||
int peakIndex = 0;
|
||||
for (int i = 1; i < Y_output.Length/2 - 1; i++)
|
||||
{
|
||||
if (Y_output[i]>MaxPeak)
|
||||
{
|
||||
MaxPeak = Y_output[i];
|
||||
peakIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
//store results
|
||||
maxf_obtained = (double)peakIndex / (double)windowSize/2* (double)samplingFrequency;
|
||||
|
||||
}
|
||||
|
||||
|
||||
yield return new WaitForFixedUpdate();
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void FixedUpdate()
|
||||
{
|
||||
//draw both charts: time-domain and frequency-domain
|
||||
Drawing.drawChart(tfTime,X_inputValues, Y_inputValues, "time");
|
||||
Drawing.drawChart(tfFreq, X_inputValues, Y_output, "frequency");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f7e2890ad1d354344943df8cd47704e7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 152492
|
||||
packageName: FFT Fast Fourrier Transform
|
||||
packageVersion: 1.0
|
||||
assetPath: Assets/FFT fast fourrier transform/Scripts/Example01_time_to_frequency.cs
|
||||
uploadId: 325757
|
||||
@@ -0,0 +1,208 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using System.Numerics;
|
||||
|
||||
public class Example02_filtering : MonoBehaviour
|
||||
{
|
||||
|
||||
public enum filterMode { low_pass, high_pass };
|
||||
|
||||
[Space]
|
||||
[Header("[!] set fixed time to 0.01f [!]")]
|
||||
[Header("FILTERING")]
|
||||
[Space]
|
||||
|
||||
//samplingfrequency
|
||||
public int samplingFrequency;
|
||||
|
||||
//input-output values for the FFT
|
||||
double[] X_inputValues;
|
||||
double[] Y_inputValues;
|
||||
double[] Y_output;
|
||||
|
||||
double[] Y_inputValues_filtered;
|
||||
double[] Y_output_filtered;
|
||||
|
||||
//list with the input values
|
||||
public List<double> Y_values;
|
||||
|
||||
//these are the frequencies, amplitude and phase of the sinus added to the signal
|
||||
[Space(10)]
|
||||
[Header("F,A and P must be same lenght")]
|
||||
[Tooltip("Add different values of amplitude/frequency to change the time response")]
|
||||
[Space]
|
||||
public double[] freq;
|
||||
public double[] Amp;
|
||||
public double[] phase;
|
||||
|
||||
|
||||
//this is the size of the window of data
|
||||
public int windowSize = 1024;
|
||||
|
||||
|
||||
//counts the steps taken
|
||||
long count = 0;
|
||||
|
||||
//
|
||||
|
||||
//the chart transforms for the time and frequency
|
||||
[Space(10)]
|
||||
[Header("CHARTS FOR DRAWING")]
|
||||
[Space]
|
||||
public Transform tfTime;
|
||||
public Transform tfFreq;
|
||||
public Transform tfTime_filt;
|
||||
public Transform tfFreq_filt;
|
||||
|
||||
[Space(10)]
|
||||
[Header("Select filtering type")]
|
||||
[Space]
|
||||
public filterMode filtermode;
|
||||
|
||||
//this is the filter parameter
|
||||
public double alpha = 0.2f;
|
||||
|
||||
void Start()
|
||||
{
|
||||
X_inputValues = new double[windowSize];
|
||||
Y_inputValues = new double[windowSize];
|
||||
|
||||
samplingFrequency = (int)(1 / Time.fixedDeltaTime);
|
||||
|
||||
for (int ii = 0; ii < windowSize; ii++)
|
||||
{
|
||||
Y_values.Add(0);
|
||||
}
|
||||
|
||||
StartCoroutine(filterSignal());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This corrutine obtains these steps in order:
|
||||
/// 1) generates a time response using SIN() signals
|
||||
/// 2) obtains a window of the signal
|
||||
/// 3) applies the FFT
|
||||
/// 4) filters the signal
|
||||
/// 5) applies FFT of filtered signal
|
||||
/// </summary>
|
||||
|
||||
IEnumerator filterSignal()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
|
||||
// add point to the time chart
|
||||
double signal = 0;
|
||||
for (int jj = 0; jj < Amp.Length; jj++)
|
||||
{
|
||||
signal += (double)(Amp[jj] * Mathf.Sin(2 * Mathf.PI * (float)freq[jj] * (float)count * 1 / (float)samplingFrequency + (float)phase[jj]));
|
||||
}
|
||||
count++;
|
||||
|
||||
Y_values.Add(signal);
|
||||
|
||||
|
||||
if (Y_values.Count >= windowSize)
|
||||
{
|
||||
//ONE IS THE INPUT VALUES
|
||||
|
||||
//this is the window size
|
||||
for (int ii = 0; ii < windowSize; ii++)
|
||||
{
|
||||
X_inputValues[ii] = ii;
|
||||
|
||||
|
||||
X_inputValues[ii] = ii;
|
||||
Y_inputValues[ii] = (Y_values[ii + Y_values.Count - 1 - windowSize]);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//perform complex opterations and set up the arrays
|
||||
Complex[] inputSignal_Time = new Complex[windowSize];
|
||||
Complex[] outputSignal_Freq = new Complex[windowSize];
|
||||
|
||||
|
||||
inputSignal_Time = FastFourierTransform.doubleToComplex(Y_inputValues);
|
||||
|
||||
|
||||
//result is the iutput values once FFT has been applied
|
||||
outputSignal_Freq = FastFourierTransform.FFT(inputSignal_Time, false);
|
||||
|
||||
|
||||
Y_output = new double[windowSize];
|
||||
//get module of complex number
|
||||
for (int ii = 0; ii < windowSize; ii++)
|
||||
{
|
||||
//Debug.Log(ii);
|
||||
Y_output[ii] = (double)Complex.Abs(outputSignal_Freq[ii]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//filter process
|
||||
if (filtermode==filterMode.low_pass)
|
||||
{
|
||||
Y_inputValues_filtered = Filters.low_pass_band(Y_inputValues, alpha);
|
||||
}
|
||||
else if (filtermode == filterMode.high_pass)
|
||||
{
|
||||
Y_inputValues_filtered = Filters.high_pass_band(Y_inputValues, alpha);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//recalculate FFT of filtered
|
||||
//perform complex opterations and set up the arrays
|
||||
inputSignal_Time = new Complex[windowSize];
|
||||
outputSignal_Freq = new Complex[windowSize];
|
||||
|
||||
inputSignal_Time = FastFourierTransform.doubleToComplex(Y_inputValues_filtered);
|
||||
|
||||
//result is the iutput values once FFT has been applied
|
||||
outputSignal_Freq = FastFourierTransform.FFT(inputSignal_Time, false);
|
||||
|
||||
|
||||
Y_output_filtered = new double[windowSize];
|
||||
//get module of complex number
|
||||
for (int ii = 0; ii < windowSize; ii++)
|
||||
{
|
||||
//Debug.Log(ii);
|
||||
Y_output_filtered[ii] = (double)Complex.Abs(outputSignal_Freq[ii]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
yield return new WaitForFixedUpdate();
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void FixedUpdate()
|
||||
{
|
||||
//draw both charts: time-domain and frequency-domain
|
||||
Drawing.drawChart(tfTime, X_inputValues, Y_inputValues, "time");
|
||||
Drawing.drawChart(tfFreq, X_inputValues, Y_output, "frequency");
|
||||
|
||||
//draw both charts: time-domain and frequency-domain
|
||||
Drawing.drawChart(tfTime_filt, X_inputValues, Y_inputValues_filtered, "time");
|
||||
Drawing.drawChart(tfFreq_filt, X_inputValues, Y_output_filtered, "frequency");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 867c2404c3444e14da2df1dd6800be23
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 152492
|
||||
packageName: FFT Fast Fourrier Transform
|
||||
packageVersion: 1.0
|
||||
assetPath: Assets/FFT fast fourrier transform/Scripts/Example02_filtering.cs
|
||||
uploadId: 325757
|
||||
@@ -0,0 +1,139 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using System.Numerics;
|
||||
|
||||
public class Example03_soundTreatment : MonoBehaviour
|
||||
{
|
||||
|
||||
|
||||
[Space]
|
||||
[Header("[!] set fixed time to 0.01f [!]")]
|
||||
[Header("sound treatment")]
|
||||
[Space]
|
||||
|
||||
//samplingfrequency
|
||||
public int samplingFrequency;
|
||||
|
||||
//input-output values for the FFT
|
||||
double [] X_inputValues;
|
||||
double [] Y_inputValues;
|
||||
double[] Y_output;
|
||||
|
||||
|
||||
//list with the input values
|
||||
public List<double> Y_values;
|
||||
|
||||
//these are the frequencies, amplitude and phase of the sinus added to the signal
|
||||
[Space(10)]
|
||||
[Header("This is the noise to analyse")]
|
||||
[Space]
|
||||
public AudioClip audioC;
|
||||
public AudioSource audioS;
|
||||
|
||||
|
||||
//counts the steps taken
|
||||
long count = 0;
|
||||
|
||||
//the chart transforms for the time and frequency
|
||||
[Space(10)]
|
||||
[Header("CHARTS FOR DRAWING")]
|
||||
[Space]
|
||||
public Transform tfTime;
|
||||
public Transform tfFreq;
|
||||
|
||||
//window size
|
||||
public long windowSize;
|
||||
|
||||
void Start()
|
||||
{
|
||||
windowSize = audioS.clip.samples * audioS.clip.channels;
|
||||
|
||||
audioS.clip = audioC;
|
||||
audioS.Play();
|
||||
|
||||
//initialize
|
||||
X_inputValues = new double[windowSize];
|
||||
Y_inputValues = new double[windowSize];
|
||||
Y_output = new double[windowSize];
|
||||
|
||||
StartCoroutine(treatmentOfSound());
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This corrutine obtains these steps in order:
|
||||
/// 1) gets the data from the audiosource
|
||||
/// 2) displays the signal in time domain
|
||||
/// 3) displays the signal in FFT
|
||||
/// </summary>
|
||||
|
||||
IEnumerator treatmentOfSound()
|
||||
{
|
||||
|
||||
//ONE IS THE INPUT VALUES
|
||||
float[] samples = new float[windowSize];
|
||||
|
||||
audioS.clip.GetData(samples, 0);
|
||||
|
||||
|
||||
//this is the window size
|
||||
for (int ii = 0; ii < windowSize; ii++)
|
||||
{
|
||||
X_inputValues[ii] = ii;
|
||||
Y_inputValues[ii] =(double)samples[ii];
|
||||
|
||||
}
|
||||
|
||||
|
||||
//perform complex opterations and set up the arrays
|
||||
Complex[] inputSignal_Time = new Complex[windowSize];
|
||||
Complex[] outputSignal_Freq = new Complex[windowSize];
|
||||
|
||||
|
||||
inputSignal_Time = FastFourierTransform.doubleToComplex(Y_inputValues);
|
||||
|
||||
|
||||
//result is the iutput values once FFT has been applied
|
||||
outputSignal_Freq = FastFourierTransform.FFT(inputSignal_Time, false);
|
||||
|
||||
|
||||
Y_output = new double[windowSize];
|
||||
//get module of complex number
|
||||
for (int ii = 0; ii < windowSize; ii++)
|
||||
{
|
||||
//Debug.Log(ii);
|
||||
Y_output[ii] = (double)Complex.Abs(outputSignal_Freq[ii]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
yield return null;
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void FixedUpdate()
|
||||
{
|
||||
//draw both charts: time-domain and frequency-domain
|
||||
Drawing.drawChart(tfTime, X_inputValues, Y_inputValues, "time");
|
||||
Drawing.drawChart(tfFreq, X_inputValues, Y_output, "frequency");
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 48de1f8e70e299f469ac55f6789258fb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 152492
|
||||
packageName: FFT Fast Fourrier Transform
|
||||
packageVersion: 1.0
|
||||
assetPath: Assets/FFT fast fourrier transform/Scripts/Example03_soundTreatment.cs
|
||||
uploadId: 325757
|
||||
@@ -0,0 +1,137 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using System.Numerics;
|
||||
|
||||
public class FastFourierTransform : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// A fast Fourier transform (FFT) is an algorithm that computes the discrete Fourier transform (DFT) of a sequence.
|
||||
/// It converts a signal from its original domain (often time or space) to a representation in the frequency domain
|
||||
/// </summary>
|
||||
///
|
||||
|
||||
//the FFT returns a complex array of numbers given a input array of complex numbers.
|
||||
public static Complex[] FFT(Complex[] input, bool invert)
|
||||
{
|
||||
//in case there is only one element
|
||||
if (input.Length == 1)
|
||||
{
|
||||
return new Complex[] { input[0] };
|
||||
}
|
||||
|
||||
//for more elements we need to otain the lenght of the input data stream
|
||||
int length = input.Length;
|
||||
|
||||
//half will be the half of the lenght
|
||||
int half = length / 2;
|
||||
|
||||
//this is the result of the FFT
|
||||
Complex[] result = new Complex[length];
|
||||
|
||||
// factor that goes in the
|
||||
double factorEXP = -2.0 * Math.PI / length;
|
||||
|
||||
//in case we want to invert the factor
|
||||
if (invert)
|
||||
{
|
||||
factorEXP = -factorEXP;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Cooley–Tukey algorithm. This is a divide and conquer algorithm that recursively breaks down a DFT of any composite size N = N1N2 into many smaller DFTs of sizes N1 and N2,
|
||||
// it is divided into even and odd components
|
||||
//
|
||||
|
||||
//even
|
||||
Complex[] evens = new Complex[half];
|
||||
for (int i = 0; i < half; i++)
|
||||
{
|
||||
evens[i] = input[2 * i];
|
||||
}
|
||||
//FFT recursive call
|
||||
Complex[] evenResult = FFT(evens, invert);
|
||||
|
||||
//odd
|
||||
Complex[] odds = evens;
|
||||
for (int i = 0; i < half; i++)
|
||||
{
|
||||
odds[i] = input[2 * i + 1];
|
||||
}
|
||||
// FFT recursive call
|
||||
Complex[] oddResult = FFT(odds, invert);
|
||||
|
||||
|
||||
// final algorithm
|
||||
// N/2-1 N/2-1
|
||||
// FFT_k= SUM X_2n ·e^(-2*pi*(2n)*k)/(N/2) + SUM X_2n+1 ·e^(-2*pi*(2n+1)*k)/(N/2)
|
||||
// 0 0
|
||||
//
|
||||
// = Even_k + O_k·e^(-2*pi**k)/(N)
|
||||
|
||||
for (int k = 0; k < half; k++)
|
||||
{
|
||||
double factor_K = factorEXP * k;
|
||||
|
||||
// odd part & this is the second part that is added module 1 argument factor_k
|
||||
Complex oddComponent = oddResult[k] * new Complex(1*Math.Cos(factor_K), 1*Math.Sin(factor_K));
|
||||
|
||||
//first part of the chart
|
||||
result[k] = evenResult[k] + oddComponent;
|
||||
//second part of the chart
|
||||
result[k + half] = evenResult[k] - oddComponent;
|
||||
}
|
||||
|
||||
//reutrn the values (complex). To show FFT we need to display module or "abs" of the complex number
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Complex[] doubleToComplex(double[] inp)
|
||||
{
|
||||
Complex[] outp = new Complex[inp.Length];
|
||||
|
||||
//convert to complex number
|
||||
for (int ii = 0; ii < inp.Length; ii++)
|
||||
{
|
||||
|
||||
outp[ii] = new Complex(inp[ii], 0);
|
||||
}
|
||||
|
||||
return outp;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// maximum and minimum funtions for double arrays
|
||||
/// </summary>
|
||||
|
||||
public static double MaxD(double[] inp)
|
||||
{
|
||||
double outp = -1e10;
|
||||
|
||||
for (int ii = 0; ii < inp.Length; ii++)
|
||||
{
|
||||
if (inp[ii] > outp)
|
||||
{
|
||||
outp = inp[ii];
|
||||
}
|
||||
}
|
||||
|
||||
return outp;
|
||||
}
|
||||
|
||||
public static double MinD(double[] inp)
|
||||
{
|
||||
double outp = 1e10;
|
||||
|
||||
for (int ii = 0; ii < inp.Length; ii++)
|
||||
{
|
||||
if (inp[ii] < outp)
|
||||
{
|
||||
outp = inp[ii];
|
||||
}
|
||||
}
|
||||
|
||||
return outp;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 77ef741c346e2a844aeebd52cc140f1c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 152492
|
||||
packageName: FFT Fast Fourrier Transform
|
||||
packageVersion: 1.0
|
||||
assetPath: Assets/FFT fast fourrier transform/Scripts/FastFourierTransform.cs
|
||||
uploadId: 325757
|
||||
@@ -0,0 +1,38 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public static class Filters
|
||||
{
|
||||
//high pass filter
|
||||
public static double[] high_pass_band(double[] inp, double alpha)
|
||||
{
|
||||
double[] outp = new double[inp.Length];
|
||||
|
||||
outp[0] = alpha * inp[0];
|
||||
|
||||
for (int jj = 1; jj < inp.Length; jj++)
|
||||
{
|
||||
outp[jj] = alpha * (outp[jj - 1]) + alpha * (inp[jj] - inp[jj - 1]);
|
||||
}
|
||||
|
||||
return outp;
|
||||
|
||||
}
|
||||
|
||||
// low pass filter
|
||||
public static double[] low_pass_band(double[] inp, double alpha)
|
||||
{
|
||||
double[] outp = new double[inp.Length];
|
||||
|
||||
outp[0] = alpha * inp[0];
|
||||
|
||||
for (int jj = 1; jj < inp.Length; jj++)
|
||||
{
|
||||
outp[jj] = alpha * (inp[jj]) + (1-alpha) * (outp[jj - 1]);
|
||||
}
|
||||
|
||||
return outp;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1d6135e9a9ceeda4ca239d8c421ede11
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 152492
|
||||
packageName: FFT Fast Fourrier Transform
|
||||
packageVersion: 1.0
|
||||
assetPath: Assets/FFT fast fourrier transform/Scripts/Filters.cs
|
||||
uploadId: 325757
|
||||
Reference in New Issue
Block a user