Click here to Skip to main content
15,868,419 members
Articles / Multimedia / DirectX

A Powerful Spectrum Analyzer Based on DirectX

Rate me:
Please Sign up or sign in to vote.
4.86/5 (22 votes)
7 Nov 2009CPOL5 min read 93.7K   22.8K   70   29
Fast, beautiful, real and easy to connect to your application

The Spectrum Analyzer, displaying spectrum of a QPSK stream

Introduction

This project simulates a real spectrum analyzer. Any application that deals with communication signals, such as an FM receiver, can use this application to monitor signal spectrum in Fourier-domain. In fact, your application will communicate with my project using the Inter-Process Communication (IPC) method. You create a shared buffer with a predefined structure. Then, you specify a sample rate (Fs), a refresh rate (Rf), and finally, you send me time-domain samples of the signal in a real-time manner. The spectrum analyzer will use these information to compute signal spectrum and display it, yet in a real-time manner.

The principal feature of my spectrum analyzer is its high speed and low load on CPU. To achieve this goal, I took advantage of Direct3D power. So, most of the rendering workload is carried out by the GPU. You must have a good graphics card to use the benefits. In addition, I used the Intel® Math Kernel Library to perform Fourier transformation and other heavy mathematical operations. If you have an Intel® processor, you are set! See remarks for more details.

Other important features of the application are:

  • Full screen mode (Alt + Enter)
  • Zoom-in and zoom-out
  • In-place vertical ruler
  • Movement of the view (left mouse button), which works after zooming-in
  • Peak hold

Background

Before proceeding, please download and run the demo application. Then, you will have a basic understanding of how the spectrum analyzer works. The demo package consists of two projects: Spectrum Analyzer and Signal Generation. The latter project generates the time-domain samples of a QPSK channel having a sample rate of 1 KHz. Then, it will execute the former project, which is the spectrum analyzer. Signal Generation continually stores sample data in a shared buffer, and Spectrum Analyzer reads the shared buffer to calculate and display the spectrum of the signal.

Zooming in

I used an interesting algorithm to handle zoom-in, zoom-out, movement, and other similar operations. As you may know from Direct3D, you have to specify three matrices to describe the geometry of the scene:

  • World Transform: which defines the position of objects within the world
  • View Transform: which tells the position and orientation of the camera within the world
  • Projection Transform: which defines the camera viewport (e.g., its horizontal and vertical view angles)

To handle zoom-in and zoom-out operations, I change the projection matrix appropriately. For example, when you zoom-in horizontally, I decrease the horizontal viewport angle of the camera. To handle movements, I change the view matrix appropriately. For example, when you move the scene to the right, I change the viewport matrix as if the camera moves to the left.

Using the Code

In the following explanation, you will encounter several numbers surrounded by brackets. These marks refer to a location within the source code. For example, {1} means that you can search for /*{1}*/ within the downloaded source, and the related code can be found there.

As I mentioned earlier, your application will communicate with me using a shared buffer. To have the definition of this buffer and to use the following functions, you must include two header files of the Spectrum Analyzer project to your project: Shared Buffer.h and IPC.h {7}. Below, you see the structure of the shared buffer, defined in Shared Buffer.h:

C++
#define BULK_SIZE    1000    // Buffer bulk size
#define FFT_LENGTH    512    // FFT length

struct SHARED_BUFFER
{
    // Time-domain samples (float complex)
    Complex8    Sample[2 * BULK_SIZE];

    float    Fs;    // Sample rate [Hz]
    float    Rf;    // Refresh rate [Hz]
    int    nAverage;    // Number of frames to include in averaging

    HWND    hWnd;    // Oscilloscope Window
};

A global instance of this structure is created within IPC.h:

C++
SHARED_BUFFER *pSharedBuffer = NULL;

The shared buffer must be created by your application by calling CreateMapFile() {1}. Then, you initialize the sample rate pSharedBuffer->Fs, the refresh rate pSharedBuffer->Rf, and the number of frames to include in averaging pSharedBuffer->nAverage {2}. Note that pSharedBuffer->nAverage should not exceed 20.

C++
if(!CreateMapFile())
    goto err;    // Fatal error
pSharedBuffer->nAverage = 5;
pSharedBuffer->Fs = BULK_SIZE;
pSharedBuffer->Rf = 25;

Then, you have to execute the spectrum analyzer. Be careful to state the correct path to the executable file {6}.

C++
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
ZeroMemory(&pi, sizeof(pi));
CreateProcess("Spectrum Analyzer.exe", NULL, NULL, NULL, TRUE, 
              NULL, NULL, NULL, &si, &pi);

After that, you continually fill pSharedBuffer->Sample with sample data in sync with the sample rate {3},{4}. pSharedBuffer->Sample is a circular buffer; i.e., whenever you reach the end of it, you will have to continue to write from its beginning. In the demo application, TimeProc is responsible to write sample data in the shared buffer. It is called by a multimedia timer every second to write 1000 new data (which equals the sample rate) {3},{4}.

C++
// A global variable filled with QPSK samples
Complex8 Signal[SIGNAL_LENGTH];

void CALLBACK TimeProc(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
{
    static int j = 0;
    static int k = 0;

    i = min(BULK_SIZE, 2 * BULK_SIZE - k);

    // fill pSharedBuffer->Sample with samples
    CopyMemory(pSharedBuffer->Sample + k, Signal + j, i * sizeof(Complex8));

    // Wrap to the beginning of pSharedBuffer->Sample 
    // and store remaining samples
    CopyMemory(pSharedBuffer->Sample, Signal + j + i, 
              (BULK_SIZE - i) * sizeof(Complex8));

    j = (j + BULK_SIZE) % SIGNAL_LENGTH;
    k = (k + BULK_SIZE) % (2 * BULK_SIZE);
}

When you are finished working with the spectrum analyzer, you can close it easily by sending a WM_QUIT message to its window and then destroying the shared buffer by calling CloseMapFile() {5}.

C++
PostMessage(pSharedBuffer->hWnd, WM_QUIT, 0, 0);
CloseMapFile();

Remarks

  1. In case you want to customize or compile the code, you must have Direct3D 9.0 SDK and Intel® Math Kernel Library installed and integrated with Visual Studio. Elsewhere, having the executable spectrum analyzer and its libraries (included in my demo application) is enough.
  2. I have a problem with averaging. It doesn't work. When I increase pSharedBuffer->nAverage, the spectrum curve does not become smooth. I think averaging is not just adding n consecutive frames divided by n. Got any ideas?
  3. I'm not going to compete with a real spectrum analyzer like a Rohde-Schwarz® one! But they have many interesting features that can also be added to this project. Among them, video bandwidth, frequency change, and screen resolution can be enumerated. If you have any ideas about implementing these features, please notify me about it. You can change the code and inform me to collaborate on this free project. I'm looking forward to hearing from you.

History

  • November 8, 2009: First version released. Waiting for feedback.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Engineer
Iran (Islamic Republic of) Iran (Islamic Republic of)
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionRe Pin
ektel16-Oct-12 22:02
ektel16-Oct-12 22:02 
QuestionHelp me Pin
yaquza2-May-12 2:52
yaquza2-May-12 2:52 
Questionکمک Pin
Member 39106094-Mar-12 21:38
Member 39106094-Mar-12 21:38 
AnswerRe: کمک Pin
Ali Tavakol5-Mar-12 2:57
Ali Tavakol5-Mar-12 2:57 
GeneralRe: Pin
Member 39106095-Mar-12 21:53
Member 39106095-Mar-12 21:53 
GeneralMy vote of 5 Pin
cowg1-Jan-12 1:59
cowg1-Jan-12 1:59 
GeneralMy vote of 5 Pin
Marius Iulian Mihailescu23-Aug-11 2:18
professionalMarius Iulian Mihailescu23-Aug-11 2:18 
GeneralDear Ali Tavakol Pin
hosein20-Apr-11 10:07
hosein20-Apr-11 10:07 
GeneralRe: Dear Ali Tavakol Pin
Ali Tavakol22-Apr-11 8:01
Ali Tavakol22-Apr-11 8:01 
GeneralRe: Dear Ali Tavakol Pin
Ali Tavakol22-Apr-11 8:05
Ali Tavakol22-Apr-11 8:05 
GeneralDear Ali Tavakol Pin
hosein31-Mar-11 9:33
hosein31-Mar-11 9:33 
GeneralRe: Dear Ali Tavakol Pin
Ali Tavakol31-Mar-11 23:01
Ali Tavakol31-Mar-11 23:01 
GeneralDear Ali Tavakol Pin
mojy11515064-Jan-11 20:08
mojy11515064-Jan-11 20:08 
GeneralRe: Dear Ali Tavakol Pin
Ali Tavakol5-Jan-11 2:13
Ali Tavakol5-Jan-11 2:13 
GeneralWorks fine with VC 8 Pin
mathewjohnth6-Apr-10 1:41
mathewjohnth6-Apr-10 1:41 
QuestionCan this code be ported to VC6? Pin
melvinwxf29-Mar-10 4:05
melvinwxf29-Mar-10 4:05 
AnswerRe: Can this code be ported to VC6? Pin
Ali Tavakol29-Mar-10 21:07
Ali Tavakol29-Mar-10 21:07 
AnswerRe: Can this code be ported to VC6? Pin
fishflynudt13-Sep-11 5:32
fishflynudt13-Sep-11 5:32 
QuestionWhat is the limitation of signal generation? Can you generate 5MHz signal? Pin
kzhao66@yahoo.com18-Dec-09 3:02
kzhao66@yahoo.com18-Dec-09 3:02 
AnswerRe: What is the limitation of signal generation? Can you generate 5MHz signal? Pin
Ali Tavakol19-Dec-09 0:48
Ali Tavakol19-Dec-09 0:48 
GeneralNOTICE Pin
Ali Tavakol16-Nov-09 2:20
Ali Tavakol16-Nov-09 2:20 
GeneralGreat work, although the demo cannot be extracted – you got my 5 any way Pin
Tage Lejon8-Nov-09 22:09
Tage Lejon8-Nov-09 22:09 
Hey Ali

Extraction of the demo zip file yielded a rar file, which cannot be extracted further to executable. So running you demo is impossible, unfortunately Confused | :confused: .

You code looks so great and I voted a 5 for it in any rate, however Big Grin | :-D .

A little consideration with “Intel® Math Kernel Library (Intel® MKL) 10.2” – why is it necessary? Present CPU is so powerful, fully capable to play video of very high resolution and complexity involving a lot of video decoding operation, such that you application could certainly work perfectly without the extra library.

I would therefore suggest you to make an other version of your powerful application with DirectX only, probably with some open source math lib of good quality if you like. This will make it more appreciated, and more useful.

Thank you for sharing you work with us! Thumbs Up | :thumbsup:
GeneralRe: Great work, although the demo cannot be extracted – you got my 5 any way Pin
Ali Tavakol8-Nov-09 22:32
Ali Tavakol8-Nov-09 22:32 
GeneralRe: Great work, although the demo cannot be extracted – you got my 5 any way Pin
Ali Tavakol8-Nov-09 22:37
Ali Tavakol8-Nov-09 22:37 
GeneralRe: Great work, although the demo cannot be extracted – you got my 5 any way Pin
qweqwe9-Nov-09 1:57
qweqwe9-Nov-09 1:57 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.