Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 74 additions & 21 deletions orangecontrib/spectroscopy/widgets/owfft.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ class Outputs:
out_limit1 = settings.Setting(400)
out_limit2 = settings.Setting(4000)
autocommit = settings.Setting(False)
complexfft = settings.Setting(False)

sweep_opts = ("Single",
"Forward-Backward",
Expand Down Expand Up @@ -95,6 +96,7 @@ class Outputs:
class Warning(OWWidget.Warning):
# This is not actuully called anywhere at the moment
phase_res_limit_low = Msg("Phase resolution limit too low")
complex_data_phase_zero = Msg("Phase data is not connected, thus it is considered zero.")

class Error(OWWidget.Error):
fft_error = Msg("FFT error:\n{}")
Expand All @@ -109,7 +111,7 @@ def __init__(self):
self.reader = None
if self.dx_HeNe is True:
self.dx = 1.0 / self.laser_wavenumber / 2.0
self.use_polar_FFT = False
self.use_interleaved_data = False

layout = QGridLayout()
layout.setContentsMargins(0, 0, 0, 0)
Expand Down Expand Up @@ -204,6 +206,12 @@ def __init__(self):
self.optionsBox = gui.widgetBox(None, "FFT Options")
layout.addWidget(self.optionsBox, 0, 1, 3, 1)

self.complexfft_cb = gui.checkBox(
self.optionsBox, self, "complexfft",
label="Complex FFT",
callback=self.complex_fft_changed
)

box = gui.comboBox(
self.optionsBox, self, "apod_func",
label="Apodization function:",
Expand Down Expand Up @@ -289,13 +297,18 @@ def set_data(self, dataset):
"""
Receive input data.
"""
self.Warning.clear()
self.Error.clear()

if dataset is not None:
self.data = dataset
self.determine_sweeps()
self.infoa.setText('%d %s interferogram(s)' %
(dataset.X.shape[0],
(["Single"] + 3*["Forward-Backward"])[self.sweeps]))
self.infob.setText('%d points each' % dataset.X.shape[1])
self.use_interleaved_data = False
self.complexfft_cb.setDisabled(False)
self.check_metadata()
self.dataBox.setDisabled(False)
self.optionsBox.setDisabled(False)
Expand Down Expand Up @@ -350,11 +363,15 @@ def peak_search_changed(self):
self.controls.zpd2.setDisabled(self.peak_search_enable or self.sweeps == 0)
self.commit.deferred()

def complex_fft_changed(self):
self.configui_for_complex_fft()
self.commit.deferred()

@gui.deferred
def commit(self):
if self.data is not None:
if self.use_polar_FFT:
self.calculate_polar_FFT()
if self.complexfft:
self.calculate_complex_FFT()
else:
self.calculateFFT()

Expand Down Expand Up @@ -496,21 +513,30 @@ def calculateFFT(self):
self.Outputs.spectra.send(self.spectra_table)
self.Outputs.phases.send(self.phases_table)

def calculate_polar_FFT(self):
# polar channel data comes in alternating channel pairs
# of amplitude and phase data for the same channel for each run
amplitude_in = self.data.X[::2]
phases_in = self.data.X[1::2]
ifg_data = amplitude_in * np.exp(phases_in * 1j)

wavenumbers = None
spectra = []
phases = []
def calculate_complex_FFT(self):

# Reset info, error and warning dialogs
self.Error.clear()
self.Warning.clear()

if self.use_interleaved_data:
amplitude_in = self.data.X[::2]
phases_in = self.data.X[1::2]
else:
amplitude_in = self.data.X
phases_in = self.stored_phase.X if self.stored_phase is not None else None

if phases_in is None:
phases_in = 0
self.Warning.complex_data_phase_zero()

ifg_data = amplitude_in * np.exp(phases_in * 1j)

wavenumbers = None
spectra = []
phases = []

fft_single = irfft.ComplexFFT(
dx=self.dx,
apod_func=self.apod_func,
Expand All @@ -535,12 +561,21 @@ def calculate_polar_FFT(self):
[ContinuousVariable.make(f"{w}") for w in wavenumbers],
metas=self.data.domain.metas,
)
self.spectra_table = Table.from_numpy(
wavenumbers_domain, X=spectra, metas=self.data.metas[::2]
)
phases_table = Table.from_numpy(
wavenumbers_domain, X=phases, metas=self.data.metas[1::2]
)

if self.use_interleaved_data:
self.spectra_table = Table.from_numpy(
wavenumbers_domain, X=spectra, metas=self.data.metas[::2]
)
phases_table = Table.from_numpy(
wavenumbers_domain, X=phases, metas=self.data.metas[1::2]
)
else:
self.spectra_table = Table.from_numpy(
wavenumbers_domain, X=spectra, metas=self.data.metas
)
phases_table = Table.from_numpy(
wavenumbers_domain, X=phases, metas=self.data.metas
)

self.Outputs.spectra.send(self.spectra_table)
self.Outputs.phases.send(phases_table)
Expand Down Expand Up @@ -594,7 +629,9 @@ def check_metadata(self):
try:
channel_data, detail = self.data.attributes["Channel Data Type"]
if channel_data == "Polar":
self.use_polar_FFT = True
self.use_interleaved_data = True
self.complexfft = True
self.controls.complexfft.setDisabled(True)
self.infoc.setText(
f"Channel data type: {channel_data} ({detail}).\n"
+ "Applying Complex Fourier Transform."
Expand All @@ -605,7 +642,7 @@ def check_metadata(self):
domain_units, dx = self.data.attributes["Calculated Datapoint Spacing (Δx)"]
if domain_units != "[cm]" or not dx:
raise KeyError

self.dx = dx
self.zff = 2
self.dx_HeNe = False
Expand Down Expand Up @@ -654,7 +691,7 @@ def check_metadata(self):

self.dx = (1 / lwn / 2 ) * udr
self.infoc.setText("{0} cm<sup>-1</sup> laser, {1} sampling interval".format(lwn, udr))

def limit_range(self, wavenumbers, spectra):

limits = np.searchsorted(wavenumbers,
Expand All @@ -668,6 +705,22 @@ def limit_range(self, wavenumbers, spectra):

return wavenumbers, spectra

def configui_for_complex_fft(self):
"""
Configure the GUI for polar FFT with phase from strored_phase input
"""
if self.complexfft:
self.dx_HeNe = False
self.dx_edit.setDisabled(False)
self.dx_HeNe_cb.setChecked(False)
self.controls.phase_corr.setDisabled(True)
self.controls.phase_res_limit.setDisabled(True)
self.controls.phase_resolution.setDisabled(True)
else:
self.controls.phase_corr.setDisabled(False)
self.controls.phase_res_limit.setDisabled(False)
self.controls.phase_resolution.setDisabled(False)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This results in some strange GUI behaviour where things get disabled but not enabled when use_polar_FFT = True



def load_test_gsf() -> Orange.data.Table:
"""Load a NeaSpec interferogram GSF file and return a Table object."""
Expand Down
Loading