Plot2, a scientific 2D plotting program for OS X.
Plot2, a scientific 2D plotting program for OS X. Available Features: ASCII, Binary, MySQL and Perl based import filter PDF, EPS, JPG, PNG, ASCII export. Plot-Pro, Harare, Zimbabwe. CAD plotting Photographic printing Graphic designing Advertising Gold foiling Embossing General printing Engraving Heat-press printing. S9cWP.vers.2.6.11.Plot2.Pro.pkg download for 10.11.6.
Available Features:
ASCII, Binary, MySQL and Perl based import filterPlot2 Pro Mac
PDF, EPS, JPG, PNG, ASCII exportmacro programming language with ~220 built in commands
Perl based scripting
subviews, automatic legend plotting, inline images
X and Y error bars (absolute, relative and from data)
expression parsing with with ~60 built in functions
spreadsheet like data editor
lines, symbols, grids, bars, filled areas, sticks, dots, histograms, error bars
fft smooth, least square smooth, spline interpolation
differentiation, integration and FFT, background subtraction
least square regression (linear, logarithmic, exponential)
normalizing, data moving, data calculations, function generator
four independent x and y axis (linear, logarithmic, time)
flexible automatic axis labeling and free defined axis labels
easy navigation, zoom and scale etc.
text and graphics objects, copy&paste, drag&drop
There is also a syntax mode for Coda2 available: Plot2-Daviz.mode.zip
Download from AppStore:
Bo Joel Svenssonblog (dot) joel (dot) svensson (at) gmail (dot) com
This program is based upon the earlier Audio input using Qt and QAudioInput text and adds a second QCustomPlot that will be displaying the discrete Fourier transform (DFT) of the audio in a 2 second sliding window.
To compute the DFT, the FFTW3 library will be used. To install FFTW3 on Ubuntu all you need to do is sudo apt-get install libfftw3-dev
. If you are on Windows, you should be able to just go download some package of files from www.fftw.org.
The final result will be a GUI like the one in the picture below.
How to construct the GUI is as usual left out. I don't really see how that could be efficiently done in text. I am also not very good at making GUIs.
Now, the program developed in this text is a small experiment for fun and we wont really be doing anything with the data in the second plot (the DFT output). If you don't know much about the Fourier Transform (like me) take a look this video from Three Blue one Brown that does a good job of explaining what is going. But in short, if you don't want to watch a video the output will show (with a spike in the plot) the presence of a frequency within in the audio. So if you were to play a tone, say at 440Hz there should appear a spike at 440 along the x-axis in the graph. So it does give you some interesting insights into the audio waveform.
Adding FFTW to the Qt Project
If the FFTW3 libraries are installed then all that is needed should be to add the following line to your Qt project .pro
file.
You can also right click on your project in the Projects explorer within Qt Creator and select option Add Library...
that starts up a kind of library adding wizard.
The Code
Since the code is mostly identical to the previous post, we will only look at the new additions in any detail.
To get started, let's jump into mainwindow.h
and take a look at the new bit of private state added to the MainWindow class.
First there is a QVector called mFFtIndices
this will be frequencies and is used in the drawing of the FFT plot. More about this when it is filled with values in the MainWindow constructor.
Next up is an fftw_plan
. FFTW is very clever software that will try and find optimal code for the particular system it is running for solving the task we ask of it. The mFftPlan
object will initialized in the MainWindow constructor.
Lastly there are two pointers, mFftIn
and mFftOut
. Arrays will be allocated for input and output data that we use together with the FFTW_plan
. These will also be initialized in the MainWindow constructor.
Oh, and then we need to also include the fftw3 header!
But with that done, we are finished in the mainwindow.h
file. mainwindow.h
is shown in its entirety below.
Now we can turn to the mainwindow.cpp
file and take a look at what is new there. To start with, I added a few defines in order to name some constants used in the program.
First I have defined the audible range of frequencies. That range will be used to narrow down which results in the DFT output data that we are interested in. Then NUM_SAMPLES
is the number of samples that we store in our 2 second sliding window. SAMPLE_FREQ
is of course the frequency we sample our input at. At a sampling frequency of 48KHz, the frequencies should be uniquely identifiable using DFT but signals above half of 48KHz could produce the same DFT output, given the Nyqvist sampling theorem. My understanding of these concepts is quite limited! But we can all keep learning as long as we are alive.
What we will look at in the rest of this text is:
- Setting up a second plot for DFT output and setting plotting parameters.
- Creating the QVector of indices used in the new plot.
- Allocating input and output arrays for FFTW.
- Setting up an FFTW plan.
- Executing an FFTW plan.
- Plotting of the result.
- Shut down of FFTW.
The first four of these activities take place in the constructor for the MainWindow object.
The newly added QCustomPlot us called plot2
and is here set up to not have any visible legend, the x-axis will range over the audible range of frequencies and the y-axis will range over 0 - 500. Now, these ranges are scalable and drag-able with the mouse when the program is running, so you can zoom in on a subrange of frequencies and look at the behavior of the sound at that point in more detail.
Next it is time to set up the indices for the plot that will be displayed as the x-axis labels. Here, an indices are created starting with the lowest audible frequency and then we keep adding freqStep
to this until we reach the end of the audible range. The reason for this is that the output array produced by FFTW will not show a response for frequency f at index f, that response will rather be seen at index = (NUM_SAMPLES/SAMPLE_FREQ) * f. This means, in our case, that the output array will at index X have the response for frequency (1/2)X. So the function below creates a list of indices to display in the GUI that makes it so that the response for frequency X appears over the number X in the graph. Bah! I think this is quite on the edge of what I manage to explain. If you know of a good clear explanation, please share it with me and I'll edit for its inclusion.
This creates more indices than we will probably ever use though, we will trim that later.
Ok now we got to the setup of the FFTW related things.
FFTW functions are used to the allocation of the arrays used for input and output to the plan. Then the plan is set up.
For more information about FFTW plans check out these links:
But as I understand this, we are now setting up for a 'real to real' type of transform and there is some different kinds of those. The kind chosen here is FFTW_R2HC
which should be a DFT according to the documentation linked above. Now when we have created a plan, FFTW has set up a function for performing the DFT according to our specifications. The mFftPlan
member is our way to access that functionality.
Later in the code we will execute the plan and when doing so the data in the input array will be processed and the result stored in the output. The output will contain half as many elements as the input array, but those will be complex numbers and thus use up all the NUM_SAMPLES
indices of the output array. Real components will be stored sequentially in the first half of the array and imaginary components in the second half.
The next set of additions to the program go into the samplesUpdated
function. This is where the plan is executed and the plot updated.
The samples in the 2 seconds window is copied into the mFftIn
array and the plan is executed.
When doing so, NUM_SAMPLES
values are created into the mFftOut
array. The first half of these contain the real component of the DFT, so that is NUM_SAMPLES/2 values or in our case 48000 values. But given that the value at index i corresponds to the frequency 2*i (in this particular case), really the highest frequency represented in there is 24KHz.
Next, we copy data from the mFftOut
array to a QVector to be able to pass it on to QCustomPlot for display.
Here, the starting and end point of the audible range is multiplied with, in this case, 2. this is again because the response for frequency i will be at index 2i. Notice that for the values added to the QVector for plotting we are only interested in the magnitude of the response, not if it is positive or negative. This is why there is an application of abs
to the values of mFftOut
. I was, at first, a bit surprised to see nagive values in the result but a look at the Three Blue one Brown video cleared that up.
Plot2 Program
Then QCustomPlot takes over and makes the plot appear.
Plot2 Pro Make A Plot
Here we just match up the lengths of the mFftIndices
and the fftVec
vectors and call setData
. No rescaling is automatically performed so it wont interfere with any manual zooming or paning that you may do with the mouse.
Only one more addition left and it is in the MainWindow destructor.
The input and output arrays are freed and the plan is destroyed.
Below is the complete mainwindow.cpp
file.
Thanks for reading. This was an experiment with calling FFTW from Qt and to plot the result of an DFT alongside the waveform used to compute it. I hope it is useful for someone. If you have questions, feedback, hints or tips, please contact me (information below).
Have a good day!
Please contact me with questions, suggestions or feedback at blog (dot) joel (dot) svensson (at) gmail (dot) com or join the google group .
© Copyright 2020 Bo Joel Svensson
This page was generated using Pandoc.