SM API
I/Q Streaming

The I/Q streaming mode is used to stream continuous I/Q samples at a given center frequency. The sample rate, bandwidth, center frequency, and data type can be configured. If you need to capture I/Q data at many frequencies or don't need continuous streaming capabilities, consider using the I/Q Sweep List / Frequency Hopping measurements.

Example

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

// Configure the device for I/Q streaming and stream for a period of time
// This example assumes a USB 3.0 SM device.
#include <cstdio>
#include <cstdlib>
#include <vector>
#include "sm_api.h"
void sm_example_iq_stream()
{
int handle = -1;
SmStatus status = smNoError;
// Uncomment this to open a USB SM device
status = smOpenDevice(&handle);
// Uncomment this to open a networked SM device with a default network config
//status = smOpenNetworkedDevice(&handle, SM_ADDR_ANY, SM_DEFAULT_ADDR, SM_DEFAULT_PORT);
// Check open status
if(status != smNoError) {
printf("Unable to open device\n");
exit(-1);
}
// Configure the receiver for IQ acquisition
smSetRefLevel(handle, -20.0); // -20 dBm reference level
smSetIQCenterFreq(handle, 900.0e6); // 900MHz center frequency
smSetIQBaseSampleRate(handle, smIQStreamSampleRateNative); // Use native 50MS/s base sample rate.
smSetIQSampleRate(handle, 2); // 50 / 2 = 25MS/s IQ
smSetIQBandwidth(handle, smTrue, 20.0e6); // 20MHz of bandwidth
// Initialize the receiver with the above settings
status = smConfigure(handle, smModeIQ);
if(status != smNoError) {
printf("Unable to configure device\n");
printf("%s\n", smGetErrorString(status));
smCloseDevice(handle);
exit(-1);
}
// Query the receiver IQ stream characteristics
// Should match what we set earlier
double actualSampleRate, actualBandwidth;
smGetIQParameters(handle, &actualSampleRate, &actualBandwidth);
// Allocate memory for complex sample, IQ pairs interleaved
int bufLen = 16384;
std::vector<float> iqBuf(bufLen * 2);
// Let's acquire 5 second worth of data
int samplesNeeded = 5 * (int)actualSampleRate;
while(samplesNeeded > 0) {
// Notice the purge parameter is set to false, so that each time
// the get IQ function is called, the next contiguous block of data
// is returned.
smGetIQ(handle, &iqBuf[0], bufLen, 0, 0, 0, smFalse, 0, 0);
// Process/store data here
// Data is interleaved 32-bit complex values
// Need bufLen less samples
samplesNeeded -= bufLen;
}
// Finished
smCloseDevice(handle);
}
API functions for the SM435/SM200 spectrum analyzers.
SM_API SmStatus smOpenDevice(int *device)
SM_API SmStatus smSetIQCenterFreq(int device, double centerFreqHz)
SM_API SmStatus smSetIQDataType(int device, SmDataType dataType)
SM_API SmStatus smGetIQ(int device, void *iqBuf, int iqBufSize, double *triggers, int triggerBufSize, int64_t *nsSinceEpoch, SmBool purge, int *sampleLoss, int *samplesRemaining)
SM_API SmStatus smSetIQBandwidth(int device, SmBool enableSoftwareFilter, double bandwidth)
SM_API SmStatus smSetIQBaseSampleRate(int device, SmIQStreamSampleRate sampleRate)
@ smDataType32fc
Definition: sm_api.h:234
SM_API SmStatus smGetIQParameters(int device, double *sampleRate, double *bandwidth)
@ smFalse
Definition: sm_api.h:378
@ smTrue
Definition: sm_api.h:380
SM_API SmStatus smSetIQSampleRate(int device, int decimation)
SM_API SmStatus smSetRefLevel(int device, double refLevel)
@ smIQStreamSampleRateNative
Definition: sm_api.h:279
SM_API SmStatus smCloseDevice(int device)
SM_API SmStatus smConfigure(int device, SmMode mode)
SM_API const char * smGetErrorString(SmStatus status)
SmStatus
Definition: sm_api.h:142
@ smNoError
Definition: sm_api.h:203

Basics

The API provides the ability to stream I/Q samples up to the device’s native sample rate or common LTE sample rates. See I/Q Sample Rates for more information.

I/Q data can be retrieved as 32-bit complex floats or 16-bit complex shorts. See I/Q Data Types for more information.

Sample Rate, Decimation, and Bandwidth

The I/Q data stream can be decimated by powers of 2 between 1 and 4096, starting at either the native sample rate or an LTE sample rate. Filtering is performed at each decimation stage. The final filter cutoff frequency is user selectable.

(USB SM devices only) For decimations [1,2,4,8], custom cutoff frequencies are accomplished with a PC side lowpass filter. The PC software filter is optional for decimations between 1 and 8. If the software filter is disabled the FPGA half band filters are the only alias filter used for these decimation stages and there will be aliased signals in the roll off regions of the I/Q bandwidth. Disabling the software filter will reduce CPU load of the I/Q data stream at the cost of this aliasing.

(10GbE SM devices only) For decimations [1,2,4,8], custom cutoff frequencies are performed on the device with no CPU penalty, and as such these filters are always active.

For all devices, using decimations greater than 8, decimation and filtering occur entirely on the PC. The cutoff frequency of the filter must obey the Nyquist frequency for the selected sample rate. The downsample filter sizes cannot be changed and thus the roll off transition region is a fixed size for each decimation setting.

Polling Interface (I/Q)

The API for the I/Q data stream is a polling style interface, where the application must request I/Q data in blocks that will keep up with the device acquisition of data. The APIs internal circular buffer can store up to 1/2 second worth of I/Q data before data loss occurs. It is the responsibility of the user’s application to poll the I/Q data fast enough that data loss does not occur.

External Triggering

External trigger information can be retrieved when I/Q streaming. Trigger information is provided through the triggers buffer in the smGetIQ function.

If a trigger buffer is provided to smGetIQ, any external trigger events seen during the acquisition of the returned I/Q data will be placed in the trigger buffer. External trigger events are returned as indices into the I/Q data at which the trigger event occurred. For example, if 1000 I/Q samples are requested and a trigger buffer of size 3 is provided, and the function returns with the trigger buffer set to [12,300,876], this indicates that an external trigger event occurred at I/Q sample index 12, 300, and 876 in the I/Q data returned from this function call.

If fewer external triggers were seen during the I/Q acquisition than the size of the trigger buffer provided, the remainder of the trigger buffer is set to the sentinel value. The default sentinel value is 0.0, so for example, if a trigger buffer of size 3 is provided, and only a single trigger event was seen, the trigger buffer will return [N, 0.0, 0.0] where N is the single trigger index returned.

If more trigger events were seen during the I/Q acquisition than the size of the trigger buffer, those trigger events that cannot fit in the buffer are discarded.

Triggers are provided as doubles and non-integer values can indicate the trigger occurred in between 2 samples. This can occur when performing decimation, as the triggers are recorded at a much higher resolution than the final sample rate.

A note on trigger sentinel values, the default sentinel value of 0.0 does not allow the detection of triggers occurring at the first sample point. If this is an issue, set the sentinel value to -1.0 or some other negative value which cannot be normally returned. The default value of 0.0 is the result of historical choices and will remain the default value.

Additional Information

See I/Q Acquisiton for more information.