Skip to content

Commit

Permalink
Added basic tests, corrected algorithms wrt papers, typos in docstrings
Browse files Browse the repository at this point in the history
  • Loading branch information
pupperemeritus committed Aug 3, 2023
1 parent ac89b57 commit 59b2aa5
Show file tree
Hide file tree
Showing 4 changed files with 282 additions and 117 deletions.
2 changes: 1 addition & 1 deletion docs/changes/737.feature.rst
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
- Implemented the Lomb Scargle Fourier Transform
- Implemented the Lomb Scargle Fourier Transform (fast and slow versions)
- Using which wrote the corresponding :class:`LombScargleCrossspectrum` and :class:`LombScarglePowerspectrum`
138 changes: 64 additions & 74 deletions stingray/fourier.py
Original file line number Diff line number Diff line change
Expand Up @@ -1967,64 +1967,69 @@ def lsft_fast(
raise ValueError("sign must be 1 or -1")

Check warning on line 1967 in stingray/fourier.py

View check run for this annotation

Codecov / codecov/patch

stingray/fourier.py#L1967

Added line #L1967 was not covered by tests

# Constants initialization
const1 = np.sqrt(0.5)
const2 = const1 * sign

sum_xx = np.sum(y)

num_xt = len(y)
num_ww = len(freqs)
const1 = np.sqrt(0.5) * np.sqrt(num_ww)
const2 = const1

# Arrays initialization
ft_real = ft_imag = np.zeros((num_ww))
ft_res = np.zeros((num_ww), dtype=np.complex128)
f0, df, N = freqs[0], freqs[1] - freqs[0], len(freqs)

# Sum (y_i * cos(wt - wtau))
sumr, sumi = trig_sum(t, y, df, N, f0, oversampling=oversampling)
Sh, Ch = trig_sum(t, y, df, N, f0, oversampling=oversampling)

# Summation of (cos(wt - wtau))^2 and (sin(wt - wtau))^2
s2cos, c2cos = trig_sum(
t, np.ones_like(y) / len(y), df, N, f0, freq_factor=2, oversampling=oversampling
_, scos2x = trig_sum(
t,
np.ones_like(y) / len(y),
df,
N,
f0,
freq_factor=2,
oversampling=oversampling,
)
# cos^2(x) = (1 + cos(2x))/2
# sin^2(x) = (1 - cos(2x))/2
scos2, ssin2 = np.abs(1 + c2cos) / 2, np.abs(1 - s2cos) / 2
C2, S2 = (1 + scos2x) / 2, (1 - scos2x) / 2
# Angular Frequency
w = freqs * 2 * np.pi

freqs_new = f0 + df * np.arange(N)
# Summation of cos(2wt) and sin(2wt)
csum, ssum = trig_sum(
t, np.ones_like(y) / len(y), df, N, f0, freq_factor=2, oversampling=oversampling
)

fft_freqs = np.fft.ifft(freqs_new, N)
wtau = 0.5 * np.arctan2(ssum, csum)

# Summation of cos(2wt) and sin(2wt)
csum, ssum = fft_freqs.real, fft_freqs.imag
coswtau = np.cos(wtau)
sinwtau = np.sin(wtau)

# Looping through all the frequencies
for i in range(num_ww):
if i == 0:
ft_real = sum_xx / np.sqrt(num_xt)
ft_imag = 0
phase_this = 0
else:
# Angular Frequency
wrun = freqs[i] * 2 * np.pi
sumr = Ch * coswtau + Sh * sinwtau
sumi = Sh * coswtau - Ch * sinwtau

# arctan(ssum / csum)
watan = np.arctan2(ssum[i], csum[i])
wtau = 0.5 * watan
cos2wtau = np.cos(2 * wtau)
sin2wtau = np.sin(2 * wtau)

# Calculating the real and imaginary components of the Fourier transform
ft_real = const1 * (sumr[i] / np.sqrt(scos2[i]))
ft_imag = const2 * (sumi[i] / np.sqrt(ssin2[i]))
scos2 = 0.5 * (N + C2 * cos2wtau + S2 * sin2wtau)
ssin2 = 0.5 * (N - C2 * cos2wtau - S2 * sin2wtau)

# Phase of current angular frequency
phase_this = wtau - wrun * t[0]
# Resultant fourier transform for current angular frequency
ft_res[i] = np.multiply(np.complex128(complex(ft_real, ft_imag)), np.exp(1j * phase_this))
# Calculating the real and imaginary components of the Fourier transform
ft_real = const1 * sumr / np.sqrt(scos2)
ft_imag = const2 * sumi / np.sqrt(ssin2)

if fullspec:
return ft_res
else:
return ft_res[freqs > 0]
# Looping through all the frequencies
ft_real[0] = sum_xx / np.sqrt(num_xt)
ft_imag[0] = 0

# Resultant fourier transform for current angular frequency
ft_res = np.complex128(ft_real + (1j * ft_imag)) * np.exp(-1j * w * t[0])

if sign == -1:
ft_res = np.conjugate(ft_res)

return ft_res if fullspec else ft_res[freqs > 0]


def lsft_slow(
Expand Down Expand Up @@ -2059,58 +2064,43 @@ def lsft_slow(
ft_res : numpy.ndarray
An array of Fourier transformed data.
"""
if sign not in [1, -1]:
if sign not in (1, -1):
raise ValueError("sign must be 1 or -1")

Check warning on line 2068 in stingray/fourier.py

View check run for this annotation

Codecov / codecov/patch

stingray/fourier.py#L2067-L2068

Added lines #L2067 - L2068 were not covered by tests

# Constants initialization
const1 = np.sqrt(0.5)
const2 = const1 * sign

sum_xx = np.sum(y)

num_xt = len(y)
num_ww = len(freqs)
const1 = np.sqrt(0.5) * np.sqrt(len(y))
const2 = const1

Check warning on line 2072 in stingray/fourier.py

View check run for this annotation

Codecov / codecov/patch

stingray/fourier.py#L2071-L2072

Added lines #L2071 - L2072 were not covered by tests

# Arrays initialization
ft_real = ft_imag = np.zeros((num_ww))
ft_res = np.zeros((num_ww), dtype=np.complex128)
ft_real = np.zeros_like(freqs)
ft_imag = np.zeros_like(freqs)
ft_res = np.zeros_like(freqs, dtype=np.complex128)

Check warning on line 2076 in stingray/fourier.py

View check run for this annotation

Codecov / codecov/patch

stingray/fourier.py#L2074-L2076

Added lines #L2074 - L2076 were not covered by tests

# Looping through all the frequencies
for i in range(num_ww):
for i, freq in enumerate(freqs):
wrun = freq * 2 * np.pi
if i == 0:
ft_real = sum_xx / np.sqrt(num_xt)
ft_imag = 0
phase_this = 0
ft_real[i] = sum(y) / np.sqrt(len(y))
ft_imag[i] = 0

Check warning on line 2082 in stingray/fourier.py

View check run for this annotation

Codecov / codecov/patch

stingray/fourier.py#L2078-L2082

Added lines #L2078 - L2082 were not covered by tests
else:
# Angular Frequency
wrun = freqs[i] * 2 * np.pi

# Summation of cos(2wt) and sin(2wt)
csum = np.sum(np.cos(2.0 * wrun * t))
ssum = np.sum(np.sin(2.0 * wrun * t))

Check warning on line 2085 in stingray/fourier.py

View check run for this annotation

Codecov / codecov/patch

stingray/fourier.py#L2084-L2085

Added lines #L2084 - L2085 were not covered by tests

# arctan(ssum / csum)
watan = np.arctan2(ssum, csum)
wtau = 0.5 * watan

Check warning on line 2088 in stingray/fourier.py

View check run for this annotation

Codecov / codecov/patch

stingray/fourier.py#L2087-L2088

Added lines #L2087 - L2088 were not covered by tests

# Sum (y_i * cos(wt - wtau))
sumr = np.sum(np.multiply(y, np.cos(wrun * t - wtau)))
sumi = np.sum(np.multiply(y, np.sin(wrun * t - wtau)))
cos_wt_wtau = np.cos(wrun * t - wtau)
sin_wt_wtau = np.sin(wrun * t - wtau)

Check warning on line 2091 in stingray/fourier.py

View check run for this annotation

Codecov / codecov/patch

stingray/fourier.py#L2090-L2091

Added lines #L2090 - L2091 were not covered by tests

# Summation of (cos(wt - wtau))^2 and (sin(wt - wtau))^2
scos2 = np.sum((np.power(np.cos(wrun * t - wtau), 2)))
ssin2 = np.sum((np.power(np.sin(wrun * t - wtau), 2)))
sumr = np.sum(y * cos_wt_wtau)
sumi = np.sum(y * sin_wt_wtau)

Check warning on line 2094 in stingray/fourier.py

View check run for this annotation

Codecov / codecov/patch

stingray/fourier.py#L2093-L2094

Added lines #L2093 - L2094 were not covered by tests

# Calculating the real and imaginary components of the Fourier transform
ft_real = np.multiply(const1, np.divide(sumr, np.sqrt(scos2)))
ft_imag = np.multiply(const2, np.divide(sumi, np.sqrt(ssin2)))
scos2 = np.sum(np.power(cos_wt_wtau, 2))
ssin2 = np.sum(np.power(sin_wt_wtau, 2))

Check warning on line 2097 in stingray/fourier.py

View check run for this annotation

Codecov / codecov/patch

stingray/fourier.py#L2096-L2097

Added lines #L2096 - L2097 were not covered by tests

# Phase of current angular frequency
phase_this = wtau - wrun * t[0]
# Resultant fourier transform for current angular frequency
ft_res[i] = np.multiply(np.complex128(complex(ft_real, ft_imag)), np.exp(1j * phase_this))
ft_real[i] = const1 * sumr / np.sqrt(scos2)
ft_imag[i] = const2 * sumi / np.sqrt(ssin2)

Check warning on line 2100 in stingray/fourier.py

View check run for this annotation

Codecov / codecov/patch

stingray/fourier.py#L2099-L2100

Added lines #L2099 - L2100 were not covered by tests

if fullspec:
return ft_res
else:
return ft_res[freqs > 0]
ft_res[i] = np.complex128(ft_real[i] + (1j * ft_imag[i])) * np.exp(-1j * wrun * t[0])
if sign == -1:
ft_res = np.conjugate(ft_res)

Check warning on line 2104 in stingray/fourier.py

View check run for this annotation

Codecov / codecov/patch

stingray/fourier.py#L2102-L2104

Added lines #L2102 - L2104 were not covered by tests

return ft_res if fullspec else ft_res[freqs > 0]

Check warning on line 2106 in stingray/fourier.py

View check run for this annotation

Codecov / codecov/patch

stingray/fourier.py#L2106

Added line #L2106 was not covered by tests
Loading

0 comments on commit 59b2aa5

Please sign in to comment.