c# Threading a nested loop function with two separate jobs per execution - c#

I am trying to improve the speed of my program without changing the algorithm.
Currently I use this implementation of DFT:
public double[] dft(double[] data) {
int n = data.Length;
int m = n;// I use m = n / 2d;
float[] real = new float[n];
float[] imag = new float[n];
double[] result = new double[m];
float pi_div = (float)(2.0 * Math.PI / n);
for (int w = 0; w < m; w++) {
float a = w * pi_div;
for (int t = 0; t < n; t++) {
real[w] += (float)(data[t] * Math.Cos(a * t)); //thinking of threading this
imag[w] += (float)(data[t] * Math.Sin(a * t)); //and this
}
result[w] = (float)(Math.Sqrt(real[w] * real[w] + imag[w] * imag[w]) / n);
}
return result;
}
It is rather slow but it has one spot where I can see improvements can be made.
The internal parts of the functions are two separate tasks. The real and imaginary summations can be done separately but should always join to calculate the result.
Any ideas? I tried a few implementations I saw on the web but they all crashed and I have very little threading experience.

When you have a CPU bound algorithm that can be parallelized you can easily transform you single threaded implementation into a multi-threaded using the Parallel class.
In your case you have two nested loops but the number of iterations of the outer loop is much larger than the number of CPU cores you can execute on so it is only necessary to parallelize the outer loop to get all cores spinning:
public double[] ParallelDft(double[] data) {
int n = data.Length;
int m = n;// I use m = n / 2d;
float[] real = new float[n];
float[] imag = new float[n];
double[] result = new double[m];
float pi_div = (float)(2.0 * Math.PI / n);
Parallel.For(0, m,
w => {
float a = w * pi_div;
for (int t = 0; t < n; t++) {
real[w] += (float)(data[t] * Math.Cos(a * t)); //thinking of threading this
imag[w] += (float)(data[t] * Math.Sin(a * t)); //and this
}
result[w] = (float)(Math.Sqrt(real[w] * real[w] + imag[w] * imag[w]) / n);
}
);
return result;
}
I have taken your code and replaced the outer for loop with Parallel.For. On my computer with eight hyper-threaded cores I get a sevenfold increase in execution speed.
Another way to increase the execution speed is to employ the SIMD instruction set on the CPU. The System.Numerics.Vectors library and the Yeppp! library allows you to call SIMD instructions from managed code but it will require some work on your behalf to implement the algorithm using these instructions.

You should create a new Task for inner For, and each task will save result in a thread safe dictionary (ConcurrentDictionary).
I think following code be useful:
public ConcurrentDictionary<int, double> result = new ConcurrentDictionary<int, double>();
public void dft(double[] data)
{
int n = data.Length;
int m = n;// I use m = n / 2d;
float pi_div = (float)(2.0 * Math.PI / n);
for (int w = 0; w < m; w++)
{
var w1 = w;
Task.Factory.StartNew(() =>
{
float a = w1*pi_div;
float real = 0;
float imag=0;
for (int t = 0; t < n; t++)
{
real += (float)(data[t] * Math.Cos(a * t));
imag += (float)(data[t] * Math.Sin(a * t));
}
result.TryAdd(w1, (float) (Math.Sqrt(real*real + imag*imag)/n));
});
}
}

Related

How to speed up nested loops in C#

This is a piece of my code, which calculate the differentiate. It works correctly but it takes a lot (because of height and width).
"Data" is a grey image bitmap.
"Filter" is [3,3] matrix.
"fh" and "fw" maximum values are 3.
I am looking to speed up this code.
I also tried with using parallel, for but it didn't work correct (error with out of bounds).
private float[,] Differentiate(int[,] Data, int[,] Filter)
{
int i, j, k, l, Fh, Fw;
Fw = Filter.GetLength(0);
Fh = Filter.GetLength(1);
float sum = 0;
float[,] Output = new float[Width, Height];
for (i = Fw / 2; i <= (Width - Fw / 2) - 1; i++)
{
for (j = Fh / 2; j <= (Height - Fh / 2) - 1; j++)
{
sum=0;
for(k = -Fw/2; k <= Fw/2; k++)
{
for(l = -Fh/2; l <= Fh/2; l++)
{
sum = sum + Data[i+k, j+l] * Filter[Fw/2+k, Fh/2+l];
}
}
Output[i,j] = sum;
}
}
return Output;
}
For parallel execution you need to drop c language like variable declaration at the beginning of method and declare them in actual scope that they are used so they are not shared between threads. Making it parallel should provide some benefit for performance, but making them all ParallerFors is not a good idea as there is a limit for threads amount that actually can run in parallel. I would try to make it with top level loop only:
private static float[,] Differentiate(int[,] Data, int[,] Filter)
{
var Fw = Filter.GetLength(0);
var Fh = Filter.GetLength(1);
float[,] Output = new float[Width, Height];
Parallel.For(Fw / 2, Width - Fw / 2 - 1, (i, state) =>
{
for (var j = Fh / 2; j <= (Height - Fh / 2) - 1; j++)
{
var sum = 0;
for (var k = -Fw / 2; k <= Fw / 2; k++)
{
for (var l = -Fh / 2; l <= Fh / 2; l++)
{
sum = sum + Data[i + k, j + l] * Filter[Fw / 2 + k, Fh / 2 + l];
}
}
Output[i, j] = sum;
}
});
return Output;
}
This is a perfect example of a task where using the GPU is better than using the CPU. A GPU is able to perform trillions of floating point operations per second (TFlops), while CPU performance is still measured in GFlops. The catch is that it's only any good if you use SIMD instructions (Single Instruction Multiple Data). The GPU excels at data-parallel tasks. If different data needs different instructions, using the GPU has no advantage.
In your program, the elements of your bitmap go through the same calculations: the same computations just with slightly different data (SIMD!). So using the GPU is a great option. This won't be too complex because with your calculations threads on the GPU would not need to exchange information, nor would they be dependent on results of previous iterations (Each element would be processed by a different thread on the GPU).
You can use, for example, OpenCL to easily access the GPU. More on OpenCL and using the GPU here: https://www.codeproject.com/Articles/502829/GPGPU-image-processing-basics-using-OpenCL-NET

What is the Output of a fftLeft array after applying FFTDb function to a waveLeft array C# .Frequencies, or something else?

I am a newcomer to the sound programming. I have a real-time sound visualizer(http://www.codeproject.com/Articles/20025/Sound-visualizer-in-C). I downloaded it from codeproject.com.
In AudioFrame.cs class there is an array as below:
_fftLeft = FourierTransform.FFTDb(ref _waveLeft);
_fftLeft is a double array. _waveLeft is also a double array. As above they applied
FouriorTransform.cs class's FFTDb function to a _waveLeft array.
Here is FFTDb function:
static public double[] FFTDb(ref double[] x)
{
n = x.Length;
nu = (int)(Math.Log(n) / Math.Log(2));
int n2 = n / 2;
int nu1 = nu - 1;
double[] xre = new double[n];
double[] xim = new double[n];
double[] decibel = new double[n2];
double tr, ti, p, arg, c, s;
for (int i = 0; i < n; i++)
{
xre[i] = x[i];
xim[i] = 0.0f;
}
int k = 0;
for (int l = 1; l <= nu; l++)
{
while (k < n)
{
for (int i = 1; i <= n2; i++)
{
p = BitReverse(k >> nu1);
arg = 2 * (double)Math.PI * p / n;
c = (double)Math.Cos(arg);
s = (double)Math.Sin(arg);
tr = xre[k + n2] * c + xim[k + n2] * s;
ti = xim[k + n2] * c - xre[k + n2] * s;
xre[k + n2] = xre[k] - tr;
xim[k + n2] = xim[k] - ti;
xre[k] += tr;
xim[k] += ti;
k++;
}
k += n2;
}
k = 0;
nu1--;
n2 = n2 / 2;
}
k = 0;
int r;
while (k < n)
{
r = BitReverse(k);
if (r > k)
{
tr = xre[k];
ti = xim[k];
xre[k] = xre[r];
xim[k] = xim[r];
xre[r] = tr;
xim[r] = ti;
}
k++;
}
for (int i = 0; i < n / 2; i++)
decibel[i] = 10.0 * Math.Log10((float)(Math.Sqrt((xre[i] * xre[i]) + (xim[i] * xim[i]))));
return decibel;
}
When I play a music note in a guitar i wanted to know it's frequency in a numerical format. I wrote a foreach loop to know what is the output of a _fftLeft array as below,
foreach (double myarray in _fftLeft)
{
Console.WriteLine(myarray );
}
This output's contain lots of real-time values as below .
41.3672743963389
,43.0176034462662,
35.3677383746087,
42.5968946936404,
42.0600935794783,
36.7521669642071,
41.6356709559342,
41.7189032845742,
41.1002451261724,
40.8035583510188,
45.604366914128,
39.645552593115
I want to know what are those values (frequencies or not)? if the answer is frequencies then why it contains low frequency values? And when I play a guitar note I want to detect a frequency of that particular guitar note.
Based on the posted code, FFTDb first computes the FFT then computes and returns the magnitudes of the frequency spectrum in the logarithmic decibels scale. In other words, the _fftLeft then contains magnitudes for a discreet set of frequencies. The actual values of those frequencies can be computed using the array index and sampling frequency according to this answer.
As an example, if you were plotting the _fftLeft output for a pure sinusoidal tone input you should be able to see a clear spike in the index corresponding to the sinusoidal frequency. For a guitar note however you are likely going to see multiple spikes in magnitude corresponding to the harmonics. To detect the note's frequency aka pitch is a more complicated topic and typically requires the use of one of several pitch detection algorithms.

C# Exp cannot get result

When I using Math.Exp() in C# I have some questions?This code is about Kernel density estimation, and I don't have any knowledge about kernel density estimation. So I look up some wiki and some paper.
I try to write it by C#. The problem is when "distance" is getting higher the result is become 0. It's confuse me and I cannot find any other way to get the right result.
disExp = Math.Pow(Math.E, -(distance / 2 * Math.Pow(h, 2)));
So, can any one help me to get the solution? Or give me some idea about Kernel density estimation on C#. Sorry for poor English.
Try this
public static double[,] KernelDensityEstimation(double[] data, double sigma, int nsteps)
{
// probability density function (PDF) signal analysis
// Works like ksdensity in mathlab.
// KDE performs kernel density estimation (KDE)on one - dimensional data
// http://en.wikipedia.org/wiki/Kernel_density_estimation
// Input: -data: input data, one-dimensional
// -sigma: bandwidth(sometimes called "h")
// -nsteps: optional number of abscis points.If nsteps is an
// array, the abscis points will be taken directly from it. (default 100)
// Output: -x: equispaced abscis points
// -y: estimates of p(x)
// This function is part of the Kernel Methods Toolbox(KMBOX) for MATLAB.
// http://sourceforge.net/p/kmbox
// Converted to C# code by ksandric
double[,] result = new double[nsteps, 2];
double[] x = new double[nsteps], y = new double[nsteps];
double MAX = Double.MinValue, MIN = Double.MaxValue;
int N = data.Length; // number of data points
// Find MIN MAX values in data
for (int i = 0; i < N; i++)
{
if (MAX < data[i])
{
MAX = data[i];
}
if (MIN > data[i])
{
MIN = data[i];
}
}
// Like MATLAB linspace(MIN, MAX, nsteps);
x[0] = MIN;
for (int i = 1; i < nsteps; i++)
{
x[i] = x[i - 1] + ((MAX - MIN) / nsteps);
}
// kernel density estimation
double c = 1.0 / (Math.Sqrt(2 * Math.PI * sigma * sigma));
for (int i = 0; i < N; i++)
{
for (int j = 0; j < nsteps; j++)
{
y[j] = y[j] + 1.0 / N * c * Math.Exp(-(data[i] - x[j]) * (data[i] - x[j]) / (2 * sigma * sigma));
}
}
// compilation of the X,Y to result. Good for creating plot(x, y)
for (int i = 0; i < nsteps; i++)
{
result[i, 0] = x[i];
result[i, 1] = y[i];
}
return result;
}
kernel density estimation C#
plot

Weird glitch when creating sine audio signal

I had a look at the wave format today and created a little wave generator. I create a sine sound like this:
public static Wave GetSine(double length, double hz)
{
int bitRate = 44100;
int l = (int)(bitRate * length);
double f = 1.0 / bitRate;
Int16[] data = new Int16[l];
for (int i = 0; i < l; i++)
{
data[i] = (Int16)(Math.Sin(hz * i * f * Math.PI * 2) * Int16.MaxValue);
}
return new Wave(false, Wave.MakeInt16WaveData(data));
}
MakeInt16WaveData looks like this:
public static byte[] MakeInt16WaveData(Int16[] ints)
{
int s = sizeof(Int16);
byte[] buf = new byte[s * ints.Length];
for(int i = 0; i < ints.Length; i++)
{
Buffer.BlockCopy(BitConverter.GetBytes(ints[i]), 0, buf, i * s, s);
}
return buf;
}
This works as expected! Now I wanted to swoop from one frequency to another like this:
public static Wave GetSineSwoop(double length, double hzStart, double hzEnd)
{
int bitRate = 44100;
int l = (int)(bitRate * length);
double f = 1.0 / bitRate;
Int16[] data = new Int16[l];
double hz;
double hzDelta = hzEnd - hzStart;
for (int i = 0; i < l; i++)
{
hz = hzStart + ((double)i / l) * hzDelta * 0.5; // why *0.5 ?
data[i] = (Int16)(Math.Sin(hz * i * f * Math.PI * 2) * Int16.MaxValue);
}
return new Wave(false, Wave.MakeInt16WaveData(data));
}
Now, when I swooped from 200 to 100 Hz, the sound played from 200 to 0 hertz. For some reason I had to multiply the delta by 0.5 to get the correct output. What might be the issue here ? Is this an audio thing or is there a bug in my code ?
Thanks
Edit by TaW: I take the liberty to add screenshots of the data in a chart which illustrate the problem, the first is with the 0.5 factor, the 2nd with 1.0 and the 3rd & 4th with 2.0 and 5.0:
Edit: here is an example, a swoop from 200 to 100 hz:
Debug values:
Wave clearly does not end at 100 hz
Digging out my rusty math I think it may be because:
Going in L steps from frequency F1 to F2 you have a frequency of
Fi = F1 + i * ( F2 - F1 ) / L
or with
( F2 - F1 ) / L = S
Fi = F1 + i * S
Now to find out how far we have progressed we need the integral over i, which would be
I(Fi) = i * F1 + 1/2 * i ^ 2 * S
Which give or take resembles the term inside your formula for the sine.
Note that you can gain efficiency by moving the constant part (S/2) out of the loop..

Difficulty creating classes and constructors C#

I'm trying to implement a Discrete Fourier Transformation algorithm for a project I'm doing in school. But creating a class is seeming to be difficult(which it shouldn't be).
I'm using Visual Studio 2012.
Basically I need a class called Complex to store the two values I get from a DFT; The real portion and the imaginary portion.
This is what I have so far for that:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SoundEditor_V3
{
public class Complex
{
public double real;
public double im;
public Complex()
{
real = 0;
im = 0;
}
}
}
The problem is that it doesn't recognize the constructor as a constructor, I'm just learning C#, but I looked it up online and this is how it's supposed to look.
But it recognizes my constructor as a method.
Why is that?
Am I creating the class wrong?
It's doing the same thing for my Fourier class as well. So each time I try to create a
Fourier object and then use it's method...there is no such thing.
example, I do this:
Fourier fou = new Fourier();
fou.DFT(s, N, amp, 0);
and it tells me fou is a 'field' but is used like a 'type'
why is it saying that?
Here is the code for my Fourier class as well:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SoundEditor_V3
{
public class Fourier
{
//FOURIER
//N = number of samples
//s is the array of samples(data)
//amp is the array where the complex result will be written to
//start is the where in the array to start
public void DFT(byte[] s, int N, ref Complex[] amp, int start)
{
Complex tem = new Complex();
int f;
int t;
for (f = 0; f < N; f++)
{
tem.real = 0;
tem.im = 0;
for (t = 0; t < N; t++)
{
tem.real += s[t + start] * Math.Cos(2 * Math.PI * t * f / N);
tem.im -= s[t + start] * Math.Sin(2 * Math.PI * t * f / N);
}
amp[f].real = tem.real;
amp[f].im = tem.im;
}
}
//INVERSE FOURIER
public void IDFT(Complex[] A, ref int[] s)
{
int N = A.Length;
int t, f;
double result;
for (t = 0; t < N; t++)
{
result = 0;
for (f = 0; f < N; f++)
{
result += A[f].real * Math.Cos(2 * Math.PI * t * f / N) - A[f].im * Math.Sin(2 * Math.PI * t * f / N);
}
s[t] = (int)Math.Round(result);
}
}
}
}
I'm very much stuck at the moment, any and all help would be appreciated. Thank you.
edit:
this is where I'm trying to access all my classes:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace SoundEditor_V3
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
string filename;
NAudio.Wave.WaveStream waveStream;
private NAudio.Wave.DirectSoundOut sout = null;
private void openToolStripMenuItem_Click(object sender, EventArgs e)
{
OpenFileDialog open = new OpenFileDialog();
open.Filter = "Wave File (*.wav)|*.wav";
if (open.ShowDialog() != DialogResult.OK)
{
return;
}
waveStream = new NAudio.Wave.WaveFileReader(open.FileName);
filename = open.FileName;
sout = new NAudio.Wave.DirectSoundOut();
sout.Init(new NAudio.Wave.WaveChannel32(waveStream));
}
//Play
private void Play_btn_Click(object sender, EventArgs e)
{
sout.Play();
}
//Stop
private void Stop_btn_Click(object sender, EventArgs e)
{
sout.Stop();
waveStream.Position = 0;
}
//Pause
private void Pause_btn_Click(object sender, EventArgs e)
{
sout.Pause();
}
//display fourier
//N = number of samples(length of array)
//s is the array of samples(data)
//amp is the array where the complex result will be written to
//start is the where in the array to start
static int N = 8;
byte[] s = {1,2,3,4,5,6,7,8};
Complex[] amp = new Complex[N];
Fourier xfo = new Fourier();
//xfo.DFT(s, N, amp, 0);
}
}
This call should be inside a method. As of now, it looks its directly under a class.
//xfo.DFT(s, N, amp, 0);
Also add ref for amp. (As the void DFT(...., ref Complex[] amp,....) takes a ref amp parameter.
xfo.DFT(s, N, ref amp, 0);
Oh boy, so much room to improve.
First you are using the class Complex as a struct, in fact there is no need for it to be a class, so make it a struct:
public struct Complex
{
public double Imaginary;
public double Real;
}
No constructor needed, the default constructor (which the compilers add) will set the fields to their default value according to their type, and for double the default value is 0.0 (which is what you are assigning to them anyway*).
I have also renamed im to Imaginary, and don't tell me you have to type more because you got intellisense. If you didn't go download Mono Develop or Visual Studio Express. Oh, I can feel your thinking: we shouldn't relay on the tools. Well, that's right, and that is another reason to write code that is easy to read, even for those unfamiliar with the concepts (it also makes searching easier).
*: I want to note that 0 is a intenger literal and 0.0 is double, but the compiler reconizes this and optimizes the conversion away, so it is the same for practical purposes.
Let's move to your fourier class, first the method DFT, which I copy below (with the names of the fields of Complex renamed):
//FOURIER
//N = number of samples
//s is the array of samples(data)
//amp is the array where the complex result will be written to
//start is the where in the array to start
public void DFT(byte[] s, int N, ref Complex[] amp, int start)
{
Complex tem = new Complex();
int f;
int t;
for (f = 0; f < N; f++)
{
tem.real = 0;
tem.im = 0;
for (t = 0; t < N; t++)
{
tem.real += s[t + start] * Math.Cos(2 * Math.PI * t * f / N);
tem.im -= s[t + start] * Math.Sin(2 * Math.PI * t * f / N);
}
amp[f].real = tem.real;
amp[f].im = tem.im;
}
}
The first thing to notice is that you say that N is the number of samples and s is the samples array. Well, if you have an array you can query the size of the array, which is a good idea even if you want to allow to only process a portion of the array (I think you want that). But, really N and s?
Look, it's like magic:
//FOURIER
//amp is the array where the complex result will be written to
//start is the where in the array to start
public void DFT(byte[] samples, int samplesCount, ref Complex[] amp, int start)
{
Complex tem = new Complex();
int f;
int t;
for (f = 0; f < samplesCount; f++)
{
tem.Real = 0;
tem.Imaginary = 0;
for (t = 0; t < samplesCount; t++)
{
tem.Imaginary += samples[t + start] * Math.Cos(2 * Math.PI * t * f / samplesCount);
tem.Imaginary -= samples[t + start] * Math.Sin(2 * Math.PI * t * f / samplesCount);
}
amp[f].Real = tem.Real;
amp[f].Imaginary = tem.Imaginary;
}
}
Ok, next you say that amp is the output. Well if it is the output, why don't you make it te method return it?
Bam!
//FOURIER
//start is the where in the array to start
Complex[] DFT(byte[] samples, int samplesCount, int start)
{
var = new Complex[samplesCount];
Complex tem = new Complex();
int f;
int t;
for (f = 0; f < samplesCount; f++)
{
tem.Real = 0;
tem.Imaginary = 0;
for (t = 0; t < samplesCount; t++)
{
tem.Imaginary += samples[t + start] * Math.Cos(2 * Math.PI * t * f / samplesCount);
tem.Imaginary -= samples[t + start] * Math.Sin(2 * Math.PI * t * f / samplesCount);
}
result[f].Real = tem.Real;
result[f].Imaginary = tem.Imaginary;
}
return result;
}
Does it really need to be an array? I think this is a good oportunity to use the yield keyword and return IEnumerable<Complex>. But I'll take that you want, in deed, an array.
Now, may be you didn't want to return an array. May be you want to just modify portions of a preexisting array. In that case you should start checking your bounds. And even if that were true, you don't need ref at all! because the array is a reference type. It is a reference passed by value, if you cannot wrap your mind around that idea, just trust me, you can modify the contents of an array and see that reflected outside without ref... passing a reference by reference allows you to change the reference by another one, and you are not doing that.
To demostrate:
void Main()
{
var x = new int[1];
Do(x);
Console.WriteLine(x);
}
void Do (int[] array)
{
array[0] = 1;
}
The output of the previous program (compiled with LinqPad) is "1".
But let's get back to your code, shall we?
I don't know what are f and t. Thankfully I knew that im was imaginary (it was, right?). So I'll not rename them. But I'll move their definition to the loops:
Complex[] DFT(byte[] samples, int samplesCount, int start)
{
var result = new Complex[samplesCount];
Complex tem = new Complex();
for (int f = 0; f < samplesCount; f++)
{
tem.Real = 0;
tem.Imaginary = 0;
for (int t = 0; t < samplesCount; t++)
{
tem.Imaginary += samples[t + start] * Math.Cos(2 * Math.PI * t * f / samplesCount);
tem.Imaginary -= samples[t + start] * Math.Sin(2 * Math.PI * t * f / samplesCount);
}
result[f].Real = tem.Real;
result[f].Imaginary = tem.Imaginary;
}
return result;
}
Note my use of the var keyword. With it the compiler assigns the type of the variable to the type of what I'm using to initialize it. So in this case result is a Complex[] but I did not have to write that twice in the code.
And finally, that part where you copy the contents of the Complex object, well, I'll change that too. Why? Because Complex now is a struct, and structs are valuetypes. So it's content gets copied instead of a reference.
//FOURIER
//start is the where in the array to start
Complex[] DFT(byte[] samples, int samplesCount, int start)
{
var result = new Complex[samplesCount];
Complex tem = new Complex();
for (int f = 0; f < samplesCount; f++)
{
tem.Real = 0;
tem.Imaginary = 0;
for (int t = 0; t < samplesCount; t++)
{
tem.Imaginary += samples[t + start] * Math.Cos(2 * Math.PI * t * f / samplesCount);
tem.Imaginary -= samples[t + start] * Math.Sin(2 * Math.PI * t * f / samplesCount);
}
result[f] = tem;
}
return result;
}
I know you really want to proccess just a part of your array. But bear with me... you will learn a few things and that code will be useful anyway.
The next thing I want is to return an IEnumerable<Complex> which is an interface that represents anything that can be iterated to get objects of type Complex. I'll also use the yield keyword.
Additionally I've got rid of sampleCount and use samples.Length instead.
Just look how beautiful it gets:
//FOURIER
public IEnumerable<Complex> DFT(byte[] samples, int startIndex)
{
int samplesLength = samples.Length;
for (int f = 0; f < samplesLength; f++)
{
Complex resultItem = new Complex();
for (int t = 0; t < samplesLength; t++)
{
resultItem.Real += samples[t + startIndex] * Math.Cos(2 * Math.PI * t * f / samplesLength);
resultItem.Imaginary -= samples[t + startIndex] * Math.Sin(2 * Math.PI * t * f / samplesLength);
}
yield return resultItem;
}
}
In fact, I'll get rid of startIndex too (we are not checking bounds anyway*).
*: that is, we are not checking if the index are inside the array size. I know, I know, you was going to add them later... probably.
Anyway, you are learning some C# here.
//FOURIER
public IEnumerable<Complex> DFT(byte[] samples)
{
int samplesLength = samples.Length;
for (int f = 0; f < samplesLength; f++)
{
Complex resultItem = new Complex();
for (int t = 0; t < samplesLength; t++)
{
resultItem.Real += samples[t] * Math.Cos(2 * Math.PI * t * f / samplesLength);
resultItem.Imaginary -= samples[t] * Math.Sin(2 * Math.PI * t * f / samplesLength);
}
yield return resultItem;
}
}
Well, the next thing that bothers me is the fact that the class Fourier has no state (it has no fields, or any variable which value is persisted... somehow). So, make it a static class with a static method:
public static class Fourier
{
//FOURIER
public static IEnumerable<Complex> DFT(byte[] samples)
{
int samplesLength = samples.Length;
for (int f = 0; f < samplesLength; f++)
{
Complex resultItem = new Complex();
for (int t = 0; t < samplesLength; t++)
{
resultItem.Real += samples[t] * Math.Cos(2 * Math.PI * t * f / samplesLength);
resultItem.Imaginary -= samples[t] * Math.Sin(2 * Math.PI * t * f / samplesLength);
}
yield return resultItem;
}
}
}
Of course you notice I haven't added IDFT. That one is homework.
Now, let's see how you use it. In my case I created a ConsoleApplication, just to have it up and running fast (no time wasted designing a GUI).
What I want is to call Fourier.DFT which I can without an object of type Fourier because it is static (In fact I cannot create an object of type Fourier because it is static).
This method recieves an argument of type byte[]. That one will be new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }. And that method will return something I can use to iterate over to get objects of type Complex. So I want to put it a loop.
This is how my code looks like:
class Program
{
static void Main(string[] args)
{
//display fourier
foreach (var item in Fourier.DFT(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }))
{
Console.WriteLine(item);
}
}
}
Now... the output is... drum roll...
Well, I can't see it, I forgot Console.ReadLine(); but after adding that the output is...
Namespace.Complex
Namespace.Complex
Namespace.Complex
Namespace.Complex
Namespace.Complex
Namespace.Complex
Namespace.Complex
Namespace.Complex
Wait, what? It happens that I haven't told it how to convert an object of type Complex to string. So let's add that:
public struct Complex
{
public double Imaginary;
public double Real;
public override string ToString()
{
return string.Format("Complex [Real: {0}, Imaginary: {1}]", Real, Imaginary);
}
}
Now my output is:
Complex [Real: 36, Imaginary: 0]
Complex [Real: -4, Imaginary: 9,65685424949238]
Complex [Real: -4, Imaginary: 4]
Complex [Real: -4, Imaginary: 1,65685424949239]
Complex [Real: -4, Imaginary: -3,91874033223161E-15]
Complex [Real: -4,00000000000001, Imaginary: -1,65685424949239]
Complex [Real: -4,00000000000002, Imaginary: -4,00000000000001]
Complex [Real: -3,99999999999997, Imaginary: -9,65685424949237]
Is the output correct? I have no freaking idea! I have to learn more about Fourier (but it looks legit).
After verification, the output is correct.
One final note: Step trhoug the code with a debuger, you may find a surprise (hint: yield).
You need a method, try this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SoundEditor_V3
{
public class Complex
{
public double real;
public double im;
public Complex()
{
real = 0;
im = 0;
}
public Setval (double newReal, double newIm)
{
real = newReal;
im = newIm;
}
}
}
In regards to your other class, where is the constructor? ;)
Thank you for all your help; I actually ended up figuring everything out.
I couldn't access methods in the area I was trying to access them in. I had to put them inside a method block because this was all being coded inside a form.
That's my understanding anyway.
But again, thank you for all your suggestions, they were all helpful.

Categories

Resources