SA API
Modes of Operation

Now that we have seen how a typical application interfaces with the API, let’s examine the different modes of operation the API provides. Each mode will accept different configurations and have different boundary conditions. Each mode will also provide data formatted to match the mode selected. In the next sections you will see how to interact with each mode.

For a more in-depth examination of each mode of operation (read: theory) refer to the Spike User Manual.

Please also see the C++ programming examples for an example of interfacing the device for each measurement type.

Swept Spectrum Analysis

Swept analysis represents the most traditional form of spectrum analysis. This mode offers the largest amount of configuration options, and returns traditional frequency domain sweeps. A frequency domain sweep displays amplitude on the vertical axis and frequency on the horizontal axis.

Example

For a list of all examples, please see the examples/ folder in the SDK.

#include "sa_api.h"
#pragma comment(lib, "sa_api.lib")
#include <iostream>
// This example is the minimal code needed to configure the device
// to perform a single sweep. The device will block for several seconds
// while opening the device, and the call to saGetSweep will block
void simpleSweep1()
{
int handle = -1;
saStatus openStatus = saOpenDevice(&handle);
if(openStatus != saNoError) {
// Handle unable to open/find device error here
std::cout << saGetErrorString(openStatus) << std::endl;
return;
}
// Configure the device to sweep a 1MHz span centered on 900MHz
// Min/Max detector, with RBW/VBW equal to 1kHz
saConfigCenterSpan(handle, 900.0e6, 1.0e6);
saConfigLevel(handle, -10.0);
saConfigSweepCoupling(handle, 1.0e3, 1.0e3, true);
// Initialize the device with the configuration just set
saStatus initiateStatus = saInitiate(handle, SA_SWEEPING, 0);
if(initiateStatus != saNoError) {
// Handle unable to initialize
std::cout << saGetErrorString(initiateStatus) << std::endl;
return;
}
// Get sweep characteristics
int sweepLen;
double startFreq, binSize;
saQuerySweepInfo(handle, &sweepLen, &startFreq, &binSize);
// Allocate memory for the sweep
float *min = new float[sweepLen];
float *max = new float[sweepLen];
// Get 1 or more sweeps with this configuration
// This function can be called several times and will return a
// sweep measured directly after the function is called.
// The function blocks until the sweep is returned.
saStatus sweepStatus = saGetSweep_32f(handle, min, max);
delete [] min;
delete [] max;
saAbort(handle);
saCloseDevice(handle);
}
API functions for the SA44/124 spectrum analyzers.
SA_API saStatus saGetSweep_32f(int device, float *min, float *max)
#define SA_LOG_SCALE
Definition: sa_api.h:129
#define SA_MIN_MAX
Definition: sa_api.h:124
SA_API saStatus saConfigCenterSpan(int device, double center, double span)
SA_API saStatus saConfigSweepCoupling(int device, double rbw, double vbw, bool reject)
SA_API saStatus saConfigLevel(int device, double ref)
SA_API saStatus saOpenDevice(int *device)
SA_API saStatus saConfigAcquisition(int device, int detector, int scale)
saStatus
Definition: sa_api.h:237
@ saNoError
Definition: sa_api.h:298
SA_API saStatus saAbort(int device)
SA_API saStatus saQuerySweepInfo(int device, int *sweepLength, double *startFreq, double *binSize)
SA_API const char * saGetErrorString(saStatus code)
SA_API saStatus saCloseDevice(int device)
#define SA_SWEEPING
Definition: sa_api.h:108
SA_API saStatus saInitiate(int device, int mode, int flag)

Configuration

The configuration routines which affect the sweep results are:

Once you have configured the device, call saInitiate using the SA_SWEEPING flag.

Usage

This mode is driven by the programmer, causing a sweep to be collected only when the program requests one through the saGetSweep_32f/saGetSweep_64f functions. The length of the sweep is determined by a combination of resolution bandwidth, video bandwidth, and span.

Once the device is initialized you can determine the characteristics of the sweep you will be collecting with saQuerySweepInfo. This function returns the length of the sweep, the frequency of the first bin, and the bin size. You will need to allocate two arrays of memory, representing the minimum and maximum values for each frequency bin.

Now you are ready to call the saGetSweep_32f/saGetSweep_64f and saGetPartialSweep_32f/saGetPartialSweep_64f functions.

You can determine the frequency of any bin in the resulting sweep by the following function, where n is the zero-based index into the sweep array:

Frequency of nth sample point in returned sweep = startFreq + n * binSize

Real-Time Spectrum Analysis

The API provides the functionality of an online real-time spectrum analyzer for the full instantaneous bandwidth of the device (250kHz). In real-time FFTs are applied at an overlapping rate of 87.5%.

Example

For a list of all examples, please see the examples/ folder in the SDK.

#include "sa_api.h"
#pragma comment(lib, "sa_api.lib")
#include <iostream>
void realTimeSweep()
{
int handle = -1;
saStatus openStatus = saOpenDevice(&handle);
if(openStatus != saNoError) {
// Handle unable to open/find device error here
std::cout << saGetErrorString(openStatus) << std::endl;
return;
}
// Configure real-time analysis to be centered on a local
// FM broadcast frequency, with a 1kHz RBW.
// Set a frame rate of 30fps, and 100dB height on persistence frames.
saConfigCenterSpan(handle, 97.1e6, 200.0e3);
saConfigLevel(handle, -10.0);
saConfigSweepCoupling(handle, 1.0e3, 1.0e3, true);
saConfigRealTime(handle, 100.0, 30);
// Initialize the device with the configuration just set
saStatus initiateStatus = saInitiate(handle, SA_REAL_TIME, 0);
if(initiateStatus != saNoError) {
// Unable to initialize
std::cout << saGetErrorString(initiateStatus) << std::endl;
return;
}
// Get sweep and frame characteristics
int sweepLen;
double startFreq, binSize;
saQuerySweepInfo(handle, &sweepLen, &startFreq, &binSize);
int frameWidth, frameHeight;
saQueryRealTimeFrameInfo(handle, &frameWidth, &frameHeight);
// Allocate memory for the sweep and frame
float *max = new float[sweepLen];
float *frame = new float[frameWidth * frameHeight];
// Get 30 frames and sweeps, representing 1 second of real-time analysis
int frames = 0;
while(frames < 30) {
saStatus sweepStatus = saGetRealTimeFrame(handle, nullptr, max, frame, nullptr);
frames++;
// Update your application
}
saAbort(handle);
delete [] max;
delete [] frame;
saCloseDevice(handle);
}
SA_API saStatus saGetRealTimeFrame(int device, float *minSweep, float *maxSweep, float *colorFrame, float *alphaFrame)
SA_API saStatus saConfigRealTime(int device, double frameScale, int frameRate)
SA_API saStatus saQueryRealTimeFrameInfo(int device, int *frameWidth, int *frameHeight)
#define SA_REAL_TIME
Definition: sa_api.h:110

Configuration

The configuration routines which affect the spectrum results are the same for swept analysis, but span is restricted to 250kHz.

Once you have configured the device, call saInitiate using the SA_REAL_TIME flag.

Usage

The number of sweep results far exceeds a program’s capability to acquire, view, and process, therefore the API combines sweeps results for a user specified amount of time. It does this in two ways. One, is the API either min/max holds or averages the sweep results into a standard sweep.

Also, the API creates an image frame which acts as a density map for every sweep result processed during a period. Both the sweep and density map are returned at rate specified by the function saConfigRealTime.

An alpha frame is also provided by the API. The alphaFrame is the same size as the frame and each index correlates to the same index in the frame. The alphaFrame values represent activity in the frame. When activity occurs in the frame, the index correlating to that activity is set to 1. As time passes and no further activity occurs in that bin, the alphaFrame exponentially decays from 1 to 0. The alphaFrame is useful to determine how recent the activity in the frame is and useful for plotting the frames.

For a full example of using real-time see Real-Time Spectrum Analysis.

I/Q Streaming

The API can provide programmers with a continuous stream of digital I/Q samples from the device.

Example

For a list of all examples, please see the examples/ folder in the SDK.

#include "sa_api.h"
#pragma comment(lib, "sa_api.lib")
#include <iostream>
// This example demonstrates configuring the device to stream continuous
// IQ data to your application.
void iqStreaming()
{
int handle = -1;
saStatus openStatus = saOpenDevice(&handle);
if(openStatus != saNoError) {
// Handle unable to open/find device error here
std::cout << saGetErrorString(openStatus) << std::endl;
return;
}
// Set center freq, span is ignored
saConfigCenterSpan(handle, 97.1e3, 1.0e3);
// Set expected input level
saConfigLevel(handle, -10.0);
// Configure sample rate and bandwidth
// Sample rate of 486111.11 / 1 and bandwidth of 250kHz
saConfigIQ(handle, 1, 250.0e3);
saInitiate(handle, SA_IQ, 0);
// Verify the sample rate and bandwidth of the IQ stream
double bandwidth, sampleRate;
saQueryStreamInfo(handle, 0, &bandwidth, &sampleRate);
// How many IQ samples to collect per call
const int BUF_SIZE = 4096;
pkt.iqData = new float[BUF_SIZE * 2];
pkt.iqCount = BUF_SIZE;
// Setting purge to false ensures each call to getIQPacket()
// returns contiguous IQ data to the last time the function was called.
// This also means IQ data must be queried at the rate of the
// device sample rate. In this case, the sample rate is 486.111k,
// so the saGetIQData function must be called
// 486111 / 4096 = ~118 times per second.
pkt.purge = false;
// Retreive about 1 second worth of contiguous IQ data or
// 120 * 4096 IQ data values.
int pktCount = 0;
while(pktCount++ < 120) {
// Get next contiguous block of IQ data
saStatus iqStatus = saGetIQData(handle, &pkt);
std::cout << pkt.sec << " " << pkt.milli << std::endl;
// Store/process data before getting another buffer
// Check any errors or status updates
}
// Clean up
delete [] pkt.iqData;
saAbort(handle);
saCloseDevice(handle);
}
SA_API saStatus saConfigIQ(int device, int decimation, double bandwidth)
SA_API saStatus saGetIQData(int device, saIQPacket *pkt)
#define SA_IQ
Definition: sa_api.h:112
SA_API saStatus saQueryStreamInfo(int device, int *returnLen, double *bandwidth, double *samplesPerSecond)
Definition: sa_api.h:191
int iqCount
Definition: sa_api.h:199
int sec
Definition: sa_api.h:224
int milli
Definition: sa_api.h:229
int purge
Definition: sa_api.h:207
float * iqData
Definition: sa_api.h:197

Configuration

Configuration routines used to prepare streaming are:

Once configured, initialize the device with the SA_IQ mode.

Usage

The digital I/Q stream consists of interleaved 32-bit floating point I/Q pairs scaled to mW. The digital samples are amplitude corrected providing accurate measurements. The I/Q data rate at its highest is 486.111111~ kS/s and can be decimated down by a factor of up to 128 (in powers of two). Each decimation value further reduces the overall bandwidth of the I/Q samples, so the API also provides a configurable bandpass filter to control the overall passband of a given I/Q data stream. The I/Q data stream can also be tuned to an arbitrary center frequency.

Data acquisition begins immediately. The API buffers ~3/4 second worth of digital samples in circular buffers. It is the responsibility of the user application to poll the samples via saGetIQData fast enough to prevent the circular buffers from wrapping. We suggest a separate polling thread and synchronized data structure (buffer) for retrieving the samples and using them in your application.

NOTE: Decimation / filtering / calibration occur on the PC and can be processor-intensive on certain hardware. Please characterize the processor load if you think this might be an issue for your application.

Audio Demodulation

Configuration

Configure audio demodulation with:

  • saConfigAudio - Specify the type of demodulation, the center frequency, and the characteristics of the filters.
    • See saConfigAudio to see which types of audio demodulation can be performed.
  • saConfigGainAtten - Audio demodulation does not have auto ranging as do other operational modes, so saConfigGainAtten must be called to configure the internal gain, attenuator, and preamplifier.

Once configured, initialize the device with the SA_AUDIO mode.

Usage

Once the device is streaming, use saGetAudio to retrieve 4096 audio samples for an audio sample rate of 30382. The API buffers many seconds' worth of audio.

Scalar Network Analysis

When a Signal Hound tracking generator is paired together with a spectrum analyzer, the product can function as a scalar network analyzer to perform insertion loss measurements,or return loss measurements by adding a directional coupler. Throughout this document, this functionality will be referred to as tracking generator (or TG) sweeps.

Example

For a list of all examples, please see the examples/ folder in the SDK.

#include "sa_api.h"
#pragma comment(lib, "sa_api.lib")
#include <iostream>
// This example demonstrates how to use the API to perform a single TG sweep.
// See the manual for a full description of each step of the process in the
// Scalar Network Analysis section.
void trackingGeneratorSweep()
{
int handle = -1;
saStatus openStatus = saOpenDevice(&handle);
if(openStatus != saNoError) {
// Handle unable to open/find device error here
std::cout << saGetErrorString(openStatus) << std::endl;
return;
}
if(saAttachTg(handle) != saNoError) {
// Unable to find tracking generator
return;
}
// Sweep some device at 900MHz center with 1MHz span
saConfigCenterSpan(handle, 900.0e6, 1.0e6);
saConfigLevel(handle, -10.0);
saConfigSweepCoupling(handle, 1.0e3, 1.0e3, true);
// Additional configuration routine
// Configure a 100 point sweep
// The size of the sweep is a suggestion to the API, it will attempt to
// get near the requested size.
// Optimized for high dynamic range and passive devices
saConfigTgSweep(handle, 100, true, true);
// Initialize the device with the configuration just set
if(saInitiate(handle, SA_TG_SWEEP, 0) != saNoError) {
// Handle unable to initialize
return;
}
// Get sweep characteristics
int sweepLen;
double startFreq, binSize;
saQuerySweepInfo(handle, &sweepLen, &startFreq, &binSize);
// Allocate memory for the sweep
float *min = new float[sweepLen];
float *max = new float[sweepLen];
// Create test set-up without DUT present
// Get one sweep
saGetSweep_32f(handle, min, max);
// Store baseline
// Should pause here, and insert DUT into test set-up
saGetSweep_32f(handle, min, max);
// From here, you can sweep several times without needing to restore the thru,
// once you change your setup, you should reconfigure the device and
// store the thru again without the DUT inline.
delete [] min;
delete [] max;
saAbort(handle);
saCloseDevice(handle);
}
#define TG_THRU_0DB
Definition: sa_api.h:163
#define SA_TG_SWEEP
Definition: sa_api.h:116
SA_API saStatus saStoreTgThru(int device, int flag)
SA_API saStatus saAttachTg(int device)
SA_API saStatus saConfigTgSweep(int device, int sweepSize, bool highDynamicRange, bool passiveDevice)

Configuration and Usage

Scalar Network Analysis can be realized by following these steps:

  1. Ensure a Signal Hound spectrum analyzer and tracking generator is connected to your PC.
  2. Open the spectrum analyzer through normal means.
  3. Associate a tracking generator to a spectrum analyzer by calling saAttachTg. At this point, if a TG is present, it is claimed by the API and cannot be discovered again until saCloseDevice is called.
  4. Configure the device as normal, setting sweep frequencies and reference level (or manually setting gain and attenuation).
  5. Configure the TG sweep with the saConfigTgSweep function. This function configures TG sweep specific parameters.
  6. Call saInitiate with the SA_TG_SWEEP mode flag.
  7. Get the sweep characteristics with saQuerySweepInfo.
  8. Connect the SA and TG device into the final test state without the DUT and perform one sweep with saGetSweep_32f/saGetSweep_64f or saGetPartialSweep_32f/saGetPartialSweep_64f. After one full sweep has returned, call saStoreTgThru with the TG_THRU_0DB flag.
  9. (Optional) Configure the setup again still without the DUT but with a 20dB pad inserted into the system. Perform an additional full sweep and call saStoreTgThru with the TG_THRU_20DB.
  10. Once store through has been called, insert your DUT into the system and then you can freely call the get sweep functions until you modify the configuration or settings.

If you modify the test setup or want to re-initialize the device with a new configuration, the store thru must be performed again.