Skip to content

Commit d956ee6

Browse files
committed
working FFT
1 parent c235fa1 commit d956ee6

File tree

10 files changed

+371
-0
lines changed

10 files changed

+371
-0
lines changed

src/ConsoleDemo/App.config

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<configuration>
3+
<startup>
4+
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
5+
</startup>
6+
</configuration>

src/ConsoleDemo/ConsoleDemo.csproj

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
4+
<PropertyGroup>
5+
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
6+
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
7+
<ProjectGuid>{DA5009A8-9036-4BDA-B591-3244DEB759E9}</ProjectGuid>
8+
<OutputType>WinExe</OutputType>
9+
<RootNamespace>ConsoleDemo</RootNamespace>
10+
<AssemblyName>ConsoleDemo</AssemblyName>
11+
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
12+
<FileAlignment>512</FileAlignment>
13+
<Deterministic>true</Deterministic>
14+
</PropertyGroup>
15+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
16+
<PlatformTarget>AnyCPU</PlatformTarget>
17+
<DebugSymbols>true</DebugSymbols>
18+
<DebugType>full</DebugType>
19+
<Optimize>false</Optimize>
20+
<OutputPath>bin\Debug\</OutputPath>
21+
<DefineConstants>DEBUG;TRACE</DefineConstants>
22+
<ErrorReport>prompt</ErrorReport>
23+
<WarningLevel>4</WarningLevel>
24+
</PropertyGroup>
25+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
26+
<PlatformTarget>AnyCPU</PlatformTarget>
27+
<DebugType>pdbonly</DebugType>
28+
<Optimize>true</Optimize>
29+
<OutputPath>bin\Release\</OutputPath>
30+
<DefineConstants>TRACE</DefineConstants>
31+
<ErrorReport>prompt</ErrorReport>
32+
<WarningLevel>4</WarningLevel>
33+
</PropertyGroup>
34+
<PropertyGroup>
35+
<StartupObject />
36+
</PropertyGroup>
37+
<ItemGroup>
38+
<Reference Include="System" />
39+
<Reference Include="System.Core" />
40+
<Reference Include="System.Xml.Linq" />
41+
<Reference Include="System.Data.DataSetExtensions" />
42+
<Reference Include="Microsoft.CSharp" />
43+
<Reference Include="System.Data" />
44+
<Reference Include="System.Net.Http" />
45+
<Reference Include="System.Xml" />
46+
</ItemGroup>
47+
<ItemGroup>
48+
<Compile Include="Program.cs" />
49+
<Compile Include="Properties\AssemblyInfo.cs" />
50+
</ItemGroup>
51+
<ItemGroup>
52+
<None Include="App.config" />
53+
</ItemGroup>
54+
<ItemGroup>
55+
<ProjectReference Include="..\Spectrogram\Spectrogram.csproj">
56+
<Project>{f4814553-c114-4df7-b0f7-6512796247c7}</Project>
57+
<Name>Spectrogram</Name>
58+
</ProjectReference>
59+
</ItemGroup>
60+
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
61+
</Project>

src/ConsoleDemo/Program.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace ConsoleDemo
8+
{
9+
class Program
10+
{
11+
static void Main(string[] args)
12+
{
13+
double[] values = Spectrogram.Tools.generateFakeSignal();
14+
double[] fft = Spectrogram.Tools.FFT(values);
15+
16+
Spectrogram.Tools.plotValues(values);
17+
Spectrogram.Tools.plotFFT(fft);
18+
19+
Console.WriteLine("DONE");
20+
}
21+
}
22+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System.Reflection;
2+
using System.Runtime.CompilerServices;
3+
using System.Runtime.InteropServices;
4+
5+
// General Information about an assembly is controlled through the following
6+
// set of attributes. Change these attribute values to modify the information
7+
// associated with an assembly.
8+
[assembly: AssemblyTitle("ConsoleDemo")]
9+
[assembly: AssemblyDescription("")]
10+
[assembly: AssemblyConfiguration("")]
11+
[assembly: AssemblyCompany("")]
12+
[assembly: AssemblyProduct("ConsoleDemo")]
13+
[assembly: AssemblyCopyright("Copyright © 2019")]
14+
[assembly: AssemblyTrademark("")]
15+
[assembly: AssemblyCulture("")]
16+
17+
// Setting ComVisible to false makes the types in this assembly not visible
18+
// to COM components. If you need to access a type in this assembly from
19+
// COM, set the ComVisible attribute to true on that type.
20+
[assembly: ComVisible(false)]
21+
22+
// The following GUID is for the ID of the typelib if this project is exposed to COM
23+
[assembly: Guid("da5009a8-9036-4bda-b591-3244deb759e9")]
24+
25+
// Version information for an assembly consists of the following four values:
26+
//
27+
// Major Version
28+
// Minor Version
29+
// Build Number
30+
// Revision
31+
//
32+
// You can specify all the values or you can default the Build and Revision Numbers
33+
// by using the '*' as shown below:
34+
// [assembly: AssemblyVersion("1.0.*")]
35+
[assembly: AssemblyVersion("1.0.0.0")]
36+
[assembly: AssemblyFileVersion("1.0.0.0")]
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System.Reflection;
2+
using System.Runtime.CompilerServices;
3+
using System.Runtime.InteropServices;
4+
5+
// General Information about an assembly is controlled through the following
6+
// set of attributes. Change these attribute values to modify the information
7+
// associated with an assembly.
8+
[assembly: AssemblyTitle("Spectrogram")]
9+
[assembly: AssemblyDescription("")]
10+
[assembly: AssemblyConfiguration("")]
11+
[assembly: AssemblyCompany("")]
12+
[assembly: AssemblyProduct("Spectrogram")]
13+
[assembly: AssemblyCopyright("Copyright © 2019")]
14+
[assembly: AssemblyTrademark("")]
15+
[assembly: AssemblyCulture("")]
16+
17+
// Setting ComVisible to false makes the types in this assembly not visible
18+
// to COM components. If you need to access a type in this assembly from
19+
// COM, set the ComVisible attribute to true on that type.
20+
[assembly: ComVisible(false)]
21+
22+
// The following GUID is for the ID of the typelib if this project is exposed to COM
23+
[assembly: Guid("f4814553-c114-4df7-b0f7-6512796247c7")]
24+
25+
// Version information for an assembly consists of the following four values:
26+
//
27+
// Major Version
28+
// Minor Version
29+
// Build Number
30+
// Revision
31+
//
32+
// You can specify all the values or you can default the Build and Revision Numbers
33+
// by using the '*' as shown below:
34+
// [assembly: AssemblyVersion("1.0.*")]
35+
[assembly: AssemblyVersion("1.0.0.0")]
36+
[assembly: AssemblyFileVersion("1.0.0.0")]

src/Spectrogram/Spectrogram.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace Spectrogram
8+
{
9+
public class Spectrogram
10+
{
11+
}
12+
}

src/Spectrogram/Spectrogram.csproj

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
4+
<PropertyGroup>
5+
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
6+
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
7+
<ProjectGuid>{F4814553-C114-4DF7-B0F7-6512796247C7}</ProjectGuid>
8+
<OutputType>Library</OutputType>
9+
<AppDesignerFolder>Properties</AppDesignerFolder>
10+
<RootNamespace>Spectrogram</RootNamespace>
11+
<AssemblyName>Spectrogram</AssemblyName>
12+
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
13+
<FileAlignment>512</FileAlignment>
14+
<Deterministic>true</Deterministic>
15+
</PropertyGroup>
16+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
17+
<DebugSymbols>true</DebugSymbols>
18+
<DebugType>full</DebugType>
19+
<Optimize>false</Optimize>
20+
<OutputPath>bin\Debug\</OutputPath>
21+
<DefineConstants>DEBUG;TRACE</DefineConstants>
22+
<ErrorReport>prompt</ErrorReport>
23+
<WarningLevel>4</WarningLevel>
24+
</PropertyGroup>
25+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
26+
<DebugType>pdbonly</DebugType>
27+
<Optimize>true</Optimize>
28+
<OutputPath>bin\Release\</OutputPath>
29+
<DefineConstants>TRACE</DefineConstants>
30+
<ErrorReport>prompt</ErrorReport>
31+
<WarningLevel>4</WarningLevel>
32+
</PropertyGroup>
33+
<ItemGroup>
34+
<Reference Include="NAudio, Version=1.9.0.0, Culture=neutral, processorArchitecture=MSIL">
35+
<HintPath>..\packages\NAudio.1.9.0\lib\net35\NAudio.dll</HintPath>
36+
</Reference>
37+
<Reference Include="ScottPlot, Version=3.0.8.0, Culture=neutral, processorArchitecture=MSIL">
38+
<HintPath>..\packages\ScottPlot.3.0.9\lib\net45\ScottPlot.dll</HintPath>
39+
</Reference>
40+
<Reference Include="System" />
41+
<Reference Include="System.Core" />
42+
<Reference Include="System.Drawing" />
43+
<Reference Include="System.Windows.Forms" />
44+
<Reference Include="System.Xml.Linq" />
45+
<Reference Include="System.Data.DataSetExtensions" />
46+
<Reference Include="Microsoft.CSharp" />
47+
<Reference Include="System.Data" />
48+
<Reference Include="System.Net.Http" />
49+
<Reference Include="System.Xml" />
50+
</ItemGroup>
51+
<ItemGroup>
52+
<Compile Include="Spectrogram.cs" />
53+
<Compile Include="Properties\AssemblyInfo.cs" />
54+
<Compile Include="Tools.cs" />
55+
</ItemGroup>
56+
<ItemGroup>
57+
<None Include="packages.config" />
58+
</ItemGroup>
59+
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
60+
</Project>

src/Spectrogram/Tools.cs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace Spectrogram
8+
{
9+
public static class Tools
10+
{
11+
public static double[] FFT(double[] values, bool useHammingWindow = true)
12+
{
13+
int fftSize = 0;
14+
for (int i = 4; i < 20; i++)
15+
{
16+
int potentialFftSize = (int)Math.Pow(2, i);
17+
if (potentialFftSize <= values.Length)
18+
fftSize = potentialFftSize;
19+
else
20+
break;
21+
}
22+
23+
Console.WriteLine($"Processing FFT (size: {fftSize}) of values (size: {values.Length})");
24+
25+
NAudio.Dsp.Complex[] fft_buffer = new NAudio.Dsp.Complex[fftSize];
26+
for (int i = 0; i < fftSize; i++)
27+
{
28+
fft_buffer[i].X = (float)values[i];
29+
fft_buffer[i].Y = 0;
30+
31+
if (useHammingWindow)
32+
fft_buffer[i].X *= (float)NAudio.Dsp.FastFourierTransform.HammingWindow(i, fftSize);
33+
}
34+
35+
// perform the FFT
36+
NAudio.Dsp.FastFourierTransform.FFT(true, (int)Math.Log(fftSize, 2.0), fft_buffer);
37+
38+
// a list with FFT values
39+
double[] fft = new double[fftSize / 2];
40+
41+
for (int i = 0; i < fft.Length; i++)
42+
{
43+
// should this be sqrt(X^2+Y^2)? log10?
44+
45+
var fftPointLeft = fft_buffer[i];
46+
var fftPointRight = fft_buffer[fft_buffer.Length - i - 1];
47+
48+
fft[i] = 0;
49+
fft[i] += (double)fftPointLeft.X + (double)fftPointLeft.Y;
50+
fft[i] += (double)fftPointRight.X + (double)fftPointRight.Y;
51+
fft[i] /= 2;
52+
53+
fft[i] = Math.Abs(fft[i]);
54+
}
55+
56+
return fft;
57+
}
58+
59+
public static void plotValues(double[] values, string saveFilePath = "values.png", int sampleRateHz = 8000)
60+
{
61+
var plt = new ScottPlot.Plot();
62+
plt.PlotSignal(values, sampleRateHz, markerSize: 0, lineWidth: 2);
63+
plt.Title("Signal");
64+
plt.YLabel("Value");
65+
plt.XLabel("Time (sec)");
66+
plt.AxisAuto(0);
67+
plt.SaveFig(saveFilePath);
68+
Console.WriteLine($"Saved: {System.IO.Path.GetFullPath(saveFilePath)}");
69+
}
70+
71+
public static void plotFFT(double[] fft, string saveFilePath = "fft.png", int sampleRateHz = 8000)
72+
{
73+
var plt = new ScottPlot.Plot();
74+
double fftSampleRate = (double)fft.Length / sampleRateHz * 2;
75+
plt.PlotSignal(fft, fftSampleRate, markerSize: 0, lineWidth: 2);
76+
plt.Title("FFT");
77+
plt.YLabel("Power");
78+
plt.XLabel("Frequency (Hz)");
79+
plt.AxisAuto(0);
80+
plt.SaveFig(saveFilePath);
81+
Console.WriteLine($"Saved: {System.IO.Path.GetFullPath(saveFilePath)}");
82+
}
83+
84+
public static double[] generateFakeSignal(double durationSeconds = 1, int sampleRateHz = 8000, double signalFrequencyHz = 2000)
85+
{
86+
int pointCount = (int)(durationSeconds * sampleRateHz);
87+
double[] values = new double[pointCount];
88+
89+
// create a sine wave
90+
double oscillations = signalFrequencyHz * durationSeconds;
91+
for (int i = 0; i < values.Length; i++)
92+
values[i] = Math.Sin(((double)i / values.Length) * 2 * Math.PI * oscillations);
93+
94+
// add noise
95+
Random rand = new Random();
96+
for (int i = 0; i < values.Length; i++)
97+
values[i] += (rand.NextDouble() - .5) * .1;
98+
99+
return values;
100+
}
101+
}
102+
}

src/Spectrogram/packages.config

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<packages>
3+
<package id="NAudio" version="1.9.0" targetFramework="net45" />
4+
<package id="ScottPlot" version="3.0.9" targetFramework="net45" />
5+
</packages>

src/SpectrographStuff.sln

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 16
4+
VisualStudioVersion = 16.0.29209.62
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleDemo", "ConsoleDemo\ConsoleDemo.csproj", "{DA5009A8-9036-4BDA-B591-3244DEB759E9}"
7+
EndProject
8+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Spectrogram", "Spectrogram\Spectrogram.csproj", "{F4814553-C114-4DF7-B0F7-6512796247C7}"
9+
EndProject
10+
Global
11+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
12+
Debug|Any CPU = Debug|Any CPU
13+
Release|Any CPU = Release|Any CPU
14+
EndGlobalSection
15+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
16+
{DA5009A8-9036-4BDA-B591-3244DEB759E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17+
{DA5009A8-9036-4BDA-B591-3244DEB759E9}.Debug|Any CPU.Build.0 = Debug|Any CPU
18+
{DA5009A8-9036-4BDA-B591-3244DEB759E9}.Release|Any CPU.ActiveCfg = Release|Any CPU
19+
{DA5009A8-9036-4BDA-B591-3244DEB759E9}.Release|Any CPU.Build.0 = Release|Any CPU
20+
{F4814553-C114-4DF7-B0F7-6512796247C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21+
{F4814553-C114-4DF7-B0F7-6512796247C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
22+
{F4814553-C114-4DF7-B0F7-6512796247C7}.Release|Any CPU.ActiveCfg = Release|Any CPU
23+
{F4814553-C114-4DF7-B0F7-6512796247C7}.Release|Any CPU.Build.0 = Release|Any CPU
24+
EndGlobalSection
25+
GlobalSection(SolutionProperties) = preSolution
26+
HideSolutionNode = FALSE
27+
EndGlobalSection
28+
GlobalSection(ExtensibilityGlobals) = postSolution
29+
SolutionGuid = {7D18DDFF-2D40-4E8A-9EA7-3F7B658062D3}
30+
EndGlobalSection
31+
EndGlobal

0 commit comments

Comments
 (0)