forked from gwastro/pycbc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtest_psd.py
133 lines (123 loc) · 5.77 KB
/
test_psd.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# Copyright (C) 2012 Tito Dal Canton, Josh Willis
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# =============================================================================
#
# Preamble
#
# =============================================================================
#
'''
These are the unittests for the pycbc PSD module.
'''
import sys
import os
import tempfile
import pycbc
import pycbc.psd
from pycbc.types import TimeSeries, FrequencySeries
from pycbc.fft import ifft
from pycbc.fft.fftw import set_measure_level
import unittest
import numpy
from utils import parse_args_all_schemes, simple_exit
set_measure_level(0)
_scheme, _context = parse_args_all_schemes("PSD")
class TestPSD(unittest.TestCase):
def setUp(self):
self.scheme = _scheme
self.context = _context
self.psd_len = 1024
self.psd_delta_f = 0.1
self.psd_low_freq_cutoff = 10.
# generate 1/f noise for testing PSD estimation
noise_size = 524288
sample_freq = 4096.
delta_f = sample_freq / noise_size
numpy.random.seed(132435)
noise = numpy.random.normal(loc=0, scale=1, size=noise_size/2+1) + \
1j * numpy.random.normal(loc=0, scale=1, size=noise_size/2+1)
noise_model = 1. / numpy.linspace(1., 100., noise_size / 2 + 1)
noise *= noise_model / numpy.sqrt(delta_f) / 2
noise[0] = noise[0].real
noise_fs = FrequencySeries(noise, delta_f=delta_f)
self.noise = TimeSeries(numpy.zeros(noise_size), delta_t=1./sample_freq)
ifft(noise_fs, self.noise)
def test_analytical(self):
"""Basic test of lalsimulation's analytical noise PSDs"""
with self.context:
psd_list = pycbc.psd.analytical.get_lalsim_psd_list()
self.assertTrue(psd_list)
for psd_name in psd_list:
psd = pycbc.psd.analytical.from_string(psd_name, self.psd_len,
self.psd_delta_f, self.psd_low_freq_cutoff)
psd_min = psd.min()
self.assertTrue(psd_min >= 0,
msg=(psd_name + ': negative values'))
self.assertTrue(psd.min() < 1e-40,
msg=(psd_name + ': unreasonably high minimum'))
def test_read(self):
"""Test reading PSDs from text files"""
test_data = numpy.zeros((self.psd_len, 2))
test_data[:, 0] = numpy.linspace(0.,
(self.psd_len - 1) * self.psd_delta_f, self.psd_len)
test_data[:, 1] = numpy.sqrt(test_data[:, 0])
file_desc, file_name = tempfile.mkstemp()
os.close(file_desc)
numpy.savetxt(file_name, test_data)
test_data[test_data[:, 0] < self.psd_low_freq_cutoff, 1] = 0.
with self.context:
psd = pycbc.psd.read.from_txt(file_name, self.psd_len,
self.psd_delta_f, self.psd_low_freq_cutoff, is_asd_file=True)
self.assertAlmostEqual(abs(psd - test_data[:, 1] ** 2).max(), 0)
os.unlink(file_name)
def test_estimate_welch(self):
"""Test estimating PSDs from data using Welch's method"""
for seg_len in (2048, 4096, 8192):
noise_model = (numpy.linspace(1., 100., seg_len/2 + 1)) ** (-2)
for seg_stride in (seg_len, seg_len/2):
for method in ('mean', 'median', 'median-mean'):
with self.context:
psd = pycbc.psd.welch(self.noise, seg_len=seg_len, \
seg_stride=seg_stride, avg_method=method)
error = (psd.numpy() - noise_model) / noise_model
err_rms = numpy.sqrt(numpy.mean(error ** 2))
self.assertTrue(err_rms < 0.2,
msg='seg_len=%d seg_stride=%d method=%s -> rms=%.3f' % \
(seg_len, seg_stride, method, err_rms))
def test_truncation(self):
"""Test inverse PSD truncation"""
for seg_len in (2048, 4096, 8192):
noise_model = (numpy.linspace(1., 100., seg_len/2 + 1)) ** (-2)
for max_len in (1024, 512, 256):
with self.context:
psd = pycbc.psd.welch(self.noise, seg_len=seg_len, \
seg_stride=seg_len/2, avg_method='mean')
psd_trunc = pycbc.psd.inverse_spectrum_truncation(
psd, max_len,
low_frequency_cutoff=self.psd_low_freq_cutoff)
freq = psd.sample_frequencies.numpy()
error = (psd.numpy() - noise_model) / noise_model
error = error[freq > self.psd_low_freq_cutoff]
err_rms = numpy.sqrt(numpy.mean(error ** 2))
self.assertTrue(err_rms < 0.1,
msg='seg_len=%d max_len=%d -> rms=%.3f' \
% (seg_len, max_len, err_rms))
suite = unittest.TestSuite()
suite.addTest(unittest.TestLoader().loadTestsFromTestCase(TestPSD))
if __name__ == '__main__':
results = unittest.TextTestRunner(verbosity=2).run(suite)
simple_exit(results)