|
I am looking for imformation that someone without a PHD in math can use to implement a spectrum analyzer in C++. I am trying to use the Fast Fourier Transform to create a spectrum analyzer. I cannot seem to find any info that I can understand.
What I know is that there are many FFT implementations out there but do you apply it to my problem?
I want to use a samplng rate of 44100 Hz and or 48000 Hz.
I believe I should use a 1024 samples
I believe I want a spacing of 100 Hz
I just need some direction.
Thanks,
Steve
|
|
|
|
|
OK, here's the basic facts. There's a well known signal theory theorem stating that the most signifcant frequency computed by an FFT is half the sampling rate (google for Nyquist frequency for further info). Assuming that you're sampling at 48 kHz, that means that the maximum frequency obtained after FFT is 24 kHz. We denote this maximum frequency as fs. Now, suppose you compute the transform in 1024-sample chunks. Then the output of the FFT routine is a 1024-point chunk of frequency components in the range [-fs, fs). The spacing between frequency points is thus 2fs/1024 = 46.875 Hz. Considering that you want 100 Hz precision, you'd only actually need 512-sample chunks (giving 93.75 Hz resolution).
Additional issues to keep in mind:
Joaquín M López Muñoz
Telefónica, Investigación y Desarrollo
|
|
|
|
|
Beware
in many cases the fft return complex numbers.
|
|
|
|
|
you basically need to take the magnitude of the fft,,
try matlab, its very easy
you just need a series of number, and then type
y=fft(funcation, );
and then,, take the absolute value of it
x= abs(y);
take an introductory signal analysis book,, its very easy
done
Ehsan Behboudi
|
|
|
|
|
Joaquin,
Thanks for your timely response. I believe that I am following your explanation.
I do have several questions though.
1) With the sample rates you used in your example are you implying that the sample rate
should be base 2.
I believe that the typical range of human hearing is 20k to 20,000kHz.
2) So, if I want to display lets say 64 bars(samples??) to represent the sound starting from
20hz to 20,000kHz how does this work? Do I just select the frequencies that I want from the
fft calculation?
Thanks,
Steve Messer
|
|
|
|
|
1) With the sample rates you used in your example are you implying that the sample rate should be base 2.
No. In the example the sampling rate f2 is 48,000, which certainly is not a power of 2. What should be a a power of two is the size of the chunks passed to the FFT routine --some FFT libraries do not impose this restriction, but even so there're efficiency advantages in doing it that way.
2) So, if I want to display lets say 64 bars(samples??) to represent the sound starting from 20hz to 20,000kHz how does this work? Do I just select the frequencies that I want from the fft calculation?
Not exactly, you've got to do some postprocessing in order to get something with physical meaning. Let's do the planning:
1. As your maximum frequency is 20 kHz then fs must be at least 40 kHz. It is a good idea to have it a little higher to reduce the aliasing, so 48 kHz seems a good choice --plus, many sound formats come sampled at this very frequency. So, your maximum frequency is 24 kHz and you want 20 Hz resolution. This gives 48,000/20 = 2400 for the size of the chunks. If your FFT routine accepts this size, you're done. If not, then choose the next power of 2 (4096).
2. as you already know, FFT outputs values in the [-fs,fs), range, so it is giving you results for negative frequencies. Also, FFT values are complex numbers, with imaginary as well as real part. This has little physical meaning, so most spectrum analyzers display the energy of the signal as a function of frequency, which is more easily understandable by a human user. So, if we write X(f) for the FFT at frequency f, the energy of the function is
E<sub>X</sub>(f) = |X(f)|<sup>2</sup> + |X(-f)|<sup>2</sup> where |·| is the complex absolute value function (also called modulus). This operation "folds" the negative frequencies into the positive axis, so you only have now positive frequencies and real values (energies), which is fine.
3. Finally, the frequency bands you want to display are not evenly spaced, but they follow an exponential distribution from 20 Hz to 20 kHz. This is fine, as it models the perception system of the human ear. But the FFT gives evenly spaced frequency values (or energies, if you applied the transformation above). To transform from what you've got to the exponential bands, just group the energy points in frequency bands around the frequencies of interest (higher frequencies will get more points) and sum their energies for each band.
Joaquín M López Muñoz
Telefónica, Investigación y Desarrollo
|
|
|
|
|
Joaquín,
RE: 1) Sorry, I mean't base 2 on the size of the chucks but thanks for pointing it out.
RE: 2) Explicado muy bien. Gracias.
RE: 3) You mention picking frequencies of interest. None are particularly interesting to me ,
seriouly is there a techique or formula for picking these points of interest?
New 1) If you want to display the right and left channel at the same time having calculated them
separately do you just average them together?
Muchas gracias Joaguin. De donde está usted?
hasta la vez próxima
Steve
|
|
|
|
|
RE: 3) You mention picking frequencies of interest. None are particularly interesting to me,seriouly is there a techique or formula for picking these points of interest?
Well, frequency spectrums come in two flavors:
- linear: points in the x-axis are evenly spaced (with respect to frequency).
- logarithmic: points in the x-axis are not evenly spaced (like 10 Hz, 20, Hz, 30, HZ, etc.) but on an exponential fashion: for instance, 101 Hz, 102=100 Hz, 103=1000 Hz, etc.
Why the second style (called logarithmic scale)? Many systems, including the human ear, perceive exponentially distributed frequencies as being "perceptually" distributed in an uniform scale. For instance, the musical note C0 has a frequency 16.35 Hz, C1 is at 2·16.35=32.70 Hz, and C2 is at 4·16.35=65.40 Hz, although they "sound" as evenly distributed. Got the idea?
If you want to write a logarithmic spectrum displayer, the problem is that FFT outputs results in a linear scale. To transform to logartichmic you have to do some math in order to compute the different exponential bands and group all points inside a band into a single sample (suming their energies as described in my previous post).
Apart from this, no frequency is regarded as specially important. Go find an electronic spectrum analyzer (like the one in your music equipment) and use those values, for instance.
New 1) If you want to display the right and left channel at the same time having calculated themseparately do you just average them together?
I guess you mean the right and left channel of a stereo signal. The proper way to add them is by suming their energies is
Total = sqrt(Right<sup>2</sup>+Left<sup>2</sup>).
Muchas gracias Joaguin. De donde está usted?
De España. Suerte con tu proyecto,
Joaquín M López Muñoz
Telefónica, Investigación y Desarrollo
|
|
|
|
|
Joaquín,
Las gracias, usted ha sido el más provechoso. Era misionario en Madrid hace aproximadamente 13 años. Estuve en Talavera de la Reina, Getafe, Torrejon, y algunos otros lugares. Bien, sido un placer que hablar con usted.
Haz bien y no mires a quien,
Steve
PS: Sorry for my poor spanish spelling it has been a while.
|
|
|
|
|
Hi,
I would like to hide the view of MDI, so only the toolbar and menu would be visible.
How can I do that?
Ehsan Behboudi
|
|
|
|
|
A way could be to avoid to open a blank file when opening the application.
To do so, in YourApp::InitInstance, set the m_nShellCommand attribute of the CCommandLineInfo object to CCommandLineInfo::FileNothing before processing it (ProcessShellCmd).
From MSDN:
BOOL CMyWinApp::InitInstance()<br />
{<br />
...<br />
CCommandLineInfo cmdInfo;<br />
ParseCommandLine(cmdInfo);<br />
cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing;<br />
if (!ProcessShellCommand(cmdInfo))<br />
return FALSE;<br />
...<br />
};
HTH,
K.
Every gun that is made, every warship launched, every rocket fired, signifies in the final sense a theft from those who hunger and are not fed, those who are cold and are not clothed - Dwight D. Eisenhower
|
|
|
|
|
thanks for your response, but it doesn't seem to work!!!
I copy pasted the code in my InitInstance()
so now it looks like the following:
BOOL CMotionControllerApp::InitInstance()
{
// CG: The following block was added by the Splash Screen component.
\
{
\
CCommandLineInfo cmdInfo;
\
ParseCommandLine(cmdInfo);
\
\
CSplashWnd::EnableSplashScreen(cmdInfo.m_bShowSplash);
\
}
AfxEnableControlContainer();
// Standard initialization
// If you are not using these features and wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not need.
#ifdef _AFXDLL
Enable3dControls(); // Call this when using MFC in a shared DLL
#else
Enable3dControlsStatic(); // Call this when linking to MFC statically
#endif
// Change the registry key under which our settings are stored.
// TODO: You should modify this string to be something appropriate
// such as the name of your company or organization.
SetRegistryKey(_T("Local AppWizard-Generated Applications"));
LoadStdProfileSettings(); // Load standard INI file options
// Register the application's document templates. Document templates
// serve as the connection between documents, frame windows and
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CMotionControllerDoc),
RUNTIME_CLASS(CMainFrame), // main SDI frame window
RUNTIME_CLASS(CMotionControllerView));
AddDocTemplate(pDocTemplate);
// Parse command line for standard shell commands, DDE, file open
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
//This is your code, it is at the correct spot?
cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing;
// Dispatch commands specified on the command line
if (!ProcessShellCommand(cmdInfo))
return FALSE;
// The one and only window has been initialized, so show and update
// m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED);
// m_pMainWnd->UpdateWindow();
return TRUE;
}
Ehsan Behboudi
|
|
|
|
|
I don't understand why you have two calls to ParseCommandLine. The following implementation should be enough.
BOOL CMotionControllerApp::InitInstance()<br />
{<br />
AfxEnableControlContainer();<br />
<br />
<br />
#ifdef _AFXDLL<br />
Enable3dControls();
#else<br />
Enable3dControlsStatic();
#endif<br />
<br />
SetRegistryKey(_T("Local AppWizard-Generated Applications"));<br />
<br />
LoadStdProfileSettings();
<br />
<br />
CSingleDocTemplate* pDocTemplate;<br />
pDocTemplate = new CSingleDocTemplate(<br />
IDR_MAINFRAME,<br />
RUNTIME_CLASS(CMotionControllerDoc),<br />
RUNTIME_CLASS(CMainFrame),
RUNTIME_CLASS(CMotionControllerView));<br />
AddDocTemplate(pDocTemplate);<br />
<br />
CCommandLineInfo cmdInfo;<br />
ParseCommandLine(cmdInfo);<br />
<br />
CSplashWnd::EnableSplashScreen(cmdInfo.m_bShowSplash);<br />
<br />
cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing;<br />
if (!ProcessShellCommand(cmdInfo))<br />
return FALSE;<br />
<br />
<br />
return TRUE;<br />
}
Is the ProcessShellCommand method overriden somewhere in your code?
Check your mail, I sent a small demo application to you.
HTH,
K.
Every gun that is made, every warship launched, every rocket fired, signifies in the final sense a theft from those who hunger and are not fed, those who are cold and are not clothed - Dwight D. Eisenhower
|
|
|
|
|
Hi,
I would like to hide the view of MDI, so only the toolbar and menu would be visible.
How can I do that?
|
|
|
|
|
Hello:
I'm having trouble with this code
//**************CODE**************//
HBITMAP bmpHandle = (HBITMAP) ::LoadImage(NULL, _T("C:\\test\\bmptest.bmp"),
IMAGE_BITMAP, 0,0, LR_LOADFROMFILE) ;
m_Images.SetBitmap(bmpHandle);
//************END CODE************//
I have a dialog box with a listbox control and a picture box or CStatic
control ;
when the application starts up, all the bmp files I have in a folder are
loaded in the listbox.
By clicking on anyone of these files I should see the image into the Picture
control or CStatic control.
The problem is, when I click on a file from the list, the bitmap is NOT displayed entirely in the Picture control, part of it is in and the other
part is out of the picture control, in other words there is a disparity in relation to the size of the control. How do I keep the entire bitmap into the
picture control box.
Do I need to resize the bitmap before loading it, and if so how?
Thanks
|
|
|
|
|
CString szFilename="C:\\test\\bmptest.bmp";
HBITMAP hBmp = (HBITMAP)::LoadImage(NULL,szFilename, IMAGE_BITMAP, 0, 0,
LR_LOADFROMFILE|LR_CREATEDIBSECTION);
CBitmap pic;
pic.Attach(hBmp);
BITMAP pic_header;
pic.GetBitmap(&pic_header);
CWnd* wp = GetDlgItem(IDC_STATIC_BITMAP_GLASROHR);
CDC *pDC = wp->GetDC();
CDC imageDC;
imageDC.CreateCompatibleDC(pDC);
imageDC.SelectObject( &pic);
pDC->BitBlt(3, 3, pic_header.bmWidth, pic_header.bmHeight, &imageDC, 0,
0, SRCCOPY);
imageDC.DeleteDC();
wp->ReleaseDC(pDC);
|
|
|
|
|
Consider the following scenario:
The London underground administration would like to store the following information for each line that it serves: name of line, name of stations for each line and their sequence, the interchange stations.
1.Write a program that reads a list of underground stations and lines into a double circular linked list that is created using dynamic memory allocation.
The underground stations to be used in the assignment are given below. The information about the stations should be written in the Underground.txt file.
Line Stations
District South Kensington
Picadilly South Kensington
Picadilly Knightsbridge
Picadilly Hyde Park Corner
Picadilly Green Park
Picadilly Picadilly Circus
Bakerloo Picadilly Circus
Bakerloo Charing Cross
Bakerloo Embankment
District Embankment
District Victoria
District Sloane Square
Victoria Green Park
Victoria Victoria
The format of the text file can be considered similar to one shown in the above table.
2.Support the program with the additional feature to add a node. This can be used if the station is opened. The user should specify which station should be added.
3.Support the program with the additional feature to delete a node. This can be used if the station is closed. The user should specify which station should be deleted.
4.Allow the user to enter two underground stations: the station of your departure and the station of your arrival. Find the shortest path to get to from one station to another one in terms of the number of underground stations passed. Print the list of stations and name of the lines that you have to pass to get to the station of your destination. Give summary how many lines you have to use, where you have to change and how many stations you have to pass in each line.
------------------------------------------------------------------------------------
Can anybody give me any suggestions on how I could start this assignment. Will I need 2 classes, one for Lines and one for Stations??? Or do I store them both in one class and call it Underground e.g.
struct Underground
{
char nameofstation[MAX CHARS];
char nameofline[MAXCHARS];
Underground *nextstn;
}
Is this correct?????
What do i need to do next????? Can somebody please help.....
|
|
|
|
|
Seems like a bit of school homework to me. You really should figure this out on your own.
|
|
|
|
|
hi all,
I have a round dialog, i use the OnColorCTL to color the background of the dialog to yellow. i use OnPaint and dc.TextOut to display text on the round dialog. also i want to draw an ellipse as a mark for the round dialog border
here is the code i use in the OnPaint():
void CRoundDlg::OnPaint()
{
CPaintDC dc(this);
CRect rect,rectTmp;
GetWindowRect(rect);
ScreenToClient(rect);
rectTmp = CRect(rect.left + 17 * SPACE_MARGINGS,
rect.top + 23 * SPACE_MARGINGS,
rect.Width(),
rect.Height());
CBrush* pOldBrush = dc.SelectObject(&m_brush);
dc.SetBkColor(MESSAGE_BOX_DIALOG_BK_COLOR);
dc.SetTextColor(MESSAGE_BOX_TEXT_COLOR);
dc.TextOut(rectTmp.left,rectTmp.top,m_szText);
dc.PatBlt(0, 0,rect.Width(),rect.Height(), PATCOPY);
CPen* pOldPen= dc.SelectObject(&m_Pen);
rect.DeflateRect(4,4,4,4);
dc.Ellipse(rect);
dc.SelectObject(pOldBrush);
dc.SelectObject(pOldPen);
}
trouble is that i see the rectangle but i don't see the text.....
can any1 help here?
thanks in advanced
Yaron
Ask not what your application can do for you,
Ask what you can do for your application
|
|
|
|
|
Looks like you are painting over the text, dude!
Swap the order of the TextOut and the PatBlt and you should see it.
|
|
|
|
|
thanks that helped me...but only when i moved it after the ellipse drawing...
thanks again
Ask not what your application can do for you,
Ask what you can do for your application
|
|
|
|
|
Try moving the dc.TextOut() after the PatBlt(), or even later still. FYI I use a rounded dialog in ED without any problems.
Neville Franks, Author of ED for Windows. Free Trial at www.getsoft.com
|
|
|
|
|
thanks that helped me...but only when i moved it after the ellipse drawing...
thanks again
Ask not what your application can do for you,
Ask what you can do for your application
|
|
|
|
|
Anyone here knows how to calculate pi in visual c++ 6 to the 100ths maybe less maybe more. I just want to know how maybe an example but I would appreciate a method.
<marquee>Universal Project... Soon to be a .net
|
|
|
|
|
|