LALPulsar  6.1.0.1-89842e6
simulateCW.py
Go to the documentation of this file.
1 # Copyright (C) 2017 Karl Wette
2 #
3 # This program is free software; you can redistribute it and/or modify it
4 # under the terms of the GNU General Public License as published by the
5 # Free Software Foundation; either version 2 of the License, or (at your
6 # option) any later version.
7 #
8 # This program is distributed in the hope that it will be useful, but
9 # WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
11 # Public License for more details.
12 #
13 # You should have received a copy of the GNU General Public License along
14 # with this program; if not, write to the Free Software Foundation, Inc.,
15 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 
17 ## \defgroup lalpulsar_py_simulateCW SimulateCW
18 ## \ingroup lalpulsar_python
19 r"""
20 Generate strain time series of a continuous-wave signal in the detector frame,
21 given a function which computes signal phase and amplitudes as functions of time.
22 
23 The given function should compute quantities \f$\Delta\phi(t)\f$, \f$a_+(t)\f$,
24 and \f$a_\times(t)\f$ such that the plus and cross gravitational-wave
25 polarisations \f$h_+(t)\f$ and \f$h_\times(t)\f$ are given by:
26 \f{eqnarray}{
27 h_+(t) & = & a_+(t) \cos[\phi_0 + \Delta\phi(t)] \; , \\
28 h_\times(t) & = & a_\times(t)\sin[\phi_0 + \Delta\phi(t)] \; .
29 \f}
30 
31 This module provides a class CWSimulator() to generate the strain time series.
32 CWSimulator() can also directly write frame files and SFT files. Example usage:
33 
34 ~~~
35 import lal
36 from lalpulsar import simulateCW
37 
38 def waveform(h0, cosi, freq, f1dot):
39  def wf(dt):
40  dphi = lal.TWOPI * (freq * dt + f1dot * 0.5 * dt**2)
41  ap = h0 * (1.0 + cosi**2) / 2.0
42  ax = h0 * cosi
43  return dphi, ap, ax
44  return wf
45 
46 tref = 900043200
47 tstart = 900000000
48 Tdata = 86400
49 h0 = 1e-24
50 cosi = 0.123
51 psi = 2.345
52 phi0 = 3.210
53 freq = 10.0
54 f1dot = -1.35e-8
55 dt_wf = 5
56 alpha = 6.12
57 delta = 1.02
58 detector = 'H1'
59 
60 wf = waveform(h0, cosi, freq, f1dot)
61 S = simulateCW.CWSimulator(tref, tstart, Tdata, wf, dt_wf, phi0, psi, alpha, delta, detector)
62 
63 # To write SFT files
64 for file, i, N in S.write_sft_files(fmax=32, Tsft=1800, comment="simCW"):
65  print('Generated SFT file %s (%i of %i)' % (file, i+1, N))
66 
67 # To write frame files
68 for file, i, N in S.write_frame_files(fs=1, Tframe=1800, comment="simCW"):
69  print('Generated frame file %s (%i of %i)' % (file, i+1, N))
70 
71 ~~~
72 """
73 ## @{
74 
75 from __future__ import division, print_function
76 
77 import os
78 import sys
79 import re
80 import math
81 
82 import lal
83 import lalpulsar
84 
85 from . import git_version
86 
87 __author__ = "Karl Wette <karl.wette@ligo.org>"
88 __version__ = git_version.id
89 __date__ = git_version.date
90 
91 
92 class CWSimulator(object):
93  def __init__(
94  self,
95  tref,
96  tstart,
97  Tdata,
98  waveform,
99  dt_wf,
100  phi0,
101  psi,
102  alpha,
103  delta,
104  det_name,
105  earth_ephem_file="earth00-40-DE405.dat.gz",
106  sun_ephem_file="sun00-40-DE405.dat.gz",
107  tref_at_det=False,
108  extra_comment=None,
109  ):
110  """
111  Initialise a continuous-wave signal simulator.
112 
113  @param tref: reference time of signal phase at Solar System barycentre, in GPS seconds
114  (but see @b tref_at_det)
115  @param tstart: start time of signal, in GPS seconds
116  @param Tdata: total duration of signal, in seconds
117  @param waveform: function which computes signal phase and amplitudes as functions of time:
118  @b dphi, @b aplus, @b across = @b waveform(dt), where:
119  @b dt = time since reference time @b tref;
120  @b dphi = phase of signal at time @b dt relative to reference time @b tref, in radians;
121  @b aplus = strain amplitude of plus polarisation at time @b dt;
122  @b across = strain amplitude of cross polarisation at time @b dt
123  @param dt_wf: sampling time of the function @c waveform; this need only be small enough to ensure
124  that @c dphi, @c aplus, and @c across are smoothly interpolated, and does not need to make
125  the desired sampling frequency of the output strain time series
126  @param phi0: initial phase of the gravitational-wave signal at @b tstart, in radians
127  @param psi: polarisation angle of the gravitational-wave source, in radians
128  @param alpha: right ascension of the gravitational-wave source, in radians
129  @param delta: declination of the gravitational-wave source, in radians
130  @param det_name: name of the gravitational-wave detector to simulate a response for;
131  e.g. @c "H1" for LIGO Hanford, @c "L1" for LIGO Livingston, @c "V1" for Virgo
132  @param earth_ephem_file: name of file to load Earth ephemeris from
133  @param sun_ephem_file: name of file to load Sun ephemeris from
134  @param tref_at_det: default False; if True, shift reference time @b tref so that @b dt = 0 is
135  @b tref in @e detector frame instead of Solar System barycentre frame, useful if e.g. one
136  wants to turn on signal only for @b dt > 0, one can use @b tref as the turn-on time
137  @param extra_comment: additional text to add to comment string in frame/SFT headers
138  (not filenames), e.g. for wrapper script commandlines
139  """
140 
141  self.__origin_str__origin_str = "Generated by %s, %s-%s (%s)" % (
142  __file__,
143  git_version.id,
144  git_version.status,
145  git_version.date,
146  )
147  if extra_comment:
148  self.__origin_str__origin_str += ", " + extra_comment
149 
150  # store arguments
151  self.__tstart__tstart = tstart
152  self.__Tdata__Tdata = Tdata
153 
154  # parse detector name
155  try:
156  _, self.__site_index__site_index = lalpulsar.FindCWDetector(det_name, True)
157  assert self.__site_index__site_index >= 0
158  except:
159  raise ValueError("Invalid detector name det_name='%s'" % det_name)
160  self.__site__site = lal.CachedDetectors[self.__site_index__site_index]
161 
162  # load Earth and Sun ephemerides
163  self.__ephemerides__ephemerides = lalpulsar.InitBarycenter(earth_ephem_file, sun_ephem_file)
164 
165  if tref_at_det:
166  # calculate barycentric delay at reference time
167  bary_state = lalpulsar.EarthState()
168  bary_input = lalpulsar.BarycenterInput()
169  bary_emit = lalpulsar.EmissionTime()
170  bary_input.tgps = tref
171  bary_input.site = self.__site__site
172  for i in range(0, 3):
173  bary_input.site.location[i] /= lal.C_SI
174  bary_input.alpha = alpha
175  bary_input.delta = delta
176  bary_input.dInv = 0.0
177  lalpulsar.BarycenterEarth(bary_state, bary_input.tgps, self.__ephemerides__ephemerides)
178  lalpulsar.Barycenter(bary_emit, bary_input, bary_state)
179 
180  # adjust reference time so that dt = 0 is tref in detector frame
181  tref += bary_emit.deltaT
182 
183  # start signal time series 'Tpad_wf' before/after output strain time series
184  # add sufficient padding to signal for maximum Doppler modulation time shifts, otherwise
185  # lalpulsar.PulsarSimulateCoherentGW() will output zeros without complaint (unless
186  # you run with LAL_DEBUG_LEVEL=warning)
187  Tpad_wf = 2.0 * lal.AU_SI / lal.C_SI
188  tstart_wf = tstart - Tpad_wf
189  Nwf = int(math.ceil(float(Tdata + 2 * Tpad_wf) / float(dt_wf)))
190 
191  # create REAL8TimeSeries to store signal phase
192  self.__phi__phi = lal.CreateREAL8TimeSeries(
193  "phi", tstart_wf, 0, dt_wf, lal.DimensionlessUnit, Nwf
194  )
195 
196  # create REAL4TimeVectorSeries to store signal amplitudes
197  # - LAL provides no creator function for this type, so must be done manually
198  self.__a__a = lal.REAL4TimeVectorSeries()
199  self.__a__a.name = "a+,ax"
200  self.__a__a.epoch = tstart_wf
201  self.__a__a.deltaT = dt_wf
202  self.__a__a.f0 = 0
203  self.__a__a.sampleUnits = lal.StrainUnit
204  self.__a__a.data = lal.CreateREAL4VectorSequence(Nwf, 2)
205 
206  # call waveform() to fill time series of signal phase and amplitudes
207  dt = float(tstart_wf - tref)
208  for i in range(0, Nwf):
209  dphi, aplus, across = waveform(dt)
210  self.__phi__phi.data.data[i] = phi0 + dphi
211  self.__a__a.data.data[i][0] = aplus
212  self.__a__a.data.data[i][1] = across
213  dt += dt_wf
214 
215  # create and initialise PulsarCoherentGW struct
216  self.__wf__wf = lalpulsar.PulsarCoherentGW()
217  self.__wf__wf.position.system = lal.COORDINATESYSTEM_EQUATORIAL
218  self.__wf__wf.position.longitude = alpha
219  self.__wf__wf.position.latitude = delta
220  self.__wf__wf.psi = psi
221  self.__wf__wf.phi = self.__phi__phi
222  self.__wf__wf.a = self.__a__a
223 
224  # create and initialise PulsarDetectorResponse struct
225  self.__detector__detector = lalpulsar.PulsarDetectorResponse()
226  self.__detector__detector.site = self.__site__site
227  self.__detector__detector.ephemerides = self.__ephemerides__ephemerides
228 
229  def _simulate_coherent_gw(self, h, noise_sqrt_Sh, noise_seed):
230  # generate strain time series
231  lalpulsar.PulsarSimulateCoherentGW(h, self.__wf__wf, self.__detector__detector)
232 
233  # add Gaussian noise, if requested
234  if noise_sqrt_Sh > 0:
235  assert noise_seed is not None
236  assert noise_seed > 0
237  noise_sigma = math.sqrt(0.5 / h.deltaT) * noise_sqrt_Sh
238  lalpulsar.AddGaussianNoise(h, noise_sigma, noise_seed)
239 
240  def get_strain(self, fs, tmin=0, tmax=None, noise_sqrt_Sh=0, noise_seed=None):
241  """
242  Generate strain time series of a continuous-wave signal in the detector frame.
243 
244  @param fs: sampling frequency of strain time series, in Hz
245  @param tmin: start time for strain time series, as offsets from self.__tstart
246  @param tmax: start time for strain time series, as offsets from self.__tstart
247  @param noise_sqrt_Sh: if >0, add Gaussian noise with square-root single-sided power
248  spectral density given by this value, in Hz^(-1/2)
249  @param noise_seed: use this seed for the random number generator used to create noise;
250  required if noise_sqrt_Sh >0
251 
252  @return (@b t, @b h), where:
253  @b t = start of time strain time series, in GPS seconds;
254  @b h = strain time series
255  """
256 
257  # process tmin/tmax range (interpreted relative to self.__tstart)
258  if (tmin < 0) or (tmin >= self.__Tdata__Tdata):
259  raise ValueError("tmin must be within [0,{}).".format(self.__Tdata__Tdata))
260  if tmax is None:
261  tmax = self.__Tdata__Tdata
262  elif (tmax <= 0) or (tmax > self.__Tdata__Tdata):
263  raise ValueError("tmax must be within (0,{}].".format(self.__Tdata__Tdata))
264  tspan = tmax - tmin
265 
266  # create REAL4TimeSeries to store output time series
267  Nh = int(fs * tspan)
268  h = lal.CreateREAL4TimeSeries(
269  "h", self.__tstart__tstart + tmin, 0, 1.0 / fs, lal.DimensionlessUnit, Nh
270  )
271 
272  # generate strain time series
273  self._simulate_coherent_gw_simulate_coherent_gw(h, noise_sqrt_Sh, noise_seed)
274  return (h.epoch, h.data.data)
275 
276  def get_strain_blocks(self, fs, Tblock, noise_sqrt_Sh=0, noise_seed=None):
277  """
278  Generate strain time series of a continuous-wave signal in the detector frame, in contiguous blocks.
279 
280  @param fs: sampling frequency of strain time series, in Hz
281  @param Tblock: length of each block, in seconds; should divide evenly into @b Tdata
282  @param noise_sqrt_Sh: if >0, add Gaussian noise with square-root single-sided power
283  spectral density given by this value, in Hz^(-1/2)
284  @param noise_seed: use this seed for the random number generator used to create noise;
285  if None, generate a random seed using os.urandom()
286 
287  @return (@b t, @b h, @b i, @b N), where:
288  @b t = start of time strain time series, in GPS seconds;
289  @b h = strain time series;
290  @b i = block index, starting from zero;
291  @b N = number of blocks
292 
293  This is a Python generator function and so should be called as follows:
294  ~~~
295  S = CWSimulator(...)
296  for t, h, i, N in S.get_strain_blocks(...):
297  ...
298  ~~~
299  """
300 
301  # work out number of blocks
302  Nblock = int(round(self.__Tdata__Tdata / Tblock))
303  if Tblock * Nblock > self.__Tdata__Tdata:
304  raise ValueError(
305  "Length of block Tblock=%g does not divide evenly into Tdata=%g"
306  % (Tblock, self.__Tdata__Tdata)
307  )
308 
309  # if no noise seed is given, generate a (non-zero) random seed using os.urandom()
310  if not noise_seed:
311  noise_seed = 0
312  while not (0 < noise_seed and noise_seed < lal.LAL_INT4_MAX - Nblock):
313  noise_seed = int.from_bytes(os.urandom(4), sys.byteorder, signed=False)
314 
315  # generate strain time series in blocks of length 'Tblock'
316  tmin = 0
317  for iblock in range(0, Nblock):
318  epoch, hoft = self.get_strainget_strain(
319  fs,
320  tmin=tmin,
321  tmax=tmin + Tblock,
322  noise_sqrt_Sh=noise_sqrt_Sh,
323  noise_seed=noise_seed + iblock,
324  )
325  yield epoch, hoft, iblock, Nblock
326  tmin += Tblock
327 
328  def write_frame_files(
329  self, fs, Tframe, comment="simCW", out_dir=".", noise_sqrt_Sh=0, noise_seed=None
330  ):
331  """
332  Write frame files [1] containing strain time series of a continuous-wave signal.
333 
334  The strain time series is written as double-precision post-processed data (ProcData) channel named
335  <tt>&lt;detector&gt;:SIMCW-STRAIN</tt>,
336  where <tt>&lt;detector&gt;</tt> is the 2-character detector prefix (e.g. <tt>H1</tt> for LIGO Hanford,
337  <tt>L1</tt> for LIGO Livingston, <tt>V1</tt> for Virgo).
338 
339  @param fs: sampling frequency of strain time series, in Hz
340  @param Tframe: length of each frame, in seconds; should divide evenly into @b Tdata
341  @param comment: frame file name comment, may only contain A-Z, a-z, 0-9, _, +, # characters
342  @param out_dir: output directory to write frame files into
343  @param noise_sqrt_Sh: if >0, add Gaussian noise with square-root single-sided power
344  spectral density given by this value, in Hz^(-1/2)
345  @param noise_seed: use this seed for the random number generator used to create noise;
346  if None, generate a random seed using os.urandom()
347 
348  @return (@b file, @b i, @b N), where:
349  @b file = name of frame file just written;
350  @b i = frame file index, starting from zero;
351  @b N = number of frame files
352 
353  This is a Python generator function and so should be called as follows:
354  ~~~
355  S = CWSimulator(...)
356  for file, i, N in S.write_frame_files(...):
357  ...
358  ~~~
359 
360  [1] https://dcc.ligo.org/LIGO-T970130/public
361  """
362 
363  try:
364  import lalframe
365  except ImportError:
366  raise ImportError("SWIG wrappings of LALFrame cannot be imported")
367 
368  # check for valid frame filename comment (see LIGO-T010150)
369  valid_comment = re.compile(r"^[A-Za-z0-9_+#]+$")
370  if not valid_comment.match(comment):
371  raise ValueError(
372  "Frame file comment='%s' may only contain A-Z, a-z, 0-9, _, +, # characters"
373  % comment
374  )
375 
376  # generate strain time series in blocks of length 'Tframe'
377  frame_h = None
378  for t, h, i, N in self.get_strain_blocksget_strain_blocks(
379  fs, Tframe, noise_sqrt_Sh=noise_sqrt_Sh, noise_seed=noise_seed
380  ):
381  # create and initialise REAL8TimeSeries to write to frame files
382  if frame_h is None:
383  frame_h_channel = "%s:SIMCW-STRAIN" % self.__site__site.frDetector.prefix
384  frame_h = lal.CreateREAL8TimeSeries(
385  frame_h_channel, t, 0, 1.0 / fs, lal.DimensionlessUnit, len(h)
386  )
387  frame_h.epoch = t
388  frame_h.data.data = h
389 
390  # create standard frame file name (see LIGO-T010150)
391  frame_src = self.__site__site.frDetector.prefix[0]
392  frame_desc = comment
393  frame_t0 = int(t.gpsSeconds)
394  frame_Tdata = int(math.ceil(float(t + Tframe)) - math.floor(float(t)))
395  frame_name = "%s-%s-%u-%u.gwf" % (
396  frame_src,
397  frame_desc,
398  frame_t0,
399  frame_Tdata,
400  )
401  frame_path = os.path.join(out_dir, frame_name)
402 
403  # create frame
404  frame_det_bits = 2 * self.__site_index__site_index
405  frame = lalframe.FrameNew(
406  t, Tframe, self.__class__.__name__, -1, i, frame_det_bits
407  )
408 
409  # add strain time series to frame
410  lalframe.FrameAddREAL8TimeSeriesProcData(frame, frame_h)
411 
412  # add history
413  lalframe.FrameAddFrHistory(frame, "origin", self.__origin_str__origin_str)
414 
415  # write frame
416  lalframe.FrameWrite(frame, frame_path)
417 
418  # yield current file name for e.g. printing progress
419  yield frame_path, i, N
420 
421  def get_sfts(
422  self,
423  fmax,
424  Tsft,
425  noise_sqrt_Sh=0,
426  noise_seed=None,
427  window="rectangular",
428  window_param=0,
429  ):
430  """
431  Generate SFTs [2] containing strain time series of a continuous-wave signal.
432 
433  @param fmax: maximum SFT frequency, in Hz
434  @param Tsft: length of each SFT, in seconds; should divide evenly into @b Tdata
435  @param noise_sqrt_Sh: if >0, add Gaussian noise with square-root single-sided power
436  spectral density given by this value, in Hz^(-1/2)
437  @param noise_seed: use this seed for the random number generator used to create noise;
438  if None, generate a random seed using os.urandom()
439  @param window: if not None, window the time series before performing the FFT, using
440  the named window function; see XLALCreateNamedREAL8Window()
441  @param window_param: parameter for the window function given by @b window, if needed
442 
443  @return (@b sft, @b i, @b N), where:
444  @b sft = SFT;
445  @b i = SFT file index, starting from zero;
446  @b N = number of SFTs
447 
448  This is a Python generator function and so should be called as follows:
449  ~~~
450  S = CWSimulator(...)
451  for sft, i, N in S.get_sfts(...):
452  ...
453  ~~~
454 
455  [2] https://dcc.ligo.org/LIGO-T040164/public
456  """
457 
458  # create timestamps for generating one SFT per time series
459  sft_ts = lalpulsar.CreateTimestampVector(1)
460  sft_ts.deltaT = Tsft
461 
462  # generate strain time series in blocks of length 'Tsft'
463  sft_h = None
464  sft_fs = 2 * fmax
465  for t, h, i, N in self.get_strain_blocksget_strain_blocks(
466  sft_fs, Tsft, noise_sqrt_Sh=noise_sqrt_Sh, noise_seed=noise_seed
467  ):
468  # create and initialise REAL8TimeSeries to write to SFT files
469  if sft_h is None:
470  sft_name = self.__site__site.frDetector.prefix
471  sft_h = lal.CreateREAL8TimeSeries(
472  sft_name, t, 0, 1.0 / sft_fs, lal.DimensionlessUnit, len(h)
473  )
474  sft_h.epoch = t
475  sft_h.data.data = h
476 
477  # create SFT, possibly with windowing
478  sft_ts.data[0] = t
479  sft_vect = lalpulsar.MakeSFTsFromREAL8TimeSeries(
480  sft_h, sft_ts, window, window_param
481  )
482 
483  # yield current SFT
484  yield sft_vect.data[0], i, N
485 
486  def write_sft_files(
487  self,
488  fmax,
489  Tsft,
490  comment="simCW",
491  out_dir=".",
492  noise_sqrt_Sh=0,
493  noise_seed=None,
494  window="rectangular",
495  window_param=0,
496  ):
497  """
498  Write SFT files [2] containing strain time series of a continuous-wave signal.
499 
500  @param fmax: maximum SFT frequency, in Hz
501  @param Tsft: length of each SFT, in seconds; should divide evenly into @b Tdata
502  @param comment: SFT file name comment, may only contain A-Z, a-z, 0-9 characters
503  @param out_dir: output directory to write SFT files into
504  @param noise_sqrt_Sh: if >0, add Gaussian noise with square-root single-sided power
505  spectral density given by this value, in Hz^(-1/2)
506  @param noise_seed: use this seed for the random number generator used to create noise;
507  if None, generate a random seed using os.urandom()
508  @param window: if not None, window the time series before performing the FFT, using
509  the named window function; see XLALCreateNamedREAL8Window()
510  @param window_param: parameter for the window function given by @b window, if needed
511 
512  @return (@b file, @b i, @b N), where:
513  @b file = name of SFT file just written;
514  @b i = SFT file index, starting from zero;
515  @b N = number of SFT files
516 
517  This is a Python generator function and so should be called as follows:
518  ~~~
519  S = CWSimulator(...)
520  for file, i, N in S.write_sft_files(...):
521  ...
522  ~~~
523 
524  [2] https://dcc.ligo.org/LIGO-T040164/public
525  """
526 
527  # check for valid SFT filename comment (see LIGO-T040164)
528  valid_comment = re.compile(r"^[A-Za-z0-9]+$")
529  if not valid_comment.match(comment):
530  raise ValueError(
531  "SFT file comment='%s' may only contain A-Z, a-z, 0-9 characters"
532  % comment
533  )
534 
535  # create SFT filename specification
536  spec = lalpulsar.SFTFilenameSpec()
537  spec.path = out_dir
538  spec.window_type = window
539  spec.window_param = window_param
540  spec.privMisc = comment
541 
542  # generate SFTs
543  for sft, i, N in self.get_sftsget_sfts(
544  fmax,
545  Tsft,
546  noise_sqrt_Sh=noise_sqrt_Sh,
547  noise_seed=noise_seed,
548  window=window,
549  window_param=window_param,
550  ):
551  # write SFT
552  lalpulsar.WriteSFT2StandardFile(sft, spec, self.__origin_str__origin_str)
553 
554  # yield current file name for e.g. printing progress
555  sft_path = lalpulsar.BuildSFTFilenameFromSpec(spec)
556  yield sft_path, i, N
557 
558 
559 ## @}
def get_sfts(self, fmax, Tsft, noise_sqrt_Sh=0, noise_seed=None, window="rectangular", window_param=0)
Generate SFTs [2] containing strain time series of a continuous-wave signal.
Definition: simulateCW.py:456
def write_sft_files(self, fmax, Tsft, comment="simCW", out_dir=".", noise_sqrt_Sh=0, noise_seed=None, window="rectangular", window_param=0)
Write SFT files [2] containing strain time series of a continuous-wave signal.
Definition: simulateCW.py:525
def get_strain(self, fs, tmin=0, tmax=None, noise_sqrt_Sh=0, noise_seed=None)
Generate strain time series of a continuous-wave signal in the detector frame.
Definition: simulateCW.py:255
def write_frame_files(self, fs, Tframe, comment="simCW", out_dir=".", noise_sqrt_Sh=0, noise_seed=None)
Write frame files [1] containing strain time series of a continuous-wave signal.
Definition: simulateCW.py:361
def get_strain_blocks(self, fs, Tblock, noise_sqrt_Sh=0, noise_seed=None)
Generate strain time series of a continuous-wave signal in the detector frame, in contiguous blocks.
Definition: simulateCW.py:299
def _simulate_coherent_gw(self, h, noise_sqrt_Sh, noise_seed)
Definition: simulateCW.py:229
def __init__(self, tref, tstart, Tdata, waveform, dt_wf, phi0, psi, alpha, delta, det_name, earth_ephem_file="earth00-40-DE405.dat.gz", sun_ephem_file="sun00-40-DE405.dat.gz", tref_at_det=False, extra_comment=None)
Initialise a continuous-wave signal simulator.
Definition: simulateCW.py:139