Skip to content
Open
Show file tree
Hide file tree
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
148 changes: 100 additions & 48 deletions directional_wave_spectra_example.ipynb

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ version = "0.1.0"
description = "Reusable utility functions for internal projects"
readme = "README.md"
requires-python = ">=3.8"
dependencies = [
"numpy",
"pandas",
"matplotlib",
"pytest",
"scipy",
"numba"
]

authors = [
{ name = "Anna Savage", email = "anna.savage@sofarocean.com" }
Expand Down
6 changes: 0 additions & 6 deletions requirements.txt

This file was deleted.

62 changes: 31 additions & 31 deletions tests/test_estimate_directional_spectrum.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,9 @@ def test_realistic_wave_conditions(self):
peak_direction_idx = np.argmax(np.mean(result, axis=0))
peak_direction = self.directions[peak_direction_idx]

# Peak should be reasonably close to the dominant direction (45 degrees)
# Peak should be reasonably close to the dominant direction (225 degrees)
# Allow for some tolerance due to discretization and numerical effects
assert abs(peak_direction - 45) < 5, f"Peak direction {peak_direction} should be near 45 degrees"
assert abs(peak_direction - 225) < 5, f"Peak direction {peak_direction} should be near 225 degrees"

def test_symmetry_properties(self):
"""Test symmetry properties of the directional spectrum."""
Expand Down Expand Up @@ -480,9 +480,9 @@ def test_real_world_regression_values(self):
mean_value = np.mean(result[result > 0]) # Mean of non-zero values

# Expected values (computed from current implementation)
expected_total_energy = 0.7900041687211213 # Sum of all directional spectrum values
expected_max_value = 0.006608127419460172 # Maximum value in the spectrum
expected_mean_nonzero = 0.00013299733480153555 # Mean of non-zero values
expected_total_energy = 0.7801396662948376 # Sum of all directional spectrum values
expected_max_value = 0.00660995147262925 # Maximum value in the spectrum
expected_mean_nonzero = 0.00013133664415738004 # Mean of non-zero values

# Test with reasonable tolerance for numerical precision
np.testing.assert_allclose(total_energy, expected_total_energy, rtol=1e-10,
Expand All @@ -498,8 +498,8 @@ def test_real_world_regression_values(self):
peak_direction_idx = np.argmax(peak_freq_spectrum)
peak_value = peak_freq_spectrum[peak_direction_idx]

expected_peak_value = 0.006608127419460172
expected_peak_direction_idx = 91 # Direction index where peak occurs
expected_peak_value = 0.00660995147262925
expected_peak_direction_idx = 44 # Direction index where peak occurs

np.testing.assert_allclose(peak_value, expected_peak_value, rtol=1e-10,
err_msg="Peak value should match expected value")
Expand All @@ -515,10 +515,10 @@ def test_real_world_regression_values(self):
]

expected_values = [
0.002799481644527717, # (0, 0)
0.006597944104197192, # (0, 90)
1.7293532633632256e-08, # (10, 45)
4.510801355465396e-09, # (20, 120)
1.7770849992620845e-05, # (0, 0)
6.361678460273995e-06, # (0, 90)
0.00014728635528746644, # (10, 45)
9.475270206911038e-07, # (20, 120)
]

for (freq_idx, dir_idx), expected_val in zip(test_indices, expected_values):
Expand Down Expand Up @@ -561,9 +561,9 @@ def test_real_world_regression_values_dataset2(self):
mean_value = np.mean(result[result > 0]) # Mean of non-zero values

# Expected values (computed from current implementation)
expected_total_energy = 3.796532081195266
expected_max_value = 0.0237655737957158
expected_mean_nonzero = 0.0005408165357828014
expected_total_energy = 3.7484928623030283
expected_max_value = 0.023793139411520763
expected_mean_nonzero = 0.0005339733422084086

# Test with tight tolerance for numerical precision
np.testing.assert_allclose(total_energy, expected_total_energy, rtol=1e-10,
Expand All @@ -578,8 +578,8 @@ def test_real_world_regression_values_dataset2(self):
peak_direction_idx = np.argmax(peak_freq_spectrum)
peak_value = peak_freq_spectrum[peak_direction_idx]

expected_peak_value = 0.0237655737957158
expected_peak_direction_idx = 160 # Direction index where peak occurs
expected_peak_value = 0.023793139411520763
expected_peak_direction_idx = 153 # Direction index where peak occurs

np.testing.assert_allclose(peak_value, expected_peak_value, rtol=1e-10,
err_msg="Dataset2: Peak value should match expected value")
Expand All @@ -596,11 +596,11 @@ def test_real_world_regression_values_dataset2(self):
]

expected_values = [
0.00012979971269644488, # (0, 0)
0.00016998854068615924, # (8, 45)
1.5405259481743667e-05, # (8, 90)
1.4878006537603e-05, # (15, 120)
2.0551655355091914e-05, # (30, 60)
8.746967996651501e-06, # (0, 0)
1.7955193217159483e-05, # (8, 45)
0.00015525859898835503, # (8, 90)
0.0002541624129700038, # (15, 120)
3.352901354780756e-05, # (30, 60)
]

for (freq_idx, dir_idx), expected_val in zip(test_indices, expected_values):
Expand Down Expand Up @@ -643,9 +643,9 @@ def test_real_world_regression_values_dataset3(self):
mean_value = np.mean(result[result > 0]) # Mean of non-zero values

# Expected values (computed from current implementation)
expected_total_energy = 1.9407214806299242
expected_max_value = 0.006680274721347798
expected_mean_nonzero = 0.00027645605137178406
expected_total_energy = 1.918813864567803
expected_max_value = 0.006685444177345408
expected_mean_nonzero = 0.00027333530834299186

# Test with tight tolerance for numerical precision
np.testing.assert_allclose(total_energy, expected_total_energy, rtol=1e-10,
Expand All @@ -661,8 +661,8 @@ def test_real_world_regression_values_dataset3(self):
peak_direction_idx = np.argmax(peak_freq_spectrum)
peak_value = peak_freq_spectrum[peak_direction_idx]

expected_peak_value = 0.006680274721347798
expected_peak_direction_idx = 28
expected_peak_value = 0.006685444177345408
expected_peak_direction_idx = 107

np.testing.assert_allclose(peak_value, expected_peak_value, rtol=1e-10,
err_msg="Dataset3: Peak value should match expected value")
Expand All @@ -679,11 +679,11 @@ def test_real_world_regression_values_dataset3(self):
]

expected_values = [
2.1688225830776163e-06, # (0, 0)
0.0015228792292005142, # (3, 45)
8.339385649101882e-05, # (10, 90)
8.511075197100215e-06, # (20, 120)
4.55005492564815e-06, # (35, 60)
8.6419881036956e-07, # (0, 0)
4.802789983657425e-05, # (3, 45)
3.674605329592568e-05, # (10, 90)
0.00022398376261676908, # (20, 120)
4.3458775851265904e-06, # (35, 60)
]

for (freq_idx, dir_idx), expected_val in zip(test_indices, expected_values):
Expand Down
11 changes: 7 additions & 4 deletions wave_signal_processing/spectral_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,10 +300,13 @@ def root_finder(
direction_increment = get_direction_increment(directions_radians)

twiddle_factors = np.empty((4, len(directions_radians)))
twiddle_factors[0, :] = np.cos(directions_radians)
twiddle_factors[1, :] = np.sin(directions_radians)
twiddle_factors[2, :] = np.cos(2 * directions_radians)
twiddle_factors[3, :] = np.sin(2 * directions_radians)

phi = (3 * np.pi / 2) - directions_radians # uses meteorological directional convention

twiddle_factors[0, :] = np.cos(phi)
twiddle_factors[1, :] = np.sin(phi)
twiddle_factors[2, :] = np.cos(2 * phi)
twiddle_factors[3, :] = np.sin(2 * phi)

guess = initial_value(moments)
for ipoint in range(0, number_of_points):
Expand Down