Application: X-ray Burst Timing

import numpy as np
import matplotlib.pyplot as plt

Application: X-ray Burst Timing#

The Rossi X-ray Timing Explorer (RXTE) has very high time resolution and has been used to observe a large number of X-ray sources. We’ll look at the data from the low-mass X-ray binary 4U 1728-34—this is an X-ray burst system.

In Strohmayer et al. 1996 it was shown that the neutron star spin rate can be seen in the Fourier transform of the lightcurve of the burst. Here we repeat the analysis.

We thank Tod Strohmayer for sharing the data from that paper. : 4u1728_burstdata.txt

We’ll read in the data—although it is stored in a multidimensional fashion in the file, it is actually a time-series, so we’ll flatten the data into a 1-d array.

data = np.loadtxt("4u1728_burstdata.txt").flatten()
N = len(data)
N
262144

We can start out by plotting all of the data.

fig, ax = plt.subplots()
ax.plot(data)
[<matplotlib.lines.Line2D at 0x7fdd2c602aa0>]
../_images/4c7dcb0b6d7883b75d4971e7569f8506247a0c08cf28a135ab4f3b73c0f5f25e.png

We’ll bin the data into fewer samples to build up the signal to noise. We can do this by reshaping it into a 2-d array and then summing over the columns.

binned_data = data.reshape(N // 256, 256).sum(axis=1)
fig, ax = plt.subplots()
ax.plot(binned_data)
[<matplotlib.lines.Line2D at 0x7fdd2c6f79a0>]
../_images/4089e64138e45688f9c9be091786175c0eea54bcec566279f1580dc707901967.png

Now we see a much clearer X-ray lightcurve.

Next we want to take the FFT and look to see if there are any interesting frequencies with a lot of power

c_k = np.fft.rfft(data)

We want to get the physical frequencies corresponding to the Fourier coefficients

T = 32.0
kfreq = np.fft.rfftfreq(N) * N / T

Now we can plot the power spectrum. We normalize by \(2/N\)

fig, ax = plt.subplots()
ax.plot(kfreq, np.abs(c_k)**2 * 2 / N)

ax.set_xscale("log")
ax.set_yscale("log")
../_images/a3bbcd09da5a2fff4e1159cf3e1e23e142295f2da438f028b9bf35aa80aca15a.png

Here we see a signal around 300 Hz. We’ll bin the Fourier data to increase the signal to noise

c_k_binned = np.abs(c_k[1:]).reshape(int(len(c_k)/8), 8).mean(axis=1)
kfreq_binned = kfreq[1:].reshape(int(len(kfreq)/8), 8).mean(axis=1)
fig, ax = plt.subplots()
ax.plot(kfreq_binned, c_k_binned**2 * 2 / N)

ax.set_xlim(345, 380)
ax.set_ylim(0, 20)
(0.0, 20.0)
../_images/cf617f67cf65ffd344d076a67ece03e13bdc12a8959d8bb63e63054551b5d756.png

Now we see the strong signal at around 363 Hz—this is the same frequency identified as the neutron star rotation rate in the original paper.