Load Tek ISF File
hrodstein
I recommend that you download the attached file rather than copying this code because I had some formatting problems with the URLs in the comments.
#pragma rtGlobals=3 // Use modern global access method.
// File Loader for Tektronix ISF files
// A Tektronix ISF file is the contents of what a Tek oscilloscope sends in response
// to a WAVFrm? command. See https://www.tek.com/support/faqs/what-format-isf-file
//
// A Tek ISF file is not the same as a Tek WFM file. There exists a loader for Tek WFM files.
// See https://www.wavemetrics.com/project/LoadTekWaveform.
//
// It is recommended that you name your Tek ISF files with the ".isf" extension to make
// it clear what kind of file it is.
// The way to determine the header length is to look for the ":CURVE" keyword. It is formatted like this:
// ":CURVE <digit><number>" .e.g., ":CURVE 41000"
// where <digit> represents the number of digits is the following number and <number> represents the number of
// samples of binary data that follow. In this case, "4" is the number of digits in "1000" and 1000 is the number of samples.
static Constant kHeaderLength = 282 // Length of header in bytes. Empirically determined.
static Constant kWaveDataType = 2 // Single precision floating point
// LoadTekISFFile(pathName, fileName, createTable, createGraph)
//
// pathName is the name of an Igor symbolic path or "".
// fileName is one of the following:
// The name of a file in the folder designated by pathName.
// A partial path from the folder designated by pathName to the file to be loaded.
// A full path to the file to be loaded.
// "" to get an Open File dialog.
// Add an item to Igor's Load Waves submenu (Data menu)
Menu "Load Waves"
"Load Tek ISF File...", LoadTekISFFileMenuItem()
"Load All Tek ISF Files In Folder...", LoadAllTekISFFiles("", "", 0, 0)
End
Function/S StripDoubleQuotes(str)
String str // A string starting and ending with double quotes
if (CmpStr(str[0], "\"") != 0)
return str // String did not start with double quotes
endif
Variable len = strlen(str)
str = str[1,len-2]
return str
End
Structure TekISFHeaderInfo
Variable encoding // 0 = binary. -1 = unknown. Currently the only encoding I know about is binary. From ENCDG keyword.
Variable byteOrder // 0 = big-endian, 1 = little-endian. From BYT_OR keyword.
Variable dataType // See WaveType for possible values. From BIT_NR and BN_FMT keywords.
Variable numPoints // Number of points in waveform. From NR_PT keyword.
String xUnits // From XUNIT keyword.
Variable x0 // From XZERO keyword.
Variable dx // From XINCR keyword.
String yUnits // From YUNIT keyword.
Variable yOffset // From YOFF keyword.
Variable yZero // From YZERO keyword.
Variable yMultiplier // From YMULT keyword.
EndStructure
Function ExtractISFHeaderInfo(refNum, headerInfo, quiet)
Variable refNum // File reference number
STRUCT TekISFHeaderInfo &headerInfo
Variable quiet // 0 - print information about errors
Variable result = 0
Variable originalPos
FStatus refNum
originalPos = V_filePos
// Read header string
String headerStr = ""
Variable headerStrLength = kHeaderLength
FSetPos refNum, 0
headerStr = PadString(headerStr, kHeaderLength, 0x20)
FBinRead refNum, headerStr
FSetPos refNum, originalPos
// Parse header string
String str
str = StringByKey("ENCDG", headerStr, " ")
strswitch(str)
case "BIN":
headerInfo.encoding = 0
break
default:
headerInfo.encoding = -1 // Unknown encoding
result -= 1
break
endswitch
str = StringByKey("BYT_OR", headerStr, " ")
strswitch(str)
case "MSB":
headerInfo.byteOrder = 0
break
case "LSB":
headerInfo.byteOrder = 1
break
default:
headerInfo.byteOrder = -1 // Unknown byte order
result -= 1
break
endswitch
headerInfo.numPoints = NumberByKey("NR_PT", headerStr, " ")
headerInfo.xUnits = StripDoubleQuotes(StringByKey("XUNIT", headerStr, " "))
headerInfo.x0 = NumberByKey("XZERO", headerStr, " ")
headerInfo.dx = NumberByKey("XINCR", headerStr, " ")
headerInfo.yUnits = StripDoubleQuotes(StringByKey("YUNIT", headerStr, " "))
headerInfo.yOffset = NumberByKey("YOFF", headerStr, " ")
headerInfo.yZero = NumberByKey("YZERO", headerStr, " ")
headerInfo.yMultiplier = NumberByKey("YMULT", headerStr, " ")
Variable numBitsPerPoint = NumberByKey("BIT_NR", headerStr, " ")
String binaryFormat = StringByKey("BN_FMT", headerStr, " ")
strswitch(binaryFormat)
case "RI": // Presumably "real integer"
switch (numBitsPerPoint)
case 8:
headerInfo.dataType = 8 // 8 bit signed integer
break
case 16:
headerInfo.dataType = 16 // 16 bit signed integer
break
case 32:
headerInfo.dataType = 32 // 32 bit signed integer
break
default:
headerInfo.dataType = -1 // Unknown type
result -= 1
break
endswitch
break
default:
headerInfo.dataType = -1 // Don't understand datatype
result -= 1
break
endswitch
return result
End
// LoadTekISFFileDialog(createTable, createGraph)
// Displays a dialog in which the user can enter parameters.
// All of the parameters function both as inputs, to preset the dialog values,
// and as output, to return the values to the calling routine.
// The function result is 0 if OK or -1 if cancel.
Function LoadTekISFFileDialog(createTable, createGraph)
Variable &createTable // Input and output.
Variable &createGraph // Input and output.
if ( (createTable<1) || (createTable>2) )
createTable = 1
endif
if ( (createGraph<1) || (createGraph>2) )
createGraph = 1
endif
// This is necessary because you can't pass an & parameter to Prompt.
Variable createTable2 = createTable
Variable createGraph2 = createGraph
Prompt createTable2, "Create table", popup "Yes;No"
Prompt createGraph2, "Create graph", popup "Yes;No"
DoPrompt "Load Tek ISF File", createTable2, createGraph2
if (V_Flag != 0)
return -1 // User cancelled.
endif
createTable = createTable2
createGraph = createGraph2
return 0
End
Function LoadTekISFFile(pathName, fileName, createTable, createGraph, quiet, newWaveName)
String pathName // Igor symbolic path name or "" for dialog.
String fileName // file name, partial path and file name, or full path or "" for dialog.
Variable createTable // 1 = Yes, 2 = No, 0 for dialog.
Variable createGraph // 1 = Yes, 2 = No, 0 for dialog.
Variable quiet // 0 = print diagnostic and error messages, 1 = print error messages only, 2 = do not print diagnostic or error messages
String &newWaveName // Output: Name of wave created.
newWaveName = ""
Variable err
if ( (createTable==0) || (createGraph==0) )
err = LoadTekISFFileDialog(createTable, createGraph)
if (err != 0)
return err
endif
endif
// This puts up a dialog if the pathName and fileName do not specify a file.
String message = "Select a Tek ISF file"
Variable refNum
Open /R /Z=2 /P=$pathName /T="????" /M=message refNum as fileName // /T flag presents "All files" in Open File dialog.
// Save outputs from Open in a safe place.
err = V_Flag
String fullPath = S_fileName
if (err != 0)
return err // -1 means user canceled.
endif
// Load the header information
STRUCT TekISFHeaderInfo headerInfo
if (ExtractISFHeaderInfo(refNum, headerInfo, quiet!=2) != 0)
if (quiet != 2)
Print "Error while loading header section of the file."
endif
Close refNum
return -1
endif
Close refNum
switch (headerInfo.encoding)
case 0: // Binary
break
default:
if (quiet != 2)
Print "The file's encoding is unknown. Only binary encoding is supported."
endif
return -1
endswitch
if (quiet == 0)
Printf "Loading Tek ISF data from \"%s\"\r", fullPath
endif
GBLoadWave /B=(headerInfo.byteOrder) /A=tekWave /T={headerInfo.dataType,kWaveDataType} /S=(kHeaderLength) /W=1 /U=(headerInfo.numPoints) /Q fullPath
if (V_flag == 0)
if (quiet != 2)
Print "Error while loading binary data section of the file."
endif
return -1
endif
newWaveName = StringFromList(0, S_waveNames)
Wave w = $newWaveName
SetScale/P x, headerInfo.x0, headerInfo.dx, ""+headerInfo.xUnits, w
SetScale d, 0, 0, ""+headerInfo.yUnits, w
// I don't know what headerInfo.yZero is all about (YZERO keyword).
w = (w - headerInfo.yOffset) * headerInfo.yMultiplier
if (quiet == 0)
Printf "Created wave %s, %d points.\r", newWaveName, numpnts(w)
endif
if (createTable == 1)
Edit w.id
ModifyTable format[1]=3,digits[1]=9 // Display time in suitable format.
endif
if (createGraph == 1)
Display w
endif
return 0 // Zero signifies no error.
End
Function LoadTekISFFileMenuItem()
String newWaveName
LoadTekISFFile("", "", 1, 1, 0, newWaveName)
End
// LoadAllTekISFFilesDialog(extension, createTable, createGraph)
// Displays a dialog in which the user can enter parameters.
// All of the parameters function both as inputs, to preset the dialog values,
// and as output, to return the values to the calling routine.
// The function result is 0 if OK or -1 if cancel.
Function LoadAllTekISFFilesDialog(extension, createTable, createGraph)
String &extension // Input and output
Variable &createTable // Input and output.
Variable &createGraph // Input and output.
if (CmpStr(extension,".isf")!=0 && CmpStr(extension,"????")!=0)
extension = ".isf"
endif
if ( (createTable<1) || (createTable>2) )
createTable = 1
endif
if ( (createGraph<1) || (createGraph>2) )
createGraph = 1
endif
// This is necessary because you can't pass an & parameter to Prompt.
String extension2 = extension
Variable createTable2 = createTable
Variable createGraph2 = createGraph
Prompt extension2, "Tek ISF file name extension", popup ".isf;Any extension"
Prompt createTable2, "Create table", popup "Yes;No"
Prompt createGraph2, "Create graph", popup "Yes;No"
DoPrompt "Load All Tek ISF Files", extension2, createTable2, createGraph2
if (V_Flag != 0)
return -1 // User cancelled.
endif
if (CmpStr(extension2, "Any extension") == 0)
extension2 = "????"
endif
extension = extension2
createTable = createTable2
createGraph = createGraph2
return 0
End
Function LoadAllTekISFFiles(pathName, extension, createTable, createGraph)
String pathName // Name of an Igor symbolic folder created by Misc->NewPath
String extension // e.g., ".isf". Pass "????" for any extension. Pass "" for dialog.
Variable createTable // 1 = Yes, 2 = No, 0 for dialog.
Variable createGraph // 1 = Yes, 2 = No, 0 for dialog.
if (CmpStr(extension,"")==0 || createTable<1 || createTable>2 || createGraph<1 || createGraph>2)
if (LoadAllTekISFFilesDialog(extension, createTable, createGraph) != 0)
return -1 // User cancelled.
endif
endif
if (strlen(pathName) == 0)
String message
if (CmpStr(extension, "????") == 0)
message = "Select a directory containing Tek ISF files with any extension"
else
sprintf message, "Select a directory containing Tek ISF files with %s extension", extension
endif
NewPath/O/M=message TekISFDataPath // This displays a dialog in which you can select a folder
if (V_flag != 0)
return V_flag // -1 means user canceled
endif
pathName = "TekISFDataPath"
endif
Variable err = 0
String newWaveName
String fileName
Variable i = 0
do
fileName = IndexedFile($pathName, i, extension)
if (strlen(fileName) == 0)
break // No more files
endif
err = LoadTekISFFile(pathName, fileName, 2, 2, 1, newWaveName)
if (err != 0)
return err
endif
if (createTable == 1)
if (i == 0)
Edit $newWaveName
else
AppendToTable $newWaveName
endif
endif
if (createGraph == 1)
if (i == 0)
Display $newWaveName
else
AppendToGraph $newWaveName
endif
endif
i += 1
while(1)
return 0
End
// File Loader for Tektronix ISF files
// A Tektronix ISF file is the contents of what a Tek oscilloscope sends in response
// to a WAVFrm? command. See https://www.tek.com/support/faqs/what-format-isf-file
//
// A Tek ISF file is not the same as a Tek WFM file. There exists a loader for Tek WFM files.
// See https://www.wavemetrics.com/project/LoadTekWaveform.
//
// It is recommended that you name your Tek ISF files with the ".isf" extension to make
// it clear what kind of file it is.
// The way to determine the header length is to look for the ":CURVE" keyword. It is formatted like this:
// ":CURVE <digit><number>" .e.g., ":CURVE 41000"
// where <digit> represents the number of digits is the following number and <number> represents the number of
// samples of binary data that follow. In this case, "4" is the number of digits in "1000" and 1000 is the number of samples.
static Constant kHeaderLength = 282 // Length of header in bytes. Empirically determined.
static Constant kWaveDataType = 2 // Single precision floating point
// LoadTekISFFile(pathName, fileName, createTable, createGraph)
//
// pathName is the name of an Igor symbolic path or "".
// fileName is one of the following:
// The name of a file in the folder designated by pathName.
// A partial path from the folder designated by pathName to the file to be loaded.
// A full path to the file to be loaded.
// "" to get an Open File dialog.
// Add an item to Igor's Load Waves submenu (Data menu)
Menu "Load Waves"
"Load Tek ISF File...", LoadTekISFFileMenuItem()
"Load All Tek ISF Files In Folder...", LoadAllTekISFFiles("", "", 0, 0)
End
Function/S StripDoubleQuotes(str)
String str // A string starting and ending with double quotes
if (CmpStr(str[0], "\"") != 0)
return str // String did not start with double quotes
endif
Variable len = strlen(str)
str = str[1,len-2]
return str
End
Structure TekISFHeaderInfo
Variable encoding // 0 = binary. -1 = unknown. Currently the only encoding I know about is binary. From ENCDG keyword.
Variable byteOrder // 0 = big-endian, 1 = little-endian. From BYT_OR keyword.
Variable dataType // See WaveType for possible values. From BIT_NR and BN_FMT keywords.
Variable numPoints // Number of points in waveform. From NR_PT keyword.
String xUnits // From XUNIT keyword.
Variable x0 // From XZERO keyword.
Variable dx // From XINCR keyword.
String yUnits // From YUNIT keyword.
Variable yOffset // From YOFF keyword.
Variable yZero // From YZERO keyword.
Variable yMultiplier // From YMULT keyword.
EndStructure
Function ExtractISFHeaderInfo(refNum, headerInfo, quiet)
Variable refNum // File reference number
STRUCT TekISFHeaderInfo &headerInfo
Variable quiet // 0 - print information about errors
Variable result = 0
Variable originalPos
FStatus refNum
originalPos = V_filePos
// Read header string
String headerStr = ""
Variable headerStrLength = kHeaderLength
FSetPos refNum, 0
headerStr = PadString(headerStr, kHeaderLength, 0x20)
FBinRead refNum, headerStr
FSetPos refNum, originalPos
// Parse header string
String str
str = StringByKey("ENCDG", headerStr, " ")
strswitch(str)
case "BIN":
headerInfo.encoding = 0
break
default:
headerInfo.encoding = -1 // Unknown encoding
result -= 1
break
endswitch
str = StringByKey("BYT_OR", headerStr, " ")
strswitch(str)
case "MSB":
headerInfo.byteOrder = 0
break
case "LSB":
headerInfo.byteOrder = 1
break
default:
headerInfo.byteOrder = -1 // Unknown byte order
result -= 1
break
endswitch
headerInfo.numPoints = NumberByKey("NR_PT", headerStr, " ")
headerInfo.xUnits = StripDoubleQuotes(StringByKey("XUNIT", headerStr, " "))
headerInfo.x0 = NumberByKey("XZERO", headerStr, " ")
headerInfo.dx = NumberByKey("XINCR", headerStr, " ")
headerInfo.yUnits = StripDoubleQuotes(StringByKey("YUNIT", headerStr, " "))
headerInfo.yOffset = NumberByKey("YOFF", headerStr, " ")
headerInfo.yZero = NumberByKey("YZERO", headerStr, " ")
headerInfo.yMultiplier = NumberByKey("YMULT", headerStr, " ")
Variable numBitsPerPoint = NumberByKey("BIT_NR", headerStr, " ")
String binaryFormat = StringByKey("BN_FMT", headerStr, " ")
strswitch(binaryFormat)
case "RI": // Presumably "real integer"
switch (numBitsPerPoint)
case 8:
headerInfo.dataType = 8 // 8 bit signed integer
break
case 16:
headerInfo.dataType = 16 // 16 bit signed integer
break
case 32:
headerInfo.dataType = 32 // 32 bit signed integer
break
default:
headerInfo.dataType = -1 // Unknown type
result -= 1
break
endswitch
break
default:
headerInfo.dataType = -1 // Don't understand datatype
result -= 1
break
endswitch
return result
End
// LoadTekISFFileDialog(createTable, createGraph)
// Displays a dialog in which the user can enter parameters.
// All of the parameters function both as inputs, to preset the dialog values,
// and as output, to return the values to the calling routine.
// The function result is 0 if OK or -1 if cancel.
Function LoadTekISFFileDialog(createTable, createGraph)
Variable &createTable // Input and output.
Variable &createGraph // Input and output.
if ( (createTable<1) || (createTable>2) )
createTable = 1
endif
if ( (createGraph<1) || (createGraph>2) )
createGraph = 1
endif
// This is necessary because you can't pass an & parameter to Prompt.
Variable createTable2 = createTable
Variable createGraph2 = createGraph
Prompt createTable2, "Create table", popup "Yes;No"
Prompt createGraph2, "Create graph", popup "Yes;No"
DoPrompt "Load Tek ISF File", createTable2, createGraph2
if (V_Flag != 0)
return -1 // User cancelled.
endif
createTable = createTable2
createGraph = createGraph2
return 0
End
Function LoadTekISFFile(pathName, fileName, createTable, createGraph, quiet, newWaveName)
String pathName // Igor symbolic path name or "" for dialog.
String fileName // file name, partial path and file name, or full path or "" for dialog.
Variable createTable // 1 = Yes, 2 = No, 0 for dialog.
Variable createGraph // 1 = Yes, 2 = No, 0 for dialog.
Variable quiet // 0 = print diagnostic and error messages, 1 = print error messages only, 2 = do not print diagnostic or error messages
String &newWaveName // Output: Name of wave created.
newWaveName = ""
Variable err
if ( (createTable==0) || (createGraph==0) )
err = LoadTekISFFileDialog(createTable, createGraph)
if (err != 0)
return err
endif
endif
// This puts up a dialog if the pathName and fileName do not specify a file.
String message = "Select a Tek ISF file"
Variable refNum
Open /R /Z=2 /P=$pathName /T="????" /M=message refNum as fileName // /T flag presents "All files" in Open File dialog.
// Save outputs from Open in a safe place.
err = V_Flag
String fullPath = S_fileName
if (err != 0)
return err // -1 means user canceled.
endif
// Load the header information
STRUCT TekISFHeaderInfo headerInfo
if (ExtractISFHeaderInfo(refNum, headerInfo, quiet!=2) != 0)
if (quiet != 2)
Print "Error while loading header section of the file."
endif
Close refNum
return -1
endif
Close refNum
switch (headerInfo.encoding)
case 0: // Binary
break
default:
if (quiet != 2)
Print "The file's encoding is unknown. Only binary encoding is supported."
endif
return -1
endswitch
if (quiet == 0)
Printf "Loading Tek ISF data from \"%s\"\r", fullPath
endif
GBLoadWave /B=(headerInfo.byteOrder) /A=tekWave /T={headerInfo.dataType,kWaveDataType} /S=(kHeaderLength) /W=1 /U=(headerInfo.numPoints) /Q fullPath
if (V_flag == 0)
if (quiet != 2)
Print "Error while loading binary data section of the file."
endif
return -1
endif
newWaveName = StringFromList(0, S_waveNames)
Wave w = $newWaveName
SetScale/P x, headerInfo.x0, headerInfo.dx, ""+headerInfo.xUnits, w
SetScale d, 0, 0, ""+headerInfo.yUnits, w
// I don't know what headerInfo.yZero is all about (YZERO keyword).
w = (w - headerInfo.yOffset) * headerInfo.yMultiplier
if (quiet == 0)
Printf "Created wave %s, %d points.\r", newWaveName, numpnts(w)
endif
if (createTable == 1)
Edit w.id
ModifyTable format[1]=3,digits[1]=9 // Display time in suitable format.
endif
if (createGraph == 1)
Display w
endif
return 0 // Zero signifies no error.
End
Function LoadTekISFFileMenuItem()
String newWaveName
LoadTekISFFile("", "", 1, 1, 0, newWaveName)
End
// LoadAllTekISFFilesDialog(extension, createTable, createGraph)
// Displays a dialog in which the user can enter parameters.
// All of the parameters function both as inputs, to preset the dialog values,
// and as output, to return the values to the calling routine.
// The function result is 0 if OK or -1 if cancel.
Function LoadAllTekISFFilesDialog(extension, createTable, createGraph)
String &extension // Input and output
Variable &createTable // Input and output.
Variable &createGraph // Input and output.
if (CmpStr(extension,".isf")!=0 && CmpStr(extension,"????")!=0)
extension = ".isf"
endif
if ( (createTable<1) || (createTable>2) )
createTable = 1
endif
if ( (createGraph<1) || (createGraph>2) )
createGraph = 1
endif
// This is necessary because you can't pass an & parameter to Prompt.
String extension2 = extension
Variable createTable2 = createTable
Variable createGraph2 = createGraph
Prompt extension2, "Tek ISF file name extension", popup ".isf;Any extension"
Prompt createTable2, "Create table", popup "Yes;No"
Prompt createGraph2, "Create graph", popup "Yes;No"
DoPrompt "Load All Tek ISF Files", extension2, createTable2, createGraph2
if (V_Flag != 0)
return -1 // User cancelled.
endif
if (CmpStr(extension2, "Any extension") == 0)
extension2 = "????"
endif
extension = extension2
createTable = createTable2
createGraph = createGraph2
return 0
End
Function LoadAllTekISFFiles(pathName, extension, createTable, createGraph)
String pathName // Name of an Igor symbolic folder created by Misc->NewPath
String extension // e.g., ".isf". Pass "????" for any extension. Pass "" for dialog.
Variable createTable // 1 = Yes, 2 = No, 0 for dialog.
Variable createGraph // 1 = Yes, 2 = No, 0 for dialog.
if (CmpStr(extension,"")==0 || createTable<1 || createTable>2 || createGraph<1 || createGraph>2)
if (LoadAllTekISFFilesDialog(extension, createTable, createGraph) != 0)
return -1 // User cancelled.
endif
endif
if (strlen(pathName) == 0)
String message
if (CmpStr(extension, "????") == 0)
message = "Select a directory containing Tek ISF files with any extension"
else
sprintf message, "Select a directory containing Tek ISF files with %s extension", extension
endif
NewPath/O/M=message TekISFDataPath // This displays a dialog in which you can select a folder
if (V_flag != 0)
return V_flag // -1 means user canceled
endif
pathName = "TekISFDataPath"
endif
Variable err = 0
String newWaveName
String fileName
Variable i = 0
do
fileName = IndexedFile($pathName, i, extension)
if (strlen(fileName) == 0)
break // No more files
endif
err = LoadTekISFFile(pathName, fileName, 2, 2, 1, newWaveName)
if (err != 0)
return err
endif
if (createTable == 1)
if (i == 0)
Edit $newWaveName
else
AppendToTable $newWaveName
endif
endif
if (createGraph == 1)
if (i == 0)
Display $newWaveName
else
AppendToGraph $newWaveName
endif
endif
i += 1
while(1)
return 0
End
Forum
Support
Gallery
Igor Pro 9
Learn More
Igor XOP Toolkit
Learn More
Igor NIDAQ Tools MX
Learn More