Recompute HERA's upper limits and compare a model through its window
Sandbox Physics ·
With one short Python script and the public HERA Phase I files you can rebuild all seven Field 1 upper limits between k=0.19 and 0.58hMpc−1, digit for digit, and then compare two model histories with them the way the paper says a model should be compared: through the window functions. This guide gives the files, the command, the expected output and five mistakes that change the answer.
You should know what a bandpower, a window function and the rule U=max(Δ^2,0)+2σ are. The chapter turning delay power into a bandpower explains them.
The files and what each one is
All files are in one folder and can be downloaded individually.
Table 5.1 The tutorial files, their content and their label.
The extract comes from the three UVPSpec files in the HERA Collaboration's public release, HERA_2021_pspec_data.zip, retrieved on 12 November 2026 with SHA-256 1c98d163...388d2c. The paper states that the data behind its Tables 3 and 4 and Figures 17 and 18 are public. HERA Collaboration 2022, Data section The release page names no licence, so the extract is shared for teaching and verification with a request to cite the paper. The extraction script that reads the HDF5 files with h5py and numpy is kept in this site's source repository. It writes out the delay-to-k conversion from hera_pspec at the git hash recorded in the files. hera_pspec conversions.py
The model file is not a HERA product and was not fitted to HERA data. It is the Lab's linear prediction Δ212=Tˉb2(1+μ2)2Δm2 with μ=1, an Eisenstein-Hu no-wiggle transfer function and Planck 2018 parameters. Eisenstein and Hu 1998 The heated history has Tˉb=16.2mK at z=7.93, the cold one −221mK.
Then compare my-output.json with expected-output.json. The only field allowed to differ is the Python version. The reference run used Python 3.9.6; the model file was exported with Node v26.11.1.
The script stops with an error when a window row's sum differs from one by more than 10−6, or when the model grid differs from the window grid.
Step 1: rebuild the limits
The files hold bandpowers on a grid of Δk=0.064hMpc−1. HERA's public notebook recommends either the single lowest limit in each band or every other bin, because neighbouring bins are correlated. The script takes every other bin, starting at 0.256 in Band 1 and 0.192 in Band 2 as the notebook does. HERA Public Data Release 1, notebook
Table 5.2 Field 1 bandpowers, errors and upper limits rebuilt from the public files.
Band, redshift
k
Δ^2
σ
U
U
1, z=10.4
0.256
1708.7
3729.0
9166.8
95.74
1, z=10.4
0.384
6829.8
12467.4
31764.6
178.23
1, z=10.4
0.512
27953.9
29918.7
87791.2
296.30
2, z=7.9
0.192
211.7
367.3
946.4
30.76
2, z=7.9
0.320
−516.0
1229.8
2459.7
49.60
2, z=7.9
0.448
5974.1
3441.1
12856.3
113.39
2, z=7.9
0.576
7409.6
7373.1
22155.8
148.85
Powers are in mK2 and U in mK. The two headline limits, (95.74)2 at z=10.4 and (30.76)2 at z=7.9, are the values printed in the paper. HERA Collaboration 2022, §4.4 Reproducing them exactly checks both the extract and the rule.
Step 2: pass the models through the windows
For each kept bin the script multiplies the model on HERA's full window grid by that bin's window row and sums. It also reports the model at the bin centre, so you can see how much the window matters. At z=7.9 the cold history exceeds the limit in the first two bins, by factors 3.13 and 2.06. The heated history stays below 0.017 of every limit. At z=10.4 neither history is excluded.
What this does and does not show: a density-only model of fully coupled, unheated gas at z=7.9 is ruled out by HERA's Field 1 data. It says nothing about models with strong spin-temperature or ionization fluctuations, which this model leaves out.
Five mistakes that change the answer
The script computes each of these on purpose and writes it next to the correct value.
Keeping a negative estimate. At k=0.320 the estimate is −516.0. Adding 2σ to it gives 1943.7 instead of 2459.7mK2, a limit 21 % tighter than the data support.
Using 1σ. At k=0.192 the limit drops from 946.4 to 579.0mK2. That is no longer a 95 % limit.
Skipping the window. At k=0.192 the cold model is 2893 at the bin centre and 2964mK2 through the window; the heated model is 15.49 against 15.87. Small here, but it biases every comparison in the same direction.
Converting h twice. HERA's k is already in hMpc−1. Dividing it by h=0.6736 again moves every point to 1.48 times larger k, and the windowed cold model at 0.192 rises from 2964 to 4604mK2, 55 % too high.
Treating every native bin as independent. The extract carries the covariance between neighbouring bins. Their correlation coefficient is 0.25 to 0.31 in Band 2 and 0.32 to 0.33 in Band 1. Combining all seven native bins as if independent would overstate how much the data constrain.
Units, conventions and limits of this check
The k values in the files use HERA's cosmology, with H0=67.27kms−1Mpc−1. HERA Collaboration 2022, §4 The model uses Planck 2018, h=0.6736. The 0.13 % difference in h moves a model point by far less than the window width of 0.031hMpc−1, so it is ignored here and recorded in the manifest.
The estimates are the real part of the cross-power spectrum, in mK2. The errors are the square root of the covariance diagonal stored in the file; because the seven limits match the paper, these are the error bars behind its Tables 3 and 4. The extract also holds Fields 2 and 3; the comparison uses Field 1 only, as the paper's headline limits do. This is not a likelihood analysis. A proper constraint would treat the correlated limits in a statistical model.
Checklist
Check the SHA-256 of each file against MANIFEST.json before running.
Run with python3 -I and compare your output with expected-output.json.
Confirm the seven limits, and especially the two headline values, against the paper.
Keep negative estimates at zero, add 2σ, and use every other bin.
Pass models through the window rows and keep k in hMpc−1 once.
Label HERA numbers as real observation and model numbers as ideal reference wherever you plot them.