Click here to Skip to main content
Click here to Skip to main content

A Powerful Spectrum Analyzer Based on DirectX

, 7 Nov 2009
Rate this:
Please Sign up or sign in to vote.
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:

#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:

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.

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}.

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}.

// 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}.

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)

About the Author

Ali Tavakol
Engineer
Iran (Islamic Republic Of) Iran (Islamic Republic Of)
No Biography provided

Comments and Discussions

 
QuestionRe Pinmemberektel16-Oct-12 22:02 
QuestionHelp me Pinmemberyaquza2-May-12 2:52 
Questionکمک PinmemberMember 39106094-Mar-12 21:38 
AnswerRe: کمک PinmemberAli Tavakol5-Mar-12 2:57 
GeneralRe: PinmemberMember 39106095-Mar-12 21:53 
Thank you!!! Smile | :)
GeneralMy vote of 5 Pinmembercowg1-Jan-12 1:59 
GeneralMy vote of 5 PinmemberMarius Iulian Mihailescu23-Aug-11 2:18 
GeneralDear Ali Tavakol Pinmemberhosein20-Apr-11 10:07 
GeneralRe: Dear Ali Tavakol PinmemberAli Tavakol22-Apr-11 8:01 
GeneralRe: Dear Ali Tavakol PinmemberAli Tavakol22-Apr-11 8:05 
GeneralDear Ali Tavakol Pinmemberhosein31-Mar-11 9:33 
GeneralRe: Dear Ali Tavakol PinmemberAli Tavakol31-Mar-11 23:01 
GeneralDear Ali Tavakol Pinmembermojy11515064-Jan-11 20:08 
GeneralRe: Dear Ali Tavakol PinmemberAli Tavakol5-Jan-11 2:13 
GeneralWorks fine with VC 8 Pinmembermathewjohnth6-Apr-10 1:41 
QuestionCan this code be ported to VC6? Pinmembermelvinwxf29-Mar-10 4:05 
AnswerRe: Can this code be ported to VC6? PinmemberAli Tavakol29-Mar-10 21:07 
AnswerRe: Can this code be ported to VC6? Pinmemberfishflynudt13-Sep-11 5:32 
QuestionWhat is the limitation of signal generation? Can you generate 5MHz signal? Pinmemberkzhao66@yahoo.com18-Dec-09 3:02 
AnswerRe: What is the limitation of signal generation? Can you generate 5MHz signal? PinmemberAli Tavakol19-Dec-09 0:48 
GeneralNOTICE PinmemberAli Tavakol16-Nov-09 2:20 
GeneralGreat work, although the demo cannot be extracted – you got my 5 any way PinmemberTage Lejon8-Nov-09 22:09 
GeneralRe: Great work, although the demo cannot be extracted – you got my 5 any way PinmemberAli Tavakol8-Nov-09 22:32 
GeneralRe: Great work, although the demo cannot be extracted – you got my 5 any way PinmemberAli Tavakol8-Nov-09 22:37 
GeneralRe: Great work, although the demo cannot be extracted – you got my 5 any way Pinmemberqweqwe9-Nov-09 1:57 

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

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

| Advertise | Privacy | Mobile
Web01 | 2.8.140721.1 | Last Updated 7 Nov 2009
Article Copyright 2009 by Ali Tavakol
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid