Remote Spectrum Monitor User Guide : Programming with SCPI : I/Q Capture Block Mode
 
I/Q Capture Block Mode
This mode captures a single block of IQ data. I/Q data is first stored to high speed DDR2 SDRAM buffer memory and then it can be saved to flash memory or sent to a remote user via Ethernet. The capture length (duration) is limited by the size of the buffer memory (256 Mbytes) and I/Q data rate, which is determined by the capture bandwidth.
The IQ capture bandwidth must be set to one of the available values listed in the table below. For each selectable bandwidth, the output data rate for a single I/Q data pair is listed in Table: IQ Capture Bandwidth Values. The output data rate does not change, regardless of bit resolution.
IQ Capture Bandwidth Values
I/Q Bandwidth
Output Data Rate MSPS
IQ Sample Pairs/Sec
20 MHz
76.25 / 3
25416666.67
13.3 MHz
76.25 / 4
19062500
6.67 MHz
76.25 / 8
9531250
2.67 MHz
76.25 / 20
3812500
1.33 MHz
76.25 / 40
1906250
667 kHz
76.25 / 80
953125
267 kHz
76.25 / 200
381250
133 kHz
76.25 / 400
190625
66.7 kHz
76.25 / 800
95312.5
26.7 kHz
76.25 / 2000
38125
13.3 kHz
76.25 / 4000
19062.5
6.67 kHz
76.25 / 8000
9531.5
2.76 kHz
76.25 / 20000
3812.5
1.33 kHz
76.25 / 40000
1906.3
The maximum capture length is limited by memory, capture bandwidth and bit resolution. Table: Maximum I/Q Block Capture Length shows the maximum capture length.
 
 
 
 
 
Maximum I/Q Block Capture Length
I/Q Bandwidth
24 bits
16 bits
10 bits
8 bits
20 MHz1
1.3
s
2.5
s
3.8
s
5.0
s
13.3 MHz
1.7
s
3.4
s
5.0
s
6.7
s
6.67 MHz
3.4
s
6.7
s
10.1
s
13.4
s
2.67 MHz
8.4
s
16.8
s
25.2
s
33.6
s
1.33 MHz
16.8
s
33.6
s
50.4
s
1.12
min
667 kHz
33.6
s
1.12
min
1.68
min
2.24
min
267 kHz
1.40
min
2.80
min
4.20
min
5.60
min
133 kHz
2.80
min
5.60
min
8.39
min
11.19
min
66.7 kHz
5.60
min
11.19
min
16.79
min
22.38
min
26.7 kHz
13.99
min
27.98
min
41.97
min
55.96
min
13.3 kHz
27.98
min
55.96
min
1.40
hr
1.87
hr
6.67 kHz
55.96
min
1.87
hr
2.80
hr
3.73
hr
2.67 kHz
2.33
hr
4.66
hr
6.99
hr
9.33
hr
1.33 kHz
4.66
hr
9.33
hr
13.99
hr
18.65
hr

1 For 20 MHz capture bandwidth, when IQ bit resolution is set to 32 bits, the lower 8 bits are zeros. Therefore the maximum effective bit resolution is 24 bits for 20 MHz bandwidth.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Raw Socket Connection
import socket
from time import sleep, time
 
class SocketConnection:
"""Provides a means to connect and send SCPI commands to the DUT using a raw TCP socket."""
def __init__(self, ipAddress):
"""
Initializes an instance of SocketConnection class
@param ipAddress The IP address of the device
"""
 
# split out port number if given
splitIpAddress = ipAddress.split(':')
 
assert len(splitIpAddress) > 0
assert len(splitIpAddress) <= 2
self._ipAddress = splitIpAddress[0]
 
#assign port
if len(splitIpAddress) == 2:
self._portNumber = int(splitIpAddress[1])
else:
self._portNumber = 9001
 
self._socketConnection = None
 
self._timeoutInSec = 120
self._socketReadSize = 4096
self.__nonBulkDataSizeCuttoff = 32768
# Time to let the other end of the connection close
self.__timeoutAfterCloseInSec = 1
self._terminatedBlockResponse = False
self.prefix = ''
self._verbose = False
self._establishConnection()
 
def __del__(self):
"""
This gets called by the garbage collector so it is possible that the connection will
remain open for a while before this gets collected.
"""
self._closeConnection()
 
def getpeername(self):
return self._ipAddress, self._portNumber
 
def settimeout(self, *args, **kwargs):
return self._socketConnection.settimeout(*args, **kwargs)
 
def expectTerminatedBlockResponse(self, newval=None):
if newval is not None:
self._terminatedBlockResponse = newval
return self._terminatedBlockResponse
 
def sendWriteCommand(self, scpiCommand):
"""
Sends a SCPI write command.
@param scpiCommand The SCPI command to send.
"""
scpiCommand = self.prefix + scpiCommand
try:
returnValue = self._socketConnection.sendall(scpiCommand + "\n")
assert returnValue is None, "Error sending command: " + scpiCommand
if self._verbose:
if len(scpiCommand) < self.__nonBulkDataSizeCuttoff:
print(scpiCommand + " sent successfully")
else:
print( "sent long scpi command of length: " + str(len(scpiCommand)))
except socket.error as msg:
assert False, "Failed to send SCPI command: a socket error occurred (Error code: " + str(msg[0]) + ", Error message: " + str(msg[1]) + ")"
return
def sendQueryCommand(self, scpiCommand):
"""
Sends a SCPI query command and return the response.
@param scpiCommand The SCPI query to send.
@return The result of the SCPI command.
"""
scpiCommand = self.prefix + scpiCommand
try:
returnValue = self._socketConnection.sendall(scpiCommand + "\n")
assert returnValue is None, "failed to send command"
if self._verbose:
print(scpiCommand + " sent successfully")
 
# Read 1 byte to check for a block data response header
data = self._socketConnection.recv(1)
assert len(data) > 0, "No data returned for query"
if len(data) > 0 and data[0] == '#':
# Block data response
data = self._getBlockDataResponse()
elif len(data) > 0 and data[0] == '\n':
# Check for a response string that only contains a newline. Remove the newline and return empty data.
data = data[:-1]
elif len(data) > 0:
# ASCII response: receive until the entire response is read
while True:
data += self._socketConnection.recv(self._socketReadSize)
 
assert len(data) < self.__nonBulkDataSizeCuttoff, \
"No newline character found in response to " + scpiCommand + " SCPI command."
 
# Check for a new line at the end of the response
if data[-1] == '\n':
break;
 
# Remove the trailing \n from the response
data = data[:-1]
if self._verbose:
print('Data received: "%s"' % data)
except socket.error as msg:
assert False, "Failed to send SCPI command: a socket error occurred \n" + msg.__str__()
return data
 
def _establishConnection(self):
"""Establishes a connection. The call will fail if a connection is already open."""
assert self._socketConnection is None, "connection should not already be open"
try:
self._socketConnection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._socketConnection.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self._socketConnection.settimeout(self._timeoutInSec)
self._socketConnection.connect((self._ipAddress, self._portNumber))
self._socketConnection.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
except socket.error as msg:
assert False, "Failed to establish DUT connection (Error code: " + str(msg[0]) + ", Error message: " + str(msg[1]) + ")"
 
def _closeConnection(self):
"""
Closes the socket connection and asserts that it closed. This informs the other end of the
socket that it should close but it may take some time depending on implementation,
network conditions, etc.
"""
if self._socketConnection is not None:
self._socketConnection.shutdown(socket.SHUT_RDWR)
self._socketConnection.close()
self._socketConnection = None
sleep(self.__timeoutAfterCloseInSec)
assert self._socketConnection is None, "Socket connection not closed"
 
def _getBlockDataResponse(self):
"""
Receives a SCPI block data response of the form 'AXD' where A is a single ASCII byte
specifying the number of digits in X, X is one or more ASCII bytes specifying the number
of bytes in D, and D is one or more bytes containing the response binary data.
"""
numSizeBytes = int(self._socketConnection.recv(1))
 
assert numSizeBytes > 0, "The definite-length empty block response must be #10 not #0."
 
numDataBytesLeft = int(self._socketConnection.recv(numSizeBytes))
responses = []
readBuffer = bytearray(numDataBytesLeft)
view = memoryview(readBuffer)
timeoutSeconds = self._socketConnection.gettimeout()
lastReadTime = time()
 
while numDataBytesLeft > 0:
numBytesRead = self._socketConnection.recv_into(view, numDataBytesLeft)
if numBytesRead > 0:
lastReadTime = time()
 
dt = time() - lastReadTime
if dt > timeoutSeconds:
raise Exception('Timeout after %d ms: Only read %d/%d bytes'
% (dt, len(readBuffer),
len(readBuffer) + numDataBytesLeft))
 
view = view[numBytesRead:]
numDataBytesLeft = numDataBytesLeft - numBytesRead
 
if self._terminatedBlockResponse:
blockTerminator = self._socketConnection.recv(2)
assert blockTerminator in ('\r\n', '\n')
if self._verbose:
print("Read bytes of block data: ", len(readBuffer))
return readBuffer
 
def reset(self, delay_seconds=-1):
"""
Resets the established connection
@param delay_seconds: Wait time between closing the connection and attempting to
re-establish the connection. This is useful when rebooting an instrument.
"""
self._closeConnection()
 
if delay_seconds >= 0:
sleep(delay_seconds)
try:
self._establishConnection()
except socket.error as msg:
assert False, "Failed to establish DUT connection (Error code: " + str(msg[0]) + ", Error message: " + str(msg[1]) + ")"
else:
reset_timeout = 300 # 300 seconds == 5 minutes == max polling time
time.sleep(5) # Fixed delay before attempting to reconnect
while reset_timeout > 0:
try:
self._socketConnection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._socketConnection.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self._socketConnection.settimeout(self._timeoutInSec)
self._socketConnection.connect((self._ipAddress, self._portNumber))
break
except Exception as msg :
self._socketConnection.close()
self._socketConnection = None
sleep(1)
reset_timeout -= 1
if reset_timeout <= 0:
assert False, "Failed to establish DUT connection (Error code: " + str(msg[0]) + ", Error message: " + str(msg[1]) + ")"
 
 
I/Q Block Capture via SCPI
SENS:FREQ:CENTER 100 MHz
SENS:FREQ:SPAN 20 MHz
SWEEP:MODE FFT
//Set RBW 30 kHz
BANDWIDTH 30 KHz
//Set Reference Level to -30 dBm
DISP:WIND:TRAC:Y:SCAL:RLEV -30
//Set to single sweep
INIT:CONT OFF
//abort any sweep in progress
:ABORT
 
//Set Capture bandwidth. Not same as RBW.
IQ:BANDWIDTH 20 MHz
 
//Set 16 bit resolution
IQ:BITS 16
 
//Set to I/Q block capture mode
IQ:MODE SINGLE
//enable time stamp
SENS:IQ:TIME 1
 
//Set capture length to 5 msec
IQ:LENGTH 5 ms
 
//Start IQ Capture. Triggers single capture. Data is saved to DDR2 SDRAM memory.
MEAS:IQ:CAPT
 
//Check if capture is completed normally
STATus:OPERation?
 
//The STATus:OPERation? query responds with a integer. Convert this integer to binary.
//Bit 9 is set to 1 when the MEAS:IQ:CAPT command is issued.
//Bit 9 is set to 0 when the capture is completed normally in block mode.