Readout a Fluke oscilloscope via GPIB
thomas_braun
#pragma TextEncoding = "Windows-1252"
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
/// Acquire spectra from an oscilloscope
/// Tested with a Fluke PM3394B using a PCI GPIB card on Windows 7 and Igor Pro 7 beta
/// The oscilloscope understands SCPI, I've included some commands to add proper units
/// to the acquired data.
///
/// Steps:
/// - Connect oscilloscope
/// - Adapt board and device in Initialize()
/// - Call Initialize(), maybe even twice
/// - Call AcquireData()
/// - Voila!
Function/WAVE StringToBufferWave(str)
string str
Make/B/FREE/N=(strlen(str)) buf = char2num(str[p])
return buf
End
Function/S BufferWavetoString(buf)
Wave buf
string str = ""
str = PadString(str, DimSize(buf, 0), 0x0)
variable i
for(i = 0; i < DimSize(buf, 0); i+= 1)
str[i] = num2char(buf[i])
endfor
return str
End
Function Send(str)
string str
NVAR gBoardID, gDeviceAddress
Variable DABend = 0x02
NI4882 Send={gBoardID,gDeviceAddress,StringToBufferWave(str),strlen(str),DABend}
printf "V_iberr=%d\r", V_iberr
End
Function/WAVE Receive()
NVAR gBoardID, gDeviceAddress
Variable STOPend = 0x100 // Means stop receiving when END is asserted.
Make/B/U/FREE bufferWave
NI4882 Receive={gBoardID,gDeviceAddress,bufferWave,100000,STOPend} // Read 1000 bytes or until END is asserted.
printf "V_iberr=%d\r", V_iberr
return bufferWave
End
Function Initialize()
Variable/G gBoardID, gDeviceAddress, gDeviceDesc
gBoardID = 0
gDeviceAddress = 3
NI4882 ibfind={"gpib0"}
NI4882 ibcac={V_Flag, 1}
NI4882 ibdev={gBoardID,gDeviceAddress,0,13,1,0}
gDeviceDesc = V_Flag
End
Function AcquireData()
variable ptPeak, voltOffset, sweepTime, tracePoints
string str
NVAR gBoardID, gDeviceAddress, gDeviceDesc
// Send("*RST")
Send("FORMat INTeger,16")
Send("TRACe:POINts CH1,8192")
/// Only the following trace acquisition lengths can be programmed:
/// 512, 2024 (2K), 4096 (4K), 8192 (8K), 16384 (16K), or 32768 (32K)
Send("TRIGger:SOURce INTernal1")
Send("TRIGger:LEVel 0.1")
Send("INITiate")
Send("*WAI;TRACe? CH1")
WAVE bufferWave = Receive()
Duplicate/O bufferWave, root:bufferWave
WAVE bufferWave
ptPeak = QueryNumericalValue("SENSe:VOLTage:RANGe:PTPeak?")
voltOffset = QueryNumericalValue("SENSe:VOLTage:RANGe:OFFSet?")
sweepTime = QueryNumericalValue("SENSe:SWEep:TIME?")
tracePoints = QueryNumericalValue("TRACe:POINts? CH1")
printf "ptPeak=%g, voltOffset=%g, sweepTime=%g, tracePoints=%g\r", ptPeak, voltOffset, sweepTime, tracePoints
WAVE bufferWaveConv = ConvertFromOsziFormat(bufferWave, ptPeak, voltOffset, sweepTime, tracePoints)
Duplicate/O bufferWaveConv, root:result
End
Function QueryNumericalValue(cmd)
string cmd
string str
Send(cmd)
WAVE bufferWave = Receive()
str = BufferWavetoString(bufferWave)
return str2num(str)
End
Function ASSERT(var, str)
variable var
string str
try
AbortOnValue !var, 0; AbortOnRTE
catch
printf "Assertion failed: %s\r", str
Debugger
Abort
endtry
End
Function/WAVE ConvertFromOsziFormat(wv, ptPeak, voltageOffset, sweepTime, tracePoints)
WAVE wv
variable ptPeak, voltageOffset, sweepTime, tracePoints
variable numDigitsSize, checksum, numTraceBytes, intWidth, numRows, i, traceByteOffset
numRows = DimSize(wv, 0)
ASSERT(numRows > 20, "Malformed data: Wave is too small")
ASSERT(wv[0] == char2num("#"), "Malformed data: Expected # as first char")
ASSERT(wv[numRows - 1] == char2num("\n"), "Malformed data: Expected \\n as last char")
numDigitsSize = str2num(num2char(wv[1]))
numTraceBytes = ExtractLength(wv, numDigitsSize)
traceByteOffset = numDigitsSize + 3
ASSERT(numRows == traceByteOffset + numTraceBytes, "Malformed data: Unexpected length")
intWidth = wv[numDigitsSize + 2]
ASSERT(tracePoints == (numTraceBytes - 2) / (intWidth / 8), "Malformed data: Length does not match requested length")
printf "numDigitsSize=%g, numTraceBytes=%g, intWidth=%g\r", numDigitsSize, numTraceBytes, intWidth
Make/D/FREE/N=(tracePoints) data
for(i = traceByteOffset;i < traceByteOffset + numTraceBytes - 2; i += 1)
checksum = mod(checksum + wv[i], 256)
endfor
ASSERT(checksum == mod(wv[numRows - 2] + 256, 256), "Malformed data: Checksum mismatch")
switch(intWidth)
case 8:
MultiThread data = ConvertTraceByteToVoltage8Bit(wv[traceByteOffset + p], ptPeak, voltageOffset)
break
case 16:
MultiThread data[0, tracePoints - 1] = ConvertTraceByteToVoltage16Bit(wv[traceByteOffset + p * 2],wv[traceByteOffset + p * 2 + 1], ptPeak, voltageOffset)
break
default:
ASSERT(0, "Unexpected intWidth")
break
endswitch
SetScale/P x, 0, sweepTime / (tracePoints - 1), "s", data
SetScale d, 0, 0, "V", data
return data
End
threadsafe Function ConvertTraceByteToVoltage8Bit(byte, ptPeak, voltageOffset)
variable byte, ptPeak, voltageOffset
variable value
value = byte > 127 ? byte - 256 : byte
return (value / 200) * ptPeak - voltageOffset
End
threadsafe Function ConvertTraceByteToVoltage16Bit(msbByte, lsbByte, ptPeak, voltageOffset)
variable msbByte, lsbByte, ptPeak, voltageOffset
variable value
value = msbByte > 127 ? (msbByte - 256) * 256 + lsbByte : msbByte * 256 + lsbByte
return (value / 51200) * ptPeak - voltageOffset
End
Function ExtractLength(wv, numDigitsSize)
WAVE wv
variable numDigitsSize
variable i, length
for(i = 0; i < numDigitsSize; i += 1)
length += str2num(num2char(wv[2 + i])) * 10^(numDigitsSize - (1 + i))
endfor
return length
End
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
/// Acquire spectra from an oscilloscope
/// Tested with a Fluke PM3394B using a PCI GPIB card on Windows 7 and Igor Pro 7 beta
/// The oscilloscope understands SCPI, I've included some commands to add proper units
/// to the acquired data.
///
/// Steps:
/// - Connect oscilloscope
/// - Adapt board and device in Initialize()
/// - Call Initialize(), maybe even twice
/// - Call AcquireData()
/// - Voila!
Function/WAVE StringToBufferWave(str)
string str
Make/B/FREE/N=(strlen(str)) buf = char2num(str[p])
return buf
End
Function/S BufferWavetoString(buf)
Wave buf
string str = ""
str = PadString(str, DimSize(buf, 0), 0x0)
variable i
for(i = 0; i < DimSize(buf, 0); i+= 1)
str[i] = num2char(buf[i])
endfor
return str
End
Function Send(str)
string str
NVAR gBoardID, gDeviceAddress
Variable DABend = 0x02
NI4882 Send={gBoardID,gDeviceAddress,StringToBufferWave(str),strlen(str),DABend}
printf "V_iberr=%d\r", V_iberr
End
Function/WAVE Receive()
NVAR gBoardID, gDeviceAddress
Variable STOPend = 0x100 // Means stop receiving when END is asserted.
Make/B/U/FREE bufferWave
NI4882 Receive={gBoardID,gDeviceAddress,bufferWave,100000,STOPend} // Read 1000 bytes or until END is asserted.
printf "V_iberr=%d\r", V_iberr
return bufferWave
End
Function Initialize()
Variable/G gBoardID, gDeviceAddress, gDeviceDesc
gBoardID = 0
gDeviceAddress = 3
NI4882 ibfind={"gpib0"}
NI4882 ibcac={V_Flag, 1}
NI4882 ibdev={gBoardID,gDeviceAddress,0,13,1,0}
gDeviceDesc = V_Flag
End
Function AcquireData()
variable ptPeak, voltOffset, sweepTime, tracePoints
string str
NVAR gBoardID, gDeviceAddress, gDeviceDesc
// Send("*RST")
Send("FORMat INTeger,16")
Send("TRACe:POINts CH1,8192")
/// Only the following trace acquisition lengths can be programmed:
/// 512, 2024 (2K), 4096 (4K), 8192 (8K), 16384 (16K), or 32768 (32K)
Send("TRIGger:SOURce INTernal1")
Send("TRIGger:LEVel 0.1")
Send("INITiate")
Send("*WAI;TRACe? CH1")
WAVE bufferWave = Receive()
Duplicate/O bufferWave, root:bufferWave
WAVE bufferWave
ptPeak = QueryNumericalValue("SENSe:VOLTage:RANGe:PTPeak?")
voltOffset = QueryNumericalValue("SENSe:VOLTage:RANGe:OFFSet?")
sweepTime = QueryNumericalValue("SENSe:SWEep:TIME?")
tracePoints = QueryNumericalValue("TRACe:POINts? CH1")
printf "ptPeak=%g, voltOffset=%g, sweepTime=%g, tracePoints=%g\r", ptPeak, voltOffset, sweepTime, tracePoints
WAVE bufferWaveConv = ConvertFromOsziFormat(bufferWave, ptPeak, voltOffset, sweepTime, tracePoints)
Duplicate/O bufferWaveConv, root:result
End
Function QueryNumericalValue(cmd)
string cmd
string str
Send(cmd)
WAVE bufferWave = Receive()
str = BufferWavetoString(bufferWave)
return str2num(str)
End
Function ASSERT(var, str)
variable var
string str
try
AbortOnValue !var, 0; AbortOnRTE
catch
printf "Assertion failed: %s\r", str
Debugger
Abort
endtry
End
Function/WAVE ConvertFromOsziFormat(wv, ptPeak, voltageOffset, sweepTime, tracePoints)
WAVE wv
variable ptPeak, voltageOffset, sweepTime, tracePoints
variable numDigitsSize, checksum, numTraceBytes, intWidth, numRows, i, traceByteOffset
numRows = DimSize(wv, 0)
ASSERT(numRows > 20, "Malformed data: Wave is too small")
ASSERT(wv[0] == char2num("#"), "Malformed data: Expected # as first char")
ASSERT(wv[numRows - 1] == char2num("\n"), "Malformed data: Expected \\n as last char")
numDigitsSize = str2num(num2char(wv[1]))
numTraceBytes = ExtractLength(wv, numDigitsSize)
traceByteOffset = numDigitsSize + 3
ASSERT(numRows == traceByteOffset + numTraceBytes, "Malformed data: Unexpected length")
intWidth = wv[numDigitsSize + 2]
ASSERT(tracePoints == (numTraceBytes - 2) / (intWidth / 8), "Malformed data: Length does not match requested length")
printf "numDigitsSize=%g, numTraceBytes=%g, intWidth=%g\r", numDigitsSize, numTraceBytes, intWidth
Make/D/FREE/N=(tracePoints) data
for(i = traceByteOffset;i < traceByteOffset + numTraceBytes - 2; i += 1)
checksum = mod(checksum + wv[i], 256)
endfor
ASSERT(checksum == mod(wv[numRows - 2] + 256, 256), "Malformed data: Checksum mismatch")
switch(intWidth)
case 8:
MultiThread data = ConvertTraceByteToVoltage8Bit(wv[traceByteOffset + p], ptPeak, voltageOffset)
break
case 16:
MultiThread data[0, tracePoints - 1] = ConvertTraceByteToVoltage16Bit(wv[traceByteOffset + p * 2],wv[traceByteOffset + p * 2 + 1], ptPeak, voltageOffset)
break
default:
ASSERT(0, "Unexpected intWidth")
break
endswitch
SetScale/P x, 0, sweepTime / (tracePoints - 1), "s", data
SetScale d, 0, 0, "V", data
return data
End
threadsafe Function ConvertTraceByteToVoltage8Bit(byte, ptPeak, voltageOffset)
variable byte, ptPeak, voltageOffset
variable value
value = byte > 127 ? byte - 256 : byte
return (value / 200) * ptPeak - voltageOffset
End
threadsafe Function ConvertTraceByteToVoltage16Bit(msbByte, lsbByte, ptPeak, voltageOffset)
variable msbByte, lsbByte, ptPeak, voltageOffset
variable value
value = msbByte > 127 ? (msbByte - 256) * 256 + lsbByte : msbByte * 256 + lsbByte
return (value / 51200) * ptPeak - voltageOffset
End
Function ExtractLength(wv, numDigitsSize)
WAVE wv
variable numDigitsSize
variable i, length
for(i = 0; i < numDigitsSize; i += 1)
length += str2num(num2char(wv[2 + i])) * 10^(numDigitsSize - (1 + i))
endfor
return length
End
Forum
Support
Gallery
Igor Pro 9
Learn More
Igor XOP Toolkit
Learn More
Igor NIDAQ Tools MX
Learn More