Skip to content

Commit d23c6c9

Browse files
Move check of powers outside function and test
1 parent 19915f5 commit d23c6c9

File tree

2 files changed

+63
-14
lines changed

2 files changed

+63
-14
lines changed

stingray/fourier.py

Lines changed: 52 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -972,6 +972,48 @@ def _intrinsic_coherence_uncertainties(
972972
return uncertainty
973973

974974

975+
@vectorize(
976+
["UniTuple(float64[:, :], 2)(float64[:, :], float64[:, :], float64, float64, int64)"],
977+
nopython=True,
978+
)
979+
def check_powers_for_intrinsic_coherence(
980+
power1, power2, power1_noise, power2_noise, n_ave, threshold=3
981+
):
982+
"""Check if the powers are above the threshold for the intrinsic coherence to be well defined.
983+
984+
Parameters
985+
----------
986+
power1 : float `np.array`
987+
sub-band periodogram
988+
power2 : float `np.array`
989+
reference-band periodogram
990+
power1_noise : float
991+
Poisson noise level of the sub-band periodogram
992+
power2_noise : float
993+
Poisson noise level of the reference-band periodogram
994+
n_ave : int
995+
number of intervals that have been averaged to obtain the input spectra
996+
997+
Other Parameters
998+
----------------
999+
threshold : float, default 3
1000+
The threshold in sigma above the noise level for the powers to be considered "high".
1001+
1002+
Returns
1003+
-------
1004+
low_power1 : bool `np.array`
1005+
Whether the powers of the first band are below the threshold.
1006+
low_power2 : bool `np.array`
1007+
Whether the powers of the second band are below the threshold.
1008+
1009+
"""
1010+
# Consider low power when the power is less than 3 sigma above the noise level.
1011+
# This is somewhat arbitrary, better criteria suggestions are welcome.
1012+
low_power1 = (power1 - power1_noise) <= 3 * power1_noise / np.sqrt(n_ave)
1013+
low_power2 = (power2 - power2_noise) <= 3 * power2_noise / np.sqrt(n_ave)
1014+
return low_power1 or low_power2
1015+
1016+
9751017
@vectorize(
9761018
["UniTuple(float64[:, :], 2)(float64, float64, float64, float64, float64, int64, float64)"],
9771019
nopython=True,
@@ -1022,19 +1064,16 @@ def _intrinsic_coherence(
10221064
The intrinsic coherence values at all frequencies. If ``return_uncertainty`` is True,
10231065
also returns the uncertainty on the coherence.
10241066
"""
1067+
1068+
if check_powers_for_intrinsic_coherence(power1, power2, power1_noise, power2_noise, n_ave):
1069+
# If the powers are too close to the noise level, the coherence is not well defined.
1070+
return np.nan, np.nan
1071+
10251072
bsq = _bias_term(power1, power2, power1_noise, power2_noise, n_ave, 1)
10261073
num = (cross_power * np.conj(cross_power)).real - bsq
10271074
if num < 0:
10281075
num = 0
10291076

1030-
# Consider low power when the power is less than 3 sigma above the noise level.
1031-
# This is somewhat arbitrary, better criteria suggestions are welcome.
1032-
low_power1 = power1 - power1_noise <= 3 * power1_noise / np.sqrt(n_ave)
1033-
low_power2 = power2 - power2_noise <= 3 * power2_noise / np.sqrt(n_ave)
1034-
if low_power1 or low_power2:
1035-
# If the powers are too close to the noise level, the coherence is not well defined.
1036-
return np.nan, np.nan
1037-
10381077
power1_sub = power1 - power1_noise
10391078
power2_sub = power2 - power2_noise
10401079

@@ -1072,17 +1111,16 @@ def _intrinsic_coherence_with_adjusted_bias(
10721111
and the coherence will be set to NaN.
10731112
10741113
"""
1114+
1115+
if check_powers_for_intrinsic_coherence(power1, power2, power1_noise, power2_noise, n_ave):
1116+
# If the powers are too close to the noise level, the coherence is not well defined.
1117+
return np.nan, np.nan
1118+
10751119
# Consider low power when the power is less than 3 sigma above the noise level.
10761120
# This is somewhat arbitrary, better criteria suggestions are welcome.
10771121
power1_sub = power1 - power1_noise
10781122
power2_sub = power2 - power2_noise
10791123

1080-
low_power1 = power1_sub <= 3 * power1_noise / np.sqrt(n_ave)
1081-
low_power2 = power2_sub <= 3 * power2_noise / np.sqrt(n_ave)
1082-
if low_power1 or low_power2:
1083-
# If the powers are too close to the noise level, the coherence is not well defined.
1084-
return np.nan, np.nan
1085-
10861124
current_coherence = 1.0
10871125

10881126
for _ in range(40):

stingray/tests/test_fourier.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from stingray.fourier import get_average_ctrate, normalize_leahy_from_variance
2121
from stingray.fourier import integrate_power_in_frequency_range
2222
from stingray.fourier import get_rms_from_rms_norm_periodogram, get_rms_from_unnorm_periodogram
23+
from stingray.fourier import check_powers_for_intrinsic_coherence
2324

2425
from stingray.utils import check_allclose_and_print
2526
from astropy.modeling.models import Lorentz1D
@@ -227,6 +228,16 @@ def test_raw_high_bias(self):
227228
assert np.allclose(coh, 0)
228229
assert np.isclose(coh_sngl, 0)
229230

231+
def test_check_powers_for_intrinsic_coherence(self):
232+
pow1 = np.array([10, 20, 30])
233+
pow2 = np.array([10, 20, 30])
234+
pow1_noise = 5
235+
pow2_noise = 5
236+
n_ave = np.array([1, 10, 10])
237+
# Only one power is below the threshold, due to the low number of averaged powers.
238+
res = check_powers_for_intrinsic_coherence(pow1, pow2, pow1_noise, pow2_noise, n_ave)
239+
assert np.all(res == np.array([True, False, False]))
240+
230241

231242
class TestFourier(object):
232243
@classmethod

0 commit comments

Comments
 (0)