swharden/FftSharp

Getting aggregated data for displaying charts

Closed this issue · 4 comments

Hi,

we would like to use this library to render your charts on the web. Is there any easy way to downsample/aggregate the data like you do in your charts? Something like .AggregateChart() which returns x: and y: which can be passed to different chart libraries or other tools

Thanks for your help!

Hi @xkuyax,

I don't think I fully understand your question. This library is designed to accept data (e.g., double[] xs and double[] ys) and produce a Bitmap you can display (in a GUI) or save to disk (perhaps as a jpeg). I have used this library in Azure Functions to generate images to display on the web (here).

If you would rather use another charting library to display xs and ys on the web, you can pass that data into the other library and do not need to use ScottPlot.

If your question relates to client-side interactive charting with JavaScript, I recommend looking into Google Charts https://developers.google.com/chart/interactive/docs/gallery

Let me know if this helps, or if I am misunderstanding your question! Thanks
Scott

Hi @swharden , thanks for your very fast reply!
I have been looking at your example program, which generates the fftPower, freqs and times arrays, and feeds this into the ScottPlot.Plot()
I generated this myself for an wav File i got (30s, 44k SampleRate) which resulted in 1,4million doubles. Id rather not transmit that over the web, but instead calculate xs and ys (i guess thats the "downsampled" data?) and send this to my chart lib (and make an new call with different calculation parameters on scrolling to update the chart)

Basically what i want are 2 arrays:
X: (2.5 Hz, 5 Hz, 7.5 Hz,...)
Y: (-1, 2, 0, 1,) the fft values for the specified frequency in x (but averaged, like it is being done in your plot library)

Thanks!

Hey @xkuyax,

First off let me apologize - I got mixed up and thought this question was posted as a ScottPlot issue and now I see it is a FftSharp issue. This is why I was confused, but your queston makes more sense to me now that I realize my mistake. If you analyze 30s of FFT data it will be very slow and produce a very large amount of data (you noted 1.4 million points). These types of high resolution FFTs are rarely required, and as you have found are difficult to display.

You indeed can indeed downsample the data (taking every Nth point and dividing sample rate by N) prior to calling the FFT methods to achieve fast calculations and a result with a small number of points.

Alternatively, you can also divide your signal into many 1s chunks, calculate all the individual FFTs, and average them together. This process is typically accompanied by a windowing function so each chunk starts and ends at 0.

You may find my Spectrogram library helpful, as its purpose is to simplify the process of creating many small FFTs from a long recording. https://github.com/swharden/Spectrogram

Let me know if this helps solve your problem!

Also, it may help to review the quickstart source code which produces this output

image

using System;
using System.Drawing.Printing;
namespace FftSharp.Quickstart
{
class Program
{
static void Main(string[] args)
{
SimpleFftWithGraphs(useWindow: false);
SimpleFftWithGraphs(useWindow: true);
}
static void SimpleFftWithGraphs(bool useWindow = false)
{
// load sample audio with noise and sine waves at 500, 1200, and 1500 Hz
double[] audio = FftSharp.SampleData.SampleAudio1();
int sampleRate = 48_000;
// optionally apply a window to the data before calculating the FFT
if (useWindow)
{
double[] window = FftSharp.Window.Hanning(audio.Length);
FftSharp.Window.ApplyInPlace(window, audio);
}
// You could get the FFT as a complex result
Complex[] fft = FftSharp.Transform.FFT(audio);
// For audio we typically want the FFT amplitude (in dB)
double[] fftPower = FftSharp.Transform.FFTpower(audio);
// Create an array of frequencies for each point of the FFT
double[] freqs = FftSharp.Transform.FFTfreq(sampleRate, fftPower.Length);
// create an array of audio sample times to aid plotting
double[] times = ScottPlot.DataGen.Consecutive(audio.Length, 1000d / sampleRate);
// plot the sample audio
var plt1 = new ScottPlot.Plot(400, 300);
plt1.PlotScatter(times, audio, markerSize: 3);
//plt1.Title("Audio Signal");
plt1.YLabel("Amplitude");
plt1.XLabel("Time (ms)");
plt1.AxisAuto(0);
// plot the FFT amplitude
var plt2 = new ScottPlot.Plot(400, 300);
plt2.PlotScatter(freqs, fftPower, markerSize: 3);
//plt2.Title("Fast Fourier Transformation (FFT)");
plt2.YLabel("Power (dB)");
plt2.XLabel("Frequency (Hz)");
plt2.AxisAuto(0);
// save output
if (useWindow)
{
plt1.SaveFig("../../../output/audio-windowed.png");
plt2.SaveFig("../../../output/fft-windowed.png");
}
else
{
plt1.SaveFig("../../../output/audio.png");
plt2.SaveFig("../../../output/fft.png");
}
}
}
}

You can see that double[] freqs and double[] fftPower and are the Xs and Ys you are probably trying to plot. Since they are simple arrays, you can plot them with any charting library. In the example I use ScottPlot, but alternatively you could send them to the browser to display interactively or something like that.

Hope it helps!
Scott