Readout a Fluke oscilloscope via GPIB


#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

Forum

Support

Gallery

Igor Pro 10

Learn More

Igor XOP Toolkit

Learn More

Igor NIDAQ Tools MX

Learn More