Skip to content

Instantly share code, notes, and snippets.

@ZGainsforth
Last active March 13, 2024 09:23
Show Gist options
  • Select an option

  • Save ZGainsforth/7b05bf0b0409ae57ce7f to your computer and use it in GitHub Desktop.

Select an option

Save ZGainsforth/7b05bf0b0409ae57ce7f to your computer and use it in GitHub Desktop.
Read an SPA file from Omnic
# Created 2015, Zack Gainsforth
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import struct
from numpy.fft import fft, fftfreq
def LoadSPAInterferogram(FileName):
# Open the SPA file.
with open(FileName, 'rb') as f:
# Go to offset 294 in the header which tells us the number of sections in the file.
f.seek(294)
NumSections = struct.unpack('h', f.read(2))[0]
print('This spa file has ' + str(NumSections) + ' sections.')
# We will process each section in the spa file.
for n in range(NumSections):
# Go to the section start. Each section is 16 bytes, and starts after offset 304.
f.seek(304+16*n)
SectionType = struct.unpack('h', f.read(2))[0]
SectionOffset = struct.unpack('i', f.read(3)+b'\x00')[0]
SectionLength = struct.unpack('i', f.read(3)+b'\x00')[0]
print('Section #%d, Type: %d, Offset: %d, Length %d' % (n, SectionType, SectionOffset, SectionLength))
# If this is section type 3, then it contains the result spectrum (interferogram, single beam, etc.) Note where it is in the file.
if SectionType==3:
print('Found raw spectrum section.')
Section3Offset = SectionOffset
Section3Length = SectionLength
# If this is section type 102, then it contains a processed spectrum.
if SectionType==102:
print('Found processed spectrum section.')
Section102Offset = SectionOffset
Section102Length = SectionLength
# We will default to using section 102 (processed data) if it exists. Otherwise, we read section 3 (raw data).
if 'Section102Length' in locals():
print('Using processed spectrum.')
SectionOffset = Section102Offset
SectionLength = Section102Length
else:
print('Using raw spectrum.')
SectionOffset = Section3Offset
SectionLength = Section3Length
# Read in the data!
f.seek(SectionOffset)
DataText = f.read(SectionLength)
Data = np.fromstring(DataText, dtype='float32')[:-5]
return Data
def PlotInterferogram(Interferogram):
plt.figure()
plt.plot(Interferogram)
plt.title('Interferogram')
# Apply the hamming window to smooth out the FT (we don't want ripples.)
H = np.hamming(len(Interferogram))
I = H*Interferogram
plt.figure()
plt.plot(I)
plt.plot(H)
plt.title('Hamminged Interferogram')
# Compute the FFT
F = fft(I)
# Make the magnitude spectrum.
Mag = np.abs(F)
Mag = Mag[:int(len(Mag)/2)]
LaserFreq = 15798.3 # cm-1, this is the sampling distance for the interferogram.
#dE = 1/(2*LaserFreq)
E = fftfreq(len(Interferogram), 1/(2*LaserFreq))
E=E[:int(len(E)/2)]
plt.figure()
plt.plot(E, Mag)
plt.title('Magnitude spectrum')
# Make the phase spectrum.
Phase = np.unwrap(np.angle(F))
Phase = Phase[:int(len(Phase)/2)]
plt.figure()
plt.plot(E, Phase)
plt.title('Phase spectrum')
return
def GetMagAndPhaseFromInterferogram(Interferogram, SamplingLaserFreq=15798.3):
# Returns:
# Wavenumbers is the energy axis in cm-1
# Mag is the magnitude spectrum
# Phase is the phase spectrum.
# Apply the hamming window to smooth out the FT (we don't want ripples.)
H = np.hamming(len(Interferogram))
I = H*Interferogram
# Compute the FFT
F = fft(I)
# Make the magnitude spectrum.
Mag = np.abs(F)
Mag = Mag[:int(len(Mag)/2)]
LaserFreq = SamplingLaserFreq #15798.3 # cm-1, this is the sampling distance for the interferogram.
#dE = 1/(2*LaserFreq)
E = fftfreq(len(Interferogram), 1/(2*LaserFreq))
E=E[:int(len(E)/2)]
# Make the phase spectrum.
Phase = np.unwrap(np.angle(F))
Phase = Phase[:int(len(Phase)/2)]
return E, Mag, Phase
if __name__ == '__main__':
# FileName = 'Nuth_FeO_smoke_DriftSpot2_Au_0006.spa'
FileName = 'background/bkg_au_harmonic2.spa'
# FileName = 'section5/scan2/spec0040.spa'
Interferogram = LoadSPAInterferogram(FileName)
PlotInterferogram(Interferogram)
plt.show()
@tungcua66
Copy link
Copy Markdown

tungcua66 commented May 4, 2021

Hello,
I'm using your code to read the spa file and draw it. The problem is when i print the Interferogram, the output is not expected result(csv file).
You can test with files in this link
How can you know the spa format file ?

@ZGainsforth
Copy link
Copy Markdown
Author

ZGainsforth commented May 4, 2021 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment