FFT Fundamental frequency calculation from LomontFFT - c#

I am using the LomontFFT from http://www.lomont.org/Software/Misc/FFT/LomontFFT.html to get the fundamental frequency from sampled values of a signal. For testing if the fundamental frequency is correctly determined, I have used some samples from past (with known fundamental frequency).
Below is the code I have written to call the LomontFFT algo and determine the FFT:
private void buttonFFT_Click(object sender, EventArgs e)
{
//double fftavg = 0;
double fftmax = 0;
var fftData = new byte[512];
double[] fftValues = Enumerable.Repeat(0.0, 512).ToArray();
Array.Copy(sapmledDoubleValuesADC1, fftValues, sapmledDoubleValuesADC1.Length);
var fftMethod = new Lomont.LomontFFT();
fftMethod.RealFFT(fftValues, true);
for (int i = 0; i < 512; i += 2)
{
double fftmag = Math.Sqrt((fftValues[i] * fftValues[i]) + (fftValues[i + 1] * fftValues[i + 1]));
if (fftmag > fftmax)
fftmax = fftmag;
//fftavg += fftmag;
//fftData[i] = (byte)fftmag;
//fftData[i + 1] = fftData[i];
}
textBoxFundaFreq.Text = "Frey = " + fftmax.ToString();
for (int x = 1; x < 512; x++)
{
this.chart2.Series[0].Points.AddXY(x, fftValues[x]);
}
}
But the problem is the magnitude of the frequency is wrong. The FFT also doesn't match but that is possible as there are multiple solutions, but the frequency should be same. The algo is proven for many years so its definitely not wrong. Am I doing something wrong in calling code?
(I have only real values in sampled data)

Fundamental frequency extraction / pitch detection is not a simple algorithm. For most input signal (anything other than a single sine/cosine wave) the FFT will show several peaks and it is usually better to estimate the distance between this peaks.
Further you need to interpolate the FFT bins to get an acurate result for a single peak.
For most applications it is better to calculate the auto-correlation-function (ACF) anyway.

Related

How to use the Nelder Meade Simplex algorithm in mathdotnet for function maximization

In my C# program I have a dataset where each data point consists of:
a stimulus intensity (intensity) as x-coordinate
the percentage of correct response (percentageCorrect) to stimulus as y-coordinate
When the intensity is low percentageCorrect is low. When the intensity is high the percentageCorrect is high. The function graph is an S-shaped curve as the percentageCorrect reaches an asymptote at low and high ends.
I am trying to find the threshold intensity where percentageCorrect is half way between the asymtotes at either end (center of the S-shaped curve)
I understand this to be a function maximization problem that can be solved by the Nelder Meade Simplex algorithm.
I am trying to solve my problem using the Nelder Meade Simplex algorithm in mathdotnet and its IObjectiveFunction parameter.
However, I am having trouble understanding the API of the NedlerMeadeSimplex class FindMinimum method and the IObjectiveFunction EvaluateAt method.
I am new to numerical analysis that is pre-requisite for this question.
Specific questions are:
For the NedlerMeadeSimplex class FindMinimum method what are the initialGuess and initialPertubation parameters?
For the IObjectiveFunction EvaluateAt method, what is the point parameter? I vaguely understand that the point parameter is a datum in the dataset being minimized
How can I map my data set to this API and solve my problem?
Thanks for any guidance on this.
The initial guess is a guess at the model parameters.
I've always used the forms that don't require an entry of the initialPertubation parameter, so I can't help you there.
The objective function is what your are trying to minimize. For example, for a least squares fit, it would calculate the sum of squared areas at the point given in the argument. Something like this:
private double SumSqError(Vector<double> v)
{
double err = 0;
for (int i = 0; i < 100; i++)
{
double y_val = v[0] + v[1] * Math.Exp(v[2] * x[i]);
err += Math.Pow(y_val - y[i], 2);
}
return err;
}
You don't have to supply the point. The algorithm does that over and over while searching for the minimum. Note that the subroutine as access to the vector x.
Here is the code for a test program fitting a function to random data:
private void btnMinFit_Click(object sender, EventArgs e)
{
Random RanGen = new Random();
x = new double[100];
y = new double[100];
// fit exponential expression with three parameters
double a = 5.0;
double b = 0.5;
double c = 0.05;
// create data set
for (int i = 0; i < 100; i++) x[i] = 10 + Convert.ToDouble(i) * 90.0 / 99.0; // values span 10 to 100
for (int i = 0; i < 100; i++)
{
double y_val = a + b * Math.Exp(c * x[i]);
y[i] = y_val + 0.1 * RanGen.NextDouble() * y_val; // add error term scaled to y-value
}
// var fphv = new Func<double, double, double, double>((x, A, B) => A * x + B * x + A * B * x * x); extraneous test
var f1 = new Func<Vector<double>, double>(x => LogEval(x));
var obj = ObjectiveFunction.Value(f1);
var solver = new NelderMeadSimplex(1e-5, maximumIterations: 10000);
var initialGuess = new DenseVector(new[] { 3.0, 6.0, 0.6 });
var result = solver.FindMinimum(obj, initialGuess);
Console.WriteLine(result.MinimizingPoint.ToString());
}

NAudio FFT returns small and equal magnitude values for all frequencies

I'm working on a project with NAudio 1.9 and I want to compute an fft for an entire song, i.e split the song in chunks of equal size and compute fft for each chunk. The problem is that NAudio FFT function returns really small and equal values for any freq in the freq spectrum.
I searched for previous related posts but none seemed to help me.
The code that computes FFT using NAudio:
public IList<FrequencySpectrum> Fft(uint windowSize) {
IList<Complex[]> timeDomainChunks = this.SplitInChunks(this.audioContent, windowSize);
return timeDomainChunks.Select(this.ToFrequencySpectrum).ToList();
}
private IList<Complex[]> SplitInChunks(float[] audioContent, uint chunkSize) {
IList<Complex[]> splittedContent = new List<Complex[]>();
for (uint k = 0; k < audioContent.Length; k += chunkSize) {
long size = k + chunkSize < audioContent.Length ? chunkSize : audioContent.Length - k;
Complex[] chunk = new Complex[size];
for (int i = 0; i < chunk.Length; i++) {
//i've tried windowing here but didn't seem to help me
chunk[i].X = audioContent[k + i];
chunk[i].Y = 0;
}
splittedContent.Add(chunk);
}
return splittedContent;
}
private FrequencySpectrum ToFrequencySpectrum(Complex[] timeDomain) {
int m = (int) Math.Log(timeDomain.Length, 2);
//true = forward fft
FastFourierTransform.FFT(true, m, timeDomain);
return new FrequencySpectrum(timeDomain, 44100);
}
The FrequencySpectrum:
public struct FrequencySpectrum {
private readonly Complex[] frequencyDomain;
private readonly uint samplingFrequency;
public FrequencySpectrum(Complex[] frequencyDomain, uint samplingFrequency) {
if (frequencyDomain.Length == 0) {
throw new ArgumentException("Argument value must be greater than 0", nameof(frequencyDomain));
}
if (samplingFrequency == 0) {
throw new ArgumentException("Argument value must be greater than 0", nameof(samplingFrequency));
}
this.frequencyDomain = frequencyDomain;
this.samplingFrequency = samplingFrequency;
}
//returns magnitude for freq
public float this[uint freq] {
get {
if (freq >= this.samplingFrequency) {
throw new IndexOutOfRangeException();
}
//find corresponding bin
float k = freq / ((float) this.samplingFrequency / this.FftWindowSize);
Complex c = this.frequencyDomain[checked((uint) k)];
return (float) Math.Sqrt(c.X * c.X + c.Y * c.Y);
}
}
}
for a file that contains a sine wave of 440Hz
expected output: values like 0.5 for freq=440 and 0 for the others
actual output: values like 0.000168153987f for any freq in the spectrum
It seems that I made 4 mistakes:
1) Here I'm asumming that sampling freq is 44100. This was not the reason my code wasn't working, though
return new FrequencySpectrum(timeDomain, 44100);
2) Always make a visual representation of your output data! I must learn this lesson... It seems that for a file containing a 440Hz sine wave I'm getting the right result but...
3) The frequency spectrum is a little shifted from what I was expecting because of this:
int m = (int) Math.Log(timeDomain.Length, 2);
FastFourierTransform.FFT(true, m, timeDomain);
timeDomain is an array of size 44100 becaused that's the value of windowSize (I called the method with windowSize = 44100), but FFT method expects a window size with a value power of 2. I'm saying "Here, NAudio, compute me the fft of this array that has 44100 elements, but take into account only the first 32768". I didn't realize that this was going to have serious implications on the result:
float k = freq / ((float) this.samplingFrequency / this.FftWindowSize);
Here this.FftWindowSize is a property based on the size of the array, not on m. So, after visualizing the result I found out that magnitude of 440Hz freq was actually corresponding to the call:
spectrum[371]
instead of
spectrum[440]
So, my mistake was that the window size of fft (m) was not corresponding to the actual length of the array (FrequencySpectrum.FftWindowSize).
4) The small values that I was receiving for the magnitudes came from the fact that the audio file on which I was testing my code wasn't recorded with enough gain.

Increase volume by X decibels and rewrite audio file

I'm new in naudio. And I wanna increase volume by X db. I've written this piece of code:
public static void IncreaseVolume(string inputPath, string outputPath, double db)
{
double linearScalingRatio = Math.Pow(10d, db / 10d);
using (WaveFileReader reader = new WaveFileReader(inputPath))
{
VolumeWaveProvider16 volumeProvider = new VolumeWaveProvider16(reader);
using (WaveFileWriter writer = new WaveFileWriter(outputPath, reader.WaveFormat))
{
while (true)
{
var frame = reader.ReadNextSampleFrame();
if (frame == null)
break;
writer.WriteSample(frame[0] * (float)linearScalingRatio);
}
}
}
}
Ok, this works, but how can I find by how many decibels I've increased each sample? May anyone explain this moment for me and provide any examples?
UPDATE:
using (WaveFileReader reader = new WaveFileReader(inFile))
{
float Sum = 0f;
for (int i = 0; i < reader.SampleCount; i++)
{
var sample = reader.ReadNextSampleFrame();
Sum += sample[0] * sample[0];
}
var db = 20 * Math.Log10(Math.Sqrt(Sum / reader.SampleCount) / 1);
Console.WriteLine(db);
Console.ReadLine();
}
Your code looks good. To measure the average sound level of an audio sample you need to calculate the RMS (root mean square) of this sound level:
RMS := Sqrt( Sum(x_i*x_i)/N)
with x_i being the i-th sample and N the number of samples. The RMS is the average amplitude of your signal. Use
RMS_dB = 20*log(RMS/ref)
(with ref being 1.0 or 32767.0)
to convert it to a decibel value.
You may calculate this RMS value before and after you change the volume. The difference should be erxactly the dB you used in your IncreaseVolume()
Just adding a comment for people
The input db in line is decibel and you need to convert it into amplitude.
double linearScalingRatio = Math.Pow(10d, db / 10d);
The table is as follows-
https://blog.demofox.org/2015/04/14/decibels-db-and-amplitude/
so you need to provide value as 6 in db, to make it twice as load.
Another point already mentioned it should be
double linearScalingRatio = Math.Pow(10d, db / 20d);

Creating a graph with relative distance (C#)

I have the following problem. I create a chart with migradoc in c#.
Suppose I have the following points for my xAxis:
20.4, 20.6, 30.6, 100.4, 200.3
The problem is that it sets every xpoint in the series on an equal distance in the chart.
While what I need is a graph who sets the xpoints on a relative distance. For example, the distance between points 20.6 and 30.6 needs to be way smaller than the distance between 30.6 and 100.4. (The points always differ, as do the number of points)
One way to make the distance good is to add extra points between the existing points. For example the first step is 0.2 extra, the second step is 10.0 extra. So I want to add for example 50 extra points between this step, so that the distance is relative the same.
This is the only thing I can come up with, can somebody give me some advice how to accomplish this? (Or another possible solution?)
This method worked out for me. I first made the distances relative:
Int64[] relAfstand = new Int64[afstand.Count()];
for(int i = 0; i < afstand.Count(); i++){
double tussenRel = Convert.ToDouble(afstand[i]);
double eindRel = Convert.ToDouble(afstand[afstand.Count()-1]);
double beginRel = Convert.ToDouble(afstand[0]);
double Rel = (((eindRel - beginRel) - (eindRel - tussenRel)) / (eindRel - beginRel));
relAfstand[i] = Convert.ToInt64((Rel)*100);
}
Then I converted the data to scale with relative with the same factor as the distances:
List<double> ConvertedData = new List<double>();
int c = 0;
int c2 = 1;
double steps = 0;
bool calcSteps = false;
bool calcDistance = false;
for (int i = 0; i < 100; i++) {
if (calcDistance == false) {
distance.Add(i);
}
if (relAfstand[c] == i) {
ConvertedData.Add(data[c]);
calcSteps = false;
c2 = 1;
c++;
}else {
if (calcSteps == false) {
steps = ((data[c] - data[c-1])/(relAfstand[c] - relAfstand[c-1]));
calcSteps = true;
}
ConvertedData.Add(data[c-1] + (steps * c2));
c2++;
}
}
calcDistance = true;
Probably not the best workaround, but it works. Since the percentages can come close together I scale both now with around 200-300 instead of 100.

XNA performance

I'm writing some sort of Geometry Wars inspired game except with added 2d rigid body physics Ai pathfinding some waypoint analysis line of sight checks load balancing etc. It seems that even though with around 80-100 enemies on screen it can work reasonably fast with all that stuff enabled the performance completely breaks down once you get to a total of 250 (150 enemies) objects or so. I've searched for any O(n^2) parts in the code but there don't seem to be any left. I'm also using spatial grids.
Even if I disable pretty much everything from the supposedly expensive Ai related processing it doesn't seem to matter, it like still breaks down at 150 enemies.
Now I implemened all the code from scratch, currently even the matrix multiplication code, and I'm almost completely relying on the GC as well as using C# closures for some things, so I expect this to be seriously far from being optimized, but still it doesn't make sense to me that with like 1/15 of the processing work but double the objects the game suddenly starts to slow down to crawl? Is this normal, how is the XNA platform normally supposed to scale as far as the amount of objects being processed is concerned?
I remember Some slerp spinning cube thing I did at first could handle more than 1000 at once so I think I'm doing something wrong?
edit:
Here's the grid structure's class
public abstract class GridBase{
public const int WORLDHEIGHT = (int)AIGridInfo.height;
public const int WORLDWIDTH = (int)AIGridInfo.width;
protected float cellwidth;
protected float cellheight;
int no_of_col_types;
// a dictionary of lists that gets cleared every frame
// 3 (=no_of_col_types) groups of objects (enemy side, players side, neutral)
// 4000 initial Dictionary hash positions for each group
// I have also tried using an array of lists of 100*100 cells
//with pretty much identical results
protected Dictionary<CoordsInt, List<Collidable>>[] grid;
public GridBase(float cellwidth, float cellheight, int no_of_col_types)
{
this.no_of_col_types = no_of_col_types;
this.cellheight=cellheight;
this.cellwidth=cellwidth;
grid = new Dictionary<CoordsInt, List<Collidable>>[no_of_col_types];
for (int u = 0; u < no_of_col_types; u++)
grid[u] = new Dictionary<CoordsInt, List<Collidable>>(4000);
}
public abstract void InsertCollidable(Collidable c);
public abstract void InsertCollidable(Grid_AI_Placeable aic);
//gets called in the update loop
public void Clear()
{
for (int u = 0; u < no_of_col_types; u++)
grid[u].Clear();
}
//gets the grid cell of the left down corner
protected void BaseCell(Vector3 v, out int gx, out int gy)
{
gx = (int)((v.X + (WORLDWIDTH / 2)) / cellwidth);
gy = (int)((v.Y + (WORLDHEIGHT / 2)) / cellheight);
}
//gets all cells covered by the AABB
protected void Extent(Vector3 pos, float aabb_width, float aabb_height, out int totalx, out int totaly)
{
var xpos = pos.X + (WORLDWIDTH / 2);
var ypos = pos.Y + (WORLDHEIGHT / 2);
totalx = -(int)((xpos / cellwidth)) + (int)((xpos + aabb_width) / cellwidth) + 1;
totaly = -(int)((ypos / cellheight)) + (int)((ypos + aabb_height) / cellheight) + 1;
}
}
public class GridBaseImpl1 : GridBase{
public GridBaseImpl1(float widthx, float widthy)
: base(widthx, widthy, 3)
{
}
//adds a collidable to the grid /
//caches for intersection test
//checks if it should be tested to prevent penetration /
//tests penetration
//updates close, intersecting, touching lists
//Collidable is an interface for all objects that can be tested geometrically
//the dictionary is indexed by some simple struct that wraps the row and column number in the grid
public override void InsertCollidable(Collidable c)
{
//some tag so that objects don't get checked more than once
Grid_Query_Counter.current++;
//the AABB is allocated in the heap
var aabb = c.CollisionAABB;
if (aabb == null) return;
int gx, gy, totalxcells, totalycells;
BaseCell(aabb.Position, out gx, out gy);
Extent(aabb.Position, aabb.widthx, aabb.widthy, out totalxcells, out totalycells);
//gets which groups to test this object with in an IEnumerable (from a statically created array)
var groupstestedagainst = CollidableCalls.GetListPrevent(c.CollisionType).Select(u => CollidableCalls.group[u]);
var groups_tested_against = groupstestedagainst.Distinct();
var own_group = CollidableCalls.group[c.CollisionType];
foreach (var list in groups_tested_against)
for (int i = -1; i < totalxcells + 1; i++)
for (int j = -1; j < totalycells + 1; j++)
{
var index = new CoordsInt((short)(gx + i), (short)(gy + j));
if (grid[list].ContainsKey(index))
foreach (var other in grid[list][index])
{
if (Grid_Query_Counter.Check(other.Tag))
{
//marks the pair as close, I've tried only keeping the 20 closest but it's still slow
other.Close.Add(c);
c.Close.Add(other);
//caches the pair it so that checking if the pair intersects doesn't go through the grid //structure loop again
c.CachedIntersections.Add(other);
var collision_function_table_id = c.CollisionType * CollidableCalls.size + other.CollisionType;
//gets the function to use on the pair for testing penetration
//the function is in a delegate array statically created to simulate multiple dispatch
//the function decides what coarse test to use until descending to some complete //geometric query
var prevent_delegate = CollidableCalls.preventfunctions[collision_function_table_id];
if (prevent_delegate == null) { Grid_Query_Counter.Put(other.Tag); continue; }
var a = CollidableCalls.preventfunctions[collision_function_table_id](c, other);
//if the query returns true mark as touching
if (a) { c.Contacted.Add(other); other.Contacted.Add(c); }
//marks it as tested in this query
Grid_Query_Counter.Put(other.Tag);
}
}
}
//adds it to the grid if the key doesn't exist it creates the list first
for (int i = -1; i < totalxcells + 1; i++)
for (int j = -1; j < totalycells + 1; j++)
{
var index = new CoordsInt((short)(gx + i), (short)(gy + j));
if (!grid[own_group].ContainsKey(index)) grid[own_group][index] = new List<Collidable>();
grid[own_group][index].Add(c);
}
}
[...]
}
First. Profile your code. Even if you just use manually inserted time stamps to surround blocks you're interested in. I prefer to use the profiler that comes built into Visual Studio Pro.
However, based in your description, I would assume your problems are due to too many draw calls. Once you exceed 200-400 draw calls per frame your performance can drop dramatically. Try batching your rendering and see if this improves performance.
You can use a profiler such as ANTS Profiler to see what may be the problem.
Without any code theres not much I can do.

Categories

Resources