Skip to main content

N Dimensional Lomb Scargle Periodogram

Description

The Lomb-Scargle Periodogram (LSP) is a very useful numerical tool for spectral analysis. However, it is only supported in one dimension in scipy at the time of this writing. This code provides a multivariate extension to the Lomb-Scargle periodogram in python. This code expands upon the original distribution for this article (doi:10.3389/fspas.2024.1519436)

Usage

The following demo illustrates the ND-LSP in 1D.

import matplotlib.pyplot as plt
import numpy as np

import ndlsp as nd

np.random.seed(42)
n = 400                   # number of sample points
f0, phi0, amp0 = 5, 0.2 * np.pi, 3  # frequency, phase, amplitude for sinusoid
t = np.random.rand(n)     # Non-uniform point samples between 0 and 1

y = (
    amp0 * np.sin(2 * np.pi * f0 * t + phi0)    # Sinusoid
    + 0.1 * np.random.randn(n)                  # Noise
)
y_prime = y - np.mean(y)

# now run the LSP
X = np.reshape(t, (1, n))
fsamp = np.linspace(start=0.5, stop=10, num=1000)  # Frequencies in units of [1/X]
A, phi = nd.lsp_nd(X, y_prime, [fsamp])           # Amplitude and phase
recon_freq = fsamp[np.argmax(A)]
recon_phase = 2. * np.pi * (1 / fsamp[np.argmax(A)]) * np.mean(t)

# Plot the reconstruction
f, (ax1, ax2, ax3) = plt.subplots(nrows=3, ncols=1, sharex='none')
f: plt.Figure
ax1.plot(t, y, '.', label='Data')
ax1.set_xlabel('Time []')
ax1.set_ylabel('Value []')
ax1.legend(loc="upper right")

ax2.plot(fsamp, A)
ax2.set_xlabel('Frequency []')
ax2.set_ylabel('amplitude []')
ax2.plot([f0, f0], [0, amp0], 'r--', label=f'Known freq = {f0:.2f}')
ax2.plot([recon_freq, recon_freq], [0, amp0], 'r--', label=f'Recon. freq = {recon_freq:.4f}')
ax2.legend()

ax3.plot(fsamp, phi / np.pi)
ax3.set_xlabel('Frequency []')
ax3.set_ylabel(r'Phase [$\pi$]')
ax3.set_ylim([-1.1, 1.1])
ax3.plot([f0, f0], [-1, 1], 'r--', label=r'Known phase: %.2f $\pi$' % (phi0 / np.pi))
ax3.plot([recon_freq, recon_freq], [-1, 1], 'r--', label=r'Recon phase = %.4f $\pi$' % (recon_phase / np.pi))
ax3.legend()
ax3.set_yticks([-1., 0, 1.])
ax3.set_yticks([-1., -0.75, -0.5, -0.25, 0.,  0.25,  0.5,  0.75,  1.0], minor=True)
ax3.grid(which='both')
f.tight_layout()
f.show()

2D

A 2D example (without the phase) is shown below

n = 2000
np.random.seed(42)
x = np.random.rand(n)
y = np.random.rand(n)
X = np.vstack((x, y))

k1 = np.array([3, 4])
k2 = np.array([-3, 1])
z = (
    1 * np.sin(2 * np.pi * (np.sum(k1[:, None] * X, axis=0)))    # Sinusoid #1
    + 2 * np.sin(2 * np.pi * (np.sum(k2[:, None] * X, axis=0)))  # Sinusoid #2
    + 0.5 * np.random.randn(n)                                   # Random noise
)

# now run the LSP
fx = np.linspace(-5, 5, 40)
fy = np.linspace(-5, 5, 41)
fs = [fx, fy]
A, phi = nd.lsp_nd(X, z, fs)

# plot the results - move this to a function eventually
f, (ax1, ax2) = plt.subplots(2, 1, figsize=(6, 8))
im = ax1.scatter(x, y, c=z)
cb = plt.colorbar(im, ax=ax1)
cb.set_label('Value []')
ax1.set_xlabel('X []')
ax1.set_ylabel('Y []')

im = ax2.contourf(fx, fy, A.T)
cb = plt.colorbar(im, ax=ax2)
cb.set_label('Amplitude []')
ax2.plot(*k1, 'rx', label="Wave #1 known freq",)
ax2.plot(*k2, 'gx', label="Wave #2 known freq",)
ax2.set_xlabel('X frequency []')
ax2.set_ylabel('Y frequency []')
ax2.legend(loc="lower right")
f.tight_layout()
f.savefig("2d.png")
f.show()

Reconstruction

The simplest reconstruction of one wave is facilitated by the reconstruct method

xg = np.arange(0, 1.01, 0.01)
yg = np.arange(0, 1.01, 0.01)
grids = (xg, yg)
levs2 = np.arange(-4.0, 4.01, 0.25)

yre_1 = nd.reconstruct(A, phi, fs, [8, 24], grids)

f_recon_one_wave, ax_recon_one_wave = plt.subplots()
im = ax_recon_one_wave.contourf(xg, yg, yre_1.T, levs2, cmap='viridis')
cb = plt.colorbar(im, ax=ax_recon_one_wave)
cb.set_label('Value []')
ax_recon_one_wave.set_title("Wave Reconstruction")
ax_recon_one_wave.set_xlabel('X []')
ax_recon_one_wave.set_ylabel('Y []')
f_recon_one_wave.show()

Reconstructing multiple wave is facilitated with the iterative_orthogonal_reconstruction method.

A, phi, inner_prod = nd.lsp_nd(X, z, fs, retrieve_orthogonality=True)
yre_2 = nd.iterative_orthogonal_reconstruction(A, phi, inner_prod, fs,
                                               grids=grids,
                                               ortho_thresh=3e-1)
f_recon_waves, ax_recon_waves = plt.subplots()
im = ax_recon_waves.contourf(xg, yg, yre_2.T, levs2, cmap='viridis')
cb = plt.colorbar(im, ax=ax_recon_waves)
cb.set_label('Value []')
ax_recon_waves.set_title("Waves Reconstruction")
ax_recon_waves.set_xlabel('X []')
ax_recon_waves.set_ylabel('Y []')
f_recon_waves.show()

Release files for ndlsp 0.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ndlsp 0.2.1
File Size Uploaded
ndlsp-0.2.1.tar.gz 17.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ndlsp 0.2.1
File Interpreter ABI Platform
ndlsp-0.2.1-py3-none-any.whl Python 3 none any Details

Total release size: 34.1 kB

Release files / ndlsp-0.2.1.tar.gz

Download URL ndlsp-0.2.1.tar.gz
Size 17.2 kB
Tags Source
SHA-256 checksum
How to use checksums
3c2b4c07c33493bda18810cc790b8fc06c3ca98538b57836bdce6f416f4ac1fd
BLAKE2b-256 checksum
How to use checksums
64f5ad93aeaa78a068dd321306b13adb9dd0cab4dd5228e6c4f448a9bc9efb38
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.5.24

Release files / ndlsp-0.2.1-py3-none-any.whl

Download URL ndlsp-0.2.1-py3-none-any.whl
Size 16.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3a24136fbaf439926f72e71d2d75ae88aed6de6038ccbc9871caefa21a6cf19b
BLAKE2b-256 checksum
How to use checksums
95db0d3990caa95df192a51ad8b76727bae61289d9e7fdcc9b7ab9dff9e57b95
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.5.24

Release history Release notifications | RSS feed

This release

0.2.1 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page