Injection
Adding one time series into another on its sample grid, with support for sub-sample offsets.
alignment_tolerance(reference_time, sampling_frequency, gps_times=None)
¶
Return how far from a whole sample an offset may sit and still count as aligned.
Derived from the floating-point spacing at reference_time rather than fixed. The offset is
computed as (other_start - self_start) * sampling_frequency from two GPS-scale times, so an
exactly-aligned chunk still carries error of order spacing(epoch) * sampling_frequency: at
GPS 1.6e9 and 4096 Hz that is ~1e-3 samples, and it grows with both the epoch and the rate.
A fixed tolerance therefore cannot be right everywhere. 1e-3 covers GPS 1e9-1.8e9 at 512-16384 Hz, but at GPS 1e10 and 2000 Hz the real error reaches ~1.7e-3 -- and a tolerance below the error means genuinely aligned chunks get interpolated, which is worse than the misclassification this whole check exists to avoid. Scaling with the spacing removes the domain assumption.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
reference_time
|
float
|
Epoch the offset is measured from, in seconds. |
required |
sampling_frequency
|
float
|
Sample rate in Hz. |
required |
gps_times
|
object
|
Optional timestamps taking part in the comparison. The spacing is taken at the
largest magnitude involved, not at the epoch alone, since a time later than the epoch
has coarser resolution and it is the coarsest that bounds the error. Mirrors
|
None
|
Returns:
| Type | Description |
|---|---|
float
|
Tolerance in samples, clamped to :data: |
float
|
data: |
Source code in src/gwmock_data/injection.py
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 | |
inject(timeseries, other, interpolate_if_offset=True, *, tapered=False)
¶
Add other into timeseries where the two overlap, and return the sum.
Placement is by sample index on timeseries' grid. The offset of other's first sample is
(other.t0 - timeseries.t0) * sample_rate samples; when that is a whole number to within
:func:alignment_tolerance, the overlapping samples are added one for one. Samples of other
outside timeseries' span are not placed: those before it are lost (the caller reports them,
see :func:measure_content_before), and those after it are the caller's to carry forward.
When the offset is fractional, other is resampled onto timeseries' grid at the grid points
inside its own sample span, with the band-limited windowed-sinc kernel gwmock-signal projects
with (resample_uniform_sinc), and those are added. Positions come from integer grid indices
minus one offset rather than from per-sample GPS times, each of which carries float64 rounding
of a sizeable fraction of a sample; the indices and the offset's fraction are passed to the
kernel apart, never summed in float64, so the fraction is as precise at the end of a long target
as at its start. The whole of other is the kernel's input, so samples just
outside timeseries still give context at its edges.
The kernel alone is accurate to 0.8 x Nyquist. When other is a whole signal tapered to zero at
both ends (tapered), it is first oversampled exactly (oversample_fourier), and placed
accurately up to its own Nyquist frequency. That interpolation is global, so it is used only on
the caller's word: a chunk cut from a longer signal would ring from its cut ends across its whole
length, where the kernel alone is affected only within half its taps of them.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
timeseries
|
TimeSeries
|
The series to add into. It is not changed. |
required |
other
|
TimeSeries
|
The series to add. Same sample rate as timeseries. |
required |
interpolate_if_offset
|
bool
|
Whether to resample a fractional offset; if not, timeseries is returned unchanged. |
True
|
tapered
|
bool
|
Whether other is a whole signal that falls smoothly to zero at both ends, so it can be oversampled exactly before resampling. Leave it False for a chunk cut from a longer signal. |
False
|
Returns:
| Type | Description |
|---|---|
TimeSeries
|
A new series with timeseries' timing, name and unit, holding the sum. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the sample rates or the units are incompatible (see
:func: |
Source code in src/gwmock_data/injection.py
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 | |
is_aligned(offset_samples, tolerance)
¶
Return whether offset_samples is a whole number of samples, within tolerance.
Absolute, not relative. np.isclose's default tolerance is relative, and since a fractional
offset can never exceed 0.5 samples, a relative test passes unconditionally once
rtol * offset >= 0.5 -- about 50,000 samples, or 12 s into a segment at 4096 Hz. Beyond that
the interpolation branch was unreachable and every chunk was snapped to the nearest sample,
displacing signals by up to half a sample.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
offset_samples
|
float
|
Offset between two series' start times, in samples. |
required |
tolerance
|
float
|
Permitted deviation in samples, from :func: |
required |
Returns:
| Type | Description |
|---|---|
bool
|
Whether the offset counts as aligned. |
Source code in src/gwmock_data/injection.py
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | |
measure_content_before(segment_start_time, sampling_frequency, chunk)
¶
Measure the part of chunk lying before segment_start_time, which injection discards.
:func:inject crops a chunk to the target's span, so anything earlier is dropped. Forward
overflow is different: it is returned as a tail and carried into the next segment. Backward
overflow has nowhere to go, because the segments it belongs to have already been written.
That mattered for every compact binary landing near a boundary while segments claimed an event by
coa_time, whose inspiral precedes it. Segments now claim by where the waveform starts, so
what this measures is the residue: a waveform beginning before the run itself, or a placement
that fell back to coa_time because the pre-coalescence duration could not be established.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
segment_start_time
|
float
|
Start of the segment being injected into, in the chunk's time unit. |
required |
sampling_frequency
|
float
|
Sample rate of the segment, in Hz. |
required |
chunk
|
Any
|
The time series about to be injected. |
required |
Returns:
| Type | Description |
|---|---|
int
|
A |
float
|
|
float
|
|
tuple[int, float, float]
|
strain-squared energy, |
tuple[int, float, float]
|
matched-filter figure needs a detector PSD and frequency-domain weighting, neither of which |
tuple[int, float, float]
|
is available here. It is reported in preference to the sample fraction only because the two |
tuple[int, float, float]
|
differ by more than a factor of two in ordinary cases, and the sample fraction is the more |
tuple[int, float, float]
|
misleading of the pair. |
Source code in src/gwmock_data/injection.py
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 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | |
units_are_compatible(target_unit, other_unit)
¶
Whether samples in other_unit may be added to samples in target_unit.
Equal units are compatible, and so are any two of: no unit, "dimensionless" and "strain"
-- gwmock's segments carry no unit and the chunks injected into them carry "strain". Any other
pair is refused, as GWpy refused it, rather than summed under the target's unit: a missing unit is
not a wildcard for a dimensional one.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
target_unit
|
str | None
|
The unit of the series added into, or |
required |
other_unit
|
str | None
|
The unit of the series added, or |
required |
Returns:
| Type | Description |
|---|---|
bool
|
Whether the two may be summed. |
Source code in src/gwmock_data/injection.py
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | |