---
title: "Extract a contrast spectrum from three GPI exposures"
description: "Download exact public Beta Pictoris GPI ranges, check the headers and satellite spots, and test a sparse contrast extraction."
canonical_url: "https://sandboxphysics.com/stories/direct-imaging/betapic-gpi-tutorial/"
language: "en"
page_type: "story"
alternate_languages:
  zh-CN: "https://sandboxphysics.com/zh/stories/direct-imaging/betapic-gpi-tutorial/"
last_modified: "2026-10-28"
---

[Direct imaging, from glare to a spectrum](https://sandboxphysics.com/stories/direct-imaging/)

L3 · Direct imaging

# Extract a contrast spectrum from three GPI exposures

Sandbox Physics · 2026-10-28

Open Bonnefoy et al., Physical and orbital properties of Beta Pictoris b, arXiv:1407.4001v1, at Section 2 and Table 1. Then open the fixed source manifest below. You will work from three actual J-band exposures to a conditional channel-contrast spectrum, with the image-model failures left visible.

## Before you begin

The three preceding chapters define photon counting, ADI/SDI response and covariance. The scripts need Python and NumPy, but no private repository, pyKLIP installation or Lab Engine. The standalone download list follows the article.

## Start with the three files and the original observing night

The observations are from 10 December 2013, programme GS-ENG-GPI-COM. The fixed author-repository commit is 72a7517b1a34bdc29c33211f2ef591ddff64dcf9, contributed on 9 August 2016. Its three files end in S0092, S0099 and S0111, each followed by \_spdc\_distorcorr.fits. The files were reduced in 2016, so the observing date, later processing date and paper date describe different events.

Each original file is 14,673,600 bytes. The downloader requests exact original headers and ten selected SCI and DQ planes through anonymous HTTP ranges. It checks status 206, Content-Range, length and SHA256 for every piece. Whole-file Git blob identifiers are preserved, but a whole-file SHA256 is not claimed from partial downloads.

The ten original zero-based channel indices are 0, 4, 8, 12, 16, 20, 24, 28, 32 and 36. All three inputs remain actual observed backgrounds. Synthetic PSF injections are added only later, in explicitly separate calibration experiments.

| File number | UTSTART–UTEND on 2013-12-10 | AVPARANG / degrees |
| --- | --- | --- |
| S0092 | 05:38:15.843–05:39:48.718 | 14.9632 |
| S0099 | 05:51:16.703–05:52:48.843 | 22.3861 |
| S0111 | 06:14:45.796–06:16:19.187 | 34.6878 |

Reading: Bonnefoy et al. · Jason Wang and contributors · GPI Data Pipeline 1.4.0 data formats

## Read units and quality flags before the image

SCI has thirty-seven native wavelength planes with 281 pixels on each spatial axis. BUNIT says ADU per coadd. ITIME is 88.74219 seconds per coadd and COADDS is one. The start and end windows include overhead, so their midpoint is not automatically a charge-weighted exposure midpoint. Projection uses the CD matrix; measured AVPARANG values check the field-rotation span.

Wavelength starts at 1.11407300105 micrometres, with a native step of 0.00654594640474 micrometres and a one-based reference pixel of one. The selected channels run to 1.34972707162 micrometres. Native sampling is finer than the published resolving power of about 35–39; ten retained channels are not ten independent resolution elements.

The DQ extension carries bit flags. The default mask excludes the bad-pixel and two saturation bits. Up-the-ramp outlier-removal bits and repaired/interpolated pixels are retained unless the basic bad bit is also set. The companion validation tries the stricter policy of masking every nonzero flag and reports when a measurement loses enough valid pixels to fail.

There is no ERR extension giving a calibrated variance cube. Reprocessed ADU values should not be treated as independent Poisson electrons. The tutorial estimates a conditional spatial/spectral covariance from processed comparison patches and keeps the resulting underfit visible.

$$
\lambda_k=1.11407300105+0.00654594640474\,k\quad[\mu\mathrm m]
$$

Here k is the original zero-based channel index. Keep the original channel numbering when reading the header relation.

Reading: GPI Data Pipeline 1.4.0 data formats · Bonnefoy et al.

## Check the compass and remeasure the satellite spots

Use the two-by-two CD matrix for small sky offsets. Its column norm corresponds to 14.14 milliarcseconds per native pixel. The older CDELT values conflict with it, and the PAR\_ANG comment explicitly says to use AVPARANG. FITS CRPIX is one-based; the source reader treats PSFCENT and SATS spot locations as native zero-based coordinates.

S0099 and S0111 repeat exactly the SATS location strings and PSFCENT values. Preserve those original cards. The script independently fits the actual spot pixels with a local Gaussian plus a tilted background plane. A free iterative centroid can drift into a nearby speckle; the adopted fit searches only one pixel around the header location, rejects boundary solutions and is checked with independent empirical-PSF injections.

The independent registration test adds empirical spot shapes at known positions on other actual halo patches. Of 144 injections, 114 local fits pass and thirty fail; the accepted 95th-percentile position bias is about 0.825 pixel. Those failures and template differences limit any precision interpretation of the real spot registration.

Average the remeasured satellite positions to register each native image. Then project through the original CD matrix onto a north-up, east-left grid. The strongest middle-annulus point in the sparse reduction lies at a position angle about 212.62 degrees. The historical Table 1 value is 211.6 plus or minus 1.3 degrees. That comparison checks orientation at pixel scale. Precision astrometry for the later reduction needs its own plate-scale and north calibration.

Reading: GPI Data Pipeline 1.4.0 data formats · Jason Wang and contributors · Bonnefoy et al.

## Calibrate flux with one consistent finite template

For each exposure and channel, take small measured satellite-spot stamps, subtract local background and average their centered shapes. The template is normalized with the same three-pixel circular aperture and local background convention used for the satellite flux. The normalizing number is an integrated aperture flux; SATF header peak values are not substituted for it.

Section 2 adopts a J-band satellite-to-star magnitude difference of 9.36 with a 0.15-magnitude uncertainty. The script adopts that historical ratio as a constant common calibration across the selected reduced channels; it is not a measured precision chromatic calibration. The bare off-axis throughput lookup is not applied because its provenance and uncertainty remain unresolved. The historical magnitude error gives about fourteen percent fractional scale uncertainty and correlates all spectral channels. It is kept separate from the empirical noise covariance.

This yields a reduced-channel planet/star contrast spectrum under the adopted empirical template calibration. Obtaining absolute planet flux would additionally require a stellar spectral model and its calibration. The published paper does that with adopted stellar templates; this tutorial stops at contrast.

$$
f_{\rm spot}/f_\star=10^{-0.4\Delta m},\qquad (C_{\rm cal})_{ij}=c_ic_j(0.4\ln10\;\sigma_{\Delta m})^2
$$

The historical magnitude uncertainty multiplies the whole contrast scale. It enters all channels through one common multiplicative factor.

Reading: Bonnefoy et al. · Greco & Brandt

## Process, inject and read the actual result

The primary reduction uses the mean of all three registered frames as its angular reference. Each residual is projected through its own CD matrix before coaddition. The disclosed local region of interest uses the historical separation of 430 milliarcseconds and position angle of 211.6 degrees. This choice uses earlier knowledge of the companion position; it is not a blind discovery.

Inject an empirical point-source template into each original selected channel, run the entire subtraction and projection again, and measure all output channels. A second run adds SDI before ADI to expose spectral mixing. These deterministic injections calibrate processing on this frozen observed background; they do not create an independent photon realization.

Representative central-aperture results are listed below. Their error bars are conditional empirical noise estimates. The common magnitude calibration and the individual-spot template sensitivity are separate saved outputs. Source-photon variance cannot be reconstructed exactly from these reduced ADU without the omitted gain and raw-noise information.

| Native channel | Wavelength / micrometres | ADI contrast | Conditional noise standard error |
| --- | --- | --- | --- |
| 0 | 1.11407 | 0.0000272 | 0.00000731 |
| 16 | 1.21881 | 0.0000514 | 0.00000679 |
| 20 | 1.24499 | 0.0000671 | 0.00000694 |
| 32 | 1.32354 | 0.000105 | 0.00000549 |

Reading: Bonnefoy et al. · Pueyo · Greco & Brandt

## Keep the spatial failure beside the spectrum

Ten aperture fluxes can fit ten channel contrasts exactly. The script therefore also uses central, radial-difference and tangential-difference measurements in every channel. Forty-seven comparison patches estimate this thirty-dimensional covariance. It profiles ten contrasts over an expanded forty-nine-point position grid and twenty-four additional local refinements, keeping the measurement region and covariance fixed.

The expanded ADI profile reaches a minimum quadratic residual of about 175 for twenty residual dimensions, at an interior grid point near 430 milliarcseconds and 213.1 degrees. The ASDI profile remains much poorer, near 389, and its local refinement still reaches an edge. The simple spatial model underfits these data. Different individual satellite templates also change the extracted colors. This is a reason to retain a conditional diagnostic spectrum and seek better PSF/background modeling before fitting atmosphere parameters.

The ASDI diagnostic also leaves a negative final-channel estimate, about minus 0.00000836. It is retained. Strong changes between processing choices and empirical templates are part of the uncertainty story, even when the combined image still shows a bright point.

The available inputs are three public files, not the paper’s complete nineteen-exposure reduction. Upstream microlens spectral cross-talk and within-exposure motion are not fully reconstructed. The published analysis supplies a historical comparison and a reading target; the saved failures describe the smaller calculation actually performed here.

Reading: Bonnefoy et al. · Samland et al. · Greco & Brandt

## Run locally and retain the source attribution

Download the science-only materials below into one folder. The public package contains our scripts, the exact source-range manifest, preserved original headers and numerical results. It does not embed the GPI science or derived image pixels: a data-specific redistribution grant remains unresolved. The downloader obtains the pinned files directly from the original author’s public repository, with a named User-Agent and byte checks.

Run the commands in a clean environment. The optional local-images flag writes locally derived pixel arrays for your own inspection. Keep the source manifest next to those products and distinguish an injected calibration source from the observed companion in any figure you make.

```
            python3.12 -m venv .venv
. .venv/bin/activate
python -m pip install numpy==2.3.5
python download-gpi-ranges.py --manifest data-source-manifest.json --output gpi-cache
python reproduce-gpi.py --manifest data-source-manifest.json --cache gpi-cache --output local-results
python reproduce-gpi.py --manifest data-source-manifest.json --cache gpi-cache --output local-results --algorithm asdi
python validate-gpi-registration.py --manifest data-source-manifest.json --cache gpi-cache --output registration-validation.json
          
```

Reading: Jason Wang and contributors · GPI Data Pipeline 1.4.0 data formats

## Download and run the scientific materials

The package contains our synthetic observation, independent Python analysis, original source headers and numerical results. Observed GPI pixels come directly from the author-hosted ranges through a separate verified downloader. No private checkout or interactive Lab Engine is needed.

[Read the input, units and reproduction notes](https://sandboxphysics.com/stories/direct-imaging/materials/README-science.txt) · [Exact public file manifest](https://sandboxphysics.com/stories/direct-imaging/public-reproduction.json)

[Download the complete scientific ZIP](https://sandboxphysics.com/stories/direct-imaging/materials/direct-imaging-science.zip)

```
curl -fsS -A 'SandboxPhysics-Public-Tutorial/1.0' -o download-tutorial.py https://sandboxphysics.com/stories/direct-imaging/materials/download-tutorial.py
python3 download-tutorial.py --archive --output direct-imaging-tutorial
cd direct-imaging-tutorial
python3.12 -m venv .venv
. .venv/bin/activate
python -m pip install numpy==2.3.5
python verify-public-inputs.py .
python reproduce-synthetic.py --materials .
python download-gpi-ranges.py --manifest data-source-manifest.json --output gpi-cache
python reproduce-gpi.py --manifest data-source-manifest.json --cache gpi-cache --output local-results
```

Individual files and SHA256 checks

- [download-gpi-ranges.py](https://sandboxphysics.com/stories/direct-imaging/materials/download-gpi-ranges.py)

  text/x-python; charset=utf-8 · 3,737 bytes

  `e9e1d5d1ab9ec7d4a0fe01d8edb46ac4c5fb1492e7b49143d6f25090e3501a41`

- [download-tutorial.py](https://sandboxphysics.com/stories/direct-imaging/materials/download-tutorial.py)

  text/x-python; charset=utf-8 · 4,505 bytes

  `037cc5f7a6b38f704b9428024fde72cefd21d4cc3ecb4b8dda9b4a127c83fd6c`

- [focal\_mask.py](https://sandboxphysics.com/stories/direct-imaging/materials/focal_mask.py)

  text/x-python; charset=utf-8 · 1,867 bytes

  `e2828e2ef4b8c06452ba7a8a92cdc0fbbade9e720e85c89c157e7da9cc309812`

- [gpi\_data.py](https://sandboxphysics.com/stories/direct-imaging/materials/gpi_data.py)

  text/x-python; charset=utf-8 · 3,856 bytes

  `084026cc3b261b3ac0a8051d7228cc806751a8f0c9e650d103ce6477962445d7`

- [gpi\_reduction.py](https://sandboxphysics.com/stories/direct-imaging/materials/gpi_reduction.py)

  text/x-python; charset=utf-8 · 7,899 bytes

  `e08394023446afdc9d77fcbcc630ba163b7d7a8144258b2d3bc7ebe901c0924f`

- [gpi\_profile.py](https://sandboxphysics.com/stories/direct-imaging/materials/gpi_profile.py)

  text/x-python; charset=utf-8 · 2,820 bytes

  `7f74644fab759a8564dbbd6b6100d7e2275a1aba14edc5078580ecf270342ea5`

- [image\_tools.py](https://sandboxphysics.com/stories/direct-imaging/materials/image_tools.py)

  text/x-python; charset=utf-8 · 5,753 bytes

  `a7e21790880381c5830875764f9ce6a61b1030bfa80ebbda0fae5b5808dc7f27`

- [imaging\_reduction.py](https://sandboxphysics.com/stories/direct-imaging/materials/imaging_reduction.py)

  text/x-python; charset=utf-8 · 6,877 bytes

  `25ede33dc67445032b50fa96d599167c9661156aac0e14eeaee38365fc7134a2`

- [negative\_injection.py](https://sandboxphysics.com/stories/direct-imaging/materials/negative_injection.py)

  text/x-python; charset=utf-8 · 2,767 bytes

  `8067b1f877ceb474a5f6ea2dfb065baf09bbcc9ed0a15c42772d645aa0f697da`

- [noise\_covariance.py](https://sandboxphysics.com/stories/direct-imaging/materials/noise_covariance.py)

  text/x-python; charset=utf-8 · 5,061 bytes

  `a4b0e8c9acb6fa039e4b876a13a61b3da928fc7bfe161e01bb6522ba9010e71c`

- [plot-synthetic.py](https://sandboxphysics.com/stories/direct-imaging/materials/plot-synthetic.py)

  text/x-python; charset=utf-8 · 4,621 bytes

  `d5ce82a1f7bebf004bcabbe97229521e85084a9d2efe78f806ab8f592ec0e681`

- [reproduce-gpi.py](https://sandboxphysics.com/stories/direct-imaging/materials/reproduce-gpi.py)

  text/x-python; charset=utf-8 · 7,024 bytes

  `331120d2bb3c5e4c801a19761c9e488f3f4933262064513b914acec169b10324`

- [reproduce-synthetic.py](https://sandboxphysics.com/stories/direct-imaging/materials/reproduce-synthetic.py)

  text/x-python; charset=utf-8 · 5,506 bytes

  `70c71608d982cef95e4053352138b5fdf03851e4b9ceb3a463f7cfb40a699ead`

- [synthetic\_optics.py](https://sandboxphysics.com/stories/direct-imaging/materials/synthetic_optics.py)

  text/x-python; charset=utf-8 · 5,860 bytes

  `aba9822dd7b10b3c138499048b8564f16b42d3d999e266075c73d275d48ff789`

- [validate-blind-search.py](https://sandboxphysics.com/stories/direct-imaging/materials/validate-blind-search.py)

  text/x-python; charset=utf-8 · 4,829 bytes

  `e64d89e0b91b56ea9bfa415fde031adbcd8471aa51fbd6bb68962a7a400e36b7`

- [validate-band-pixels.py](https://sandboxphysics.com/stories/direct-imaging/materials/validate-band-pixels.py)

  text/x-python; charset=utf-8 · 2,452 bytes

  `47c352509c663a7d846196ff2448e030e5f1552908e58fc41d1b5a7dfb64cfdb`

- [validate-extraction-grid.py](https://sandboxphysics.com/stories/direct-imaging/materials/validate-extraction-grid.py)

  text/x-python; charset=utf-8 · 3,078 bytes

  `848ad4763b960a6584c2e620e94871ef3bbed8f253e49c6ce3ff3629bfa5f3b7`

- [validate-gpi-registration.py](https://sandboxphysics.com/stories/direct-imaging/materials/validate-gpi-registration.py)

  text/x-python; charset=utf-8 · 5,147 bytes

  `3273e092f4110580ed1fd6a83a3487ad91bd985bc83f970c5e695f88796ec099`

- [validate-noise-coverage.py](https://sandboxphysics.com/stories/direct-imaging/materials/validate-noise-coverage.py)

  text/x-python; charset=utf-8 · 9,078 bytes

  `37a8d85a5be90c2fb1926d46db44b4f2c9ef3099315c5e0ce59a6a3a97d03c25`

- [validate-optical-grids.py](https://sandboxphysics.com/stories/direct-imaging/materials/validate-optical-grids.py)

  text/x-python; charset=utf-8 · 4,681 bytes

  `d36c02d1018542a3affaee7e5b1cfc0ed24c1dce5de6a860cd2608c47cc4e0ec`

- [validate-response-recovery.py](https://sandboxphysics.com/stories/direct-imaging/materials/validate-response-recovery.py)

  text/x-python; charset=utf-8 · 5,334 bytes

  `96436e8e3cb943dfe428bb46bd8fb80de5d7b724bfd29207746296efc8b0b904`

- [validate-supported-optics.py](https://sandboxphysics.com/stories/direct-imaging/materials/validate-supported-optics.py)

  text/x-python; charset=utf-8 · 2,551 bytes

  `c612ae523c4003efc96fc61f5609573c68b9f0d6b8765b4b09819674ca57c034`

- [verify-small-sample.py](https://sandboxphysics.com/stories/direct-imaging/materials/verify-small-sample.py)

  text/x-python; charset=utf-8 · 1,342 bytes

  `160108d181ef96aeff595a80688fed7b39b029648bb7d106522126a2dbab3b05`

- [verify-public-inputs.py](https://sandboxphysics.com/stories/direct-imaging/materials/verify-public-inputs.py)

  text/x-python; charset=utf-8 · 753 bytes

  `d15820342daa54f854137f10ebdc8117371df722e042c7d82154a47be4e99784`

- [run-noise-validations.py](https://sandboxphysics.com/stories/direct-imaging/materials/run-noise-validations.py)

  text/x-python; charset=utf-8 · 1,730 bytes

  `9f091218bb003bb2aa891c04de71d32864491ff7d77252e81a3e1701169df8e2`

- [data-source-manifest.json](https://sandboxphysics.com/stories/direct-imaging/materials/data-source-manifest.json)

  application/json; charset=utf-8 · 21,913 bytes

  `8a338668d02bd7388180e23baa68c32eb7f0d364af12ea5cf1151475a0eeee0c`

- [paper-hashes.json](https://sandboxphysics.com/stories/direct-imaging/materials/paper-hashes.json)

  application/json; charset=utf-8 · 1,571 bytes

  `5ee504d62684bd81d2709da2c45be4fd23271a1b25d847b2461a2f8100c4f8d5`

- [small-sample-reference.json](https://sandboxphysics.com/stories/direct-imaging/materials/small-sample-reference.json)

  application/json; charset=utf-8 · 488 bytes

  `5747d7e16ca8cd203a201209f3c4211e3b790b0b51f2c6bb636d2b266d18093a`

- [README-science.txt](https://sandboxphysics.com/stories/direct-imaging/materials/README-science.txt)

  text/plain; charset=utf-8 · 10,042 bytes

  `63fcae8bf0687d8bf699fc8a456469cd7d083cf8a3033469eeed21da7791d33c`

- [source-BSD-3-Clause.txt](https://sandboxphysics.com/stories/direct-imaging/materials/source-BSD-3-Clause.txt)

  text/plain; charset=utf-8 · 1,493 bytes

  `54a4f2a1c0068f9efa2d00d7bf7c6488beb2a308271ad714173f39c89c378a22`

- [asdi-response.json](https://sandboxphysics.com/stories/direct-imaging/materials/asdi-response.json)

  application/json; charset=utf-8 · 1,762 bytes

  `4bb988464a28b9c20d25713b77eafa01d99d712b5a7571619e72efc34f985be0`

- [band-pixel-validation.json](https://sandboxphysics.com/stories/direct-imaging/materials/band-pixel-validation.json)

  application/json; charset=utf-8 · 10,743 bytes

  `ff9d1e63dd542ef1e4914b39ebace21b23e6efe64ea30ae620dde319c9a9588e`

- [blind-null.json](https://sandboxphysics.com/stories/direct-imaging/materials/blind-null.json)

  application/json; charset=utf-8 · 14,390 bytes

  `d610a85c4f3aef16ca3fe1194aee78550e00232db6dca3e3d203cb99aa1c86f2`

- [close-summary.json](https://sandboxphysics.com/stories/direct-imaging/materials/close-summary.json)

  application/json; charset=utf-8 · 3,918 bytes

  `ce94f39a1408d652f87f90ff4ad1906b8785b75f59ae4b73b8ed0ec2052c8a44`

- [extraction-grid.json](https://sandboxphysics.com/stories/direct-imaging/materials/extraction-grid.json)

  application/json; charset=utf-8 · 2,571 bytes

  `5f1ccdbe8c14b82f7e85a1f65084fa115d24d45af62c0e6202365edcca7c817d`

- [independent-reproduction.json](https://sandboxphysics.com/stories/direct-imaging/materials/independent-reproduction.json)

  application/json; charset=utf-8 · 4,852 bytes

  `d4f0720ed8997bf3064d39d2c0084513b246d69dfd31859ac1ebc257b6ff4994`

- [noise-coverage-adi.json](https://sandboxphysics.com/stories/direct-imaging/materials/noise-coverage-adi.json)

  application/json; charset=utf-8 · 89,253 bytes

  `f61c912139c9022facafa9523c75359f0857a43690d4dd6e272fb88053276eeb`

- [noise-coverage-asdi.json](https://sandboxphysics.com/stories/direct-imaging/materials/noise-coverage-asdi.json)

  application/json; charset=utf-8 · 90,344 bytes

  `1fecaef871c736ee3f421440b1d2c29b8b5dce635d3efcf8537c69096f340081`

- [noise-coverage-klip.json](https://sandboxphysics.com/stories/direct-imaging/materials/noise-coverage-klip.json)

  application/json; charset=utf-8 · 40,551 bytes

  `ded4655281ee9624c5c448540dbe31c88bc267ccce6ae868c0a9aa93008f5aca`

- [optical-convergence.json](https://sandboxphysics.com/stories/direct-imaging/materials/optical-convergence.json)

  application/json; charset=utf-8 · 14,570 bytes

  `5e8d68f6f85d2138c458a9dd3abe8700a0931b91e3ce59b351a48e72f32adf97`

- [optical-reference.json](https://sandboxphysics.com/stories/direct-imaging/materials/optical-reference.json)

  application/json; charset=utf-8 · 22,360 bytes

  `9206a44c0e266e2aabc1a342a7f5a8a53fb2e481ee5f7bbfd0cead1016de5cd6`

- [position-profile.json](https://sandboxphysics.com/stories/direct-imaging/materials/position-profile.json)

  application/json; charset=utf-8 · 12,024 bytes

  `fba6c7ddc009d2e7f95376d381ed781af9ee75ddce1a98797f0ba0aa9b237f47`

- [response-validation.json](https://sandboxphysics.com/stories/direct-imaging/materials/response-validation.json)

  application/json; charset=utf-8 · 4,190 bytes

  `b27ab646f026fb461297f20d5784897ec349211655559cf231350cced4d7ff56`

- [speckles-summary.json](https://sandboxphysics.com/stories/direct-imaging/materials/speckles-summary.json)

  application/json; charset=utf-8 · 6,389 bytes

  `57c6ae1ee6da078f2e3a862bb56a3cac746c9df8852de8f0a302898453549d45`

- [stays-summary.json](https://sandboxphysics.com/stories/direct-imaging/materials/stays-summary.json)

  application/json; charset=utf-8 · 6,394 bytes

  `db89be752a99e258d1d3566ab52c18fbbade96e04b8d897d61de75f11d5e13b9`

- [supported-optics.json](https://sandboxphysics.com/stories/direct-imaging/materials/supported-optics.json)

  application/json; charset=utf-8 · 84,206 bytes

  `5f6e81d795a2e4e432858d5a6e0e6fdb3e5d40ad063eb89fcaf6a375d317f946`

- [synthetic-input.json](https://sandboxphysics.com/stories/direct-imaging/materials/synthetic-input.json)

  application/json; charset=utf-8 · 1,492 bytes

  `131b5aa2bc87420ef8ed2402826491d9f446e3a984a9138faf570f1399825ec2`

- [turns-summary.json](https://sandboxphysics.com/stories/direct-imaging/materials/turns-summary.json)

  application/json; charset=utf-8 · 6,399 bytes

  `c3ea00f8b973e964538925505b4390dd3766b0e1b340db9047ca6153278b9289`

- [synthetic-observation.npz](https://sandboxphysics.com/stories/direct-imaging/materials/synthetic-observation.npz)

  application/octet-stream · 8,750,537 bytes

  `1a07d059256064fd191babf72653c83ee4a934d49b7e1c7951105fe70d1984b5`

- [gpi-adi-results.json](https://sandboxphysics.com/stories/direct-imaging/materials/gpi-adi-results.json)

  application/json; charset=utf-8 · 85,320 bytes

  `6c4ceb2eb87964e6f3c6b474f980d613de1bfd8cb97c12e2b4751bac2af0835c`

- [gpi-asdi-results.json](https://sandboxphysics.com/stories/direct-imaging/materials/gpi-asdi-results.json)

  application/json; charset=utf-8 · 86,841 bytes

  `b796c236c0c70db41efb58915a517020278777a5c1e35a83284d4a25f3b00e78`

- [registration-validation.json](https://sandboxphysics.com/stories/direct-imaging/materials/registration-validation.json)

  application/json; charset=utf-8 · 56,343 bytes

  `30d6a6c5e33ec60314a9ebea505945e7960c95b4facbadead13fcf494088239b`

- [gpi0092-original-headers.bin](https://sandboxphysics.com/stories/direct-imaging/materials/gpi0092-original-headers.bin)

  application/octet-stream · 57,600 bytes

  `9301a7a8e7f646dc9c39b0063eedffe8518c5d7193f41b002f6242662298b88f`

- [gpi0092-dq-header.bin](https://sandboxphysics.com/stories/direct-imaging/materials/gpi0092-dq-header.bin)

  application/octet-stream · 5,760 bytes

  `ac9afde0cc370587bf991a4757497c0a074da689f1725ff0f88659c833c120d4`

- [gpi0099-original-headers.bin](https://sandboxphysics.com/stories/direct-imaging/materials/gpi0099-original-headers.bin)

  application/octet-stream · 57,600 bytes

  `178d18ede9bf6b2b03e60ca1a11220d07db24b6c0c26e37eaeb9390d0b46d2a3`

- [gpi0099-dq-header.bin](https://sandboxphysics.com/stories/direct-imaging/materials/gpi0099-dq-header.bin)

  application/octet-stream · 5,760 bytes

  `5ad44224eefbf4107b1be8ef5830444a2bc216441b175058636eca113023c7be`

- [gpi0111-original-headers.bin](https://sandboxphysics.com/stories/direct-imaging/materials/gpi0111-original-headers.bin)

  application/octet-stream · 57,600 bytes

  `e2ffa3eaa6626ea6ad2573d727225b10992f3c157c54a2049afc44fd56582f7a`

- [gpi0111-dq-header.bin](https://sandboxphysics.com/stories/direct-imaging/materials/gpi0111-dq-header.bin)

  application/octet-stream · 5,760 bytes

  `f71d62b03cca1b756d70dfec8875bdb959d797e359b860191bf700da71f7e452`

- [spectral-response.svg](https://sandboxphysics.com/stories/direct-imaging/materials/spectral-response.svg)

  image/svg+xml · 51,023 bytes

  `5b19b387dca5c72f6cfe2516f962dac9d1f8a5919fd8f691716e598557bc2517`

- [synthetic-processing.svg](https://sandboxphysics.com/stories/direct-imaging/materials/synthetic-processing.svg)

  image/svg+xml · 138,433 bytes

  `745bced94f54b8d27c11a905e70fe90879659fa9f517c0b5bf404e3ea60d2e15`

- [synthetic-spectrum.svg](https://sandboxphysics.com/stories/direct-imaging/materials/synthetic-spectrum.svg)

  image/svg+xml · 35,680 bytes

  `c0173b4d2927f8ee4307f85dd28ff6fe778492a0d0029a36a3c36ad0604fe051`

- [hashes.json](https://sandboxphysics.com/stories/direct-imaging/materials/hashes.json)

  application/json; charset=utf-8 · 9,714 bytes

  `7c1743ed3dc4a803e9428398089fef40b4237ad6c34eee5fc1cab5ace41aa182`

- [direct-imaging-science.zip](https://sandboxphysics.com/stories/direct-imaging/materials/direct-imaging-science.zip)

  application/zip · 9,064,709 bytes

  `520ff132f51a8c7f2de47854b838d0cb6dbb27459aaf73782dab892f881850e3`

## Try the observation

### [Rehearse the calibration with known synthetic input](https://sandboxphysics.com/labs/pupil-engineering-coronagraph/)

1. Use the default synthetic acquisition to identify the direct and off-diagonal spectral responses.
2. Compare with the real tutorial’s reduced-channel response and its much sparser rotation sequence.
3. Use the deceptive-halo preset to explain why a bright local feature or a nominal statistic is insufficient for an atmospheric interpretation.

## Exercises and explained answers

The selected channel at array position five has original index twenty. Which wavelength should it use?

Use $k=20$ in the original header relation to obtain about 1.24499 micrometres. Using five would assign the wrong wavelength and corrupt both SDI geometry and the spectrum axis.

Why can a ten-channel aperture fit look exact while the spatial fit fails?

The aperture solve has ten freely varying contrasts for ten measurements. The thirty-dimensional spatial fit also tests where the light is and how the PSF looks. Its large residual quantifies image-shape disagreement left unexamined by the total aperture flux.

[Previous: Recover a spectrum without losing its uncertainty](https://sandboxphysics.com/stories/direct-imaging/recovering-a-coupled-spectrum/) [Next: Read the papers that separate speckles from companions](https://sandboxphysics.com/stories/direct-imaging/reading-speckles-and-wavefront-control/)

## Sources and calculation scope

1. [Pueyo, Detection and Characterization of Exoplanets Using Projections on Karhunen–Loève Eigenimages (2016)](https://arxiv.org/abs/1604.06097v1)

   Fixed v1, Sections 2.1–2.5, 3.1–3.3 and 4.1–4.2; Appendix E, Equations E18/E20, and Appendix F, Equations F8–F12. Source contamination changes the reference basis. The illustrative J-band spectra use synthetic injections.

2. [Greco & Brandt, The Measurement, Treatment, and Impact of Spectral Covariance and Bayesian Priors in Integral-Field Spectroscopy of Exoplanets (2016)](https://arxiv.org/abs/1602.00691v1)

   Fixed v1, Section 2, Equations 1–6; Sections 3.1–3.2, Equations 7–8. Spectral covariance changes the weighting of broad spectral structures.

3. [Bonnefoy et al., Physical and orbital properties of beta Pictoris b (2014)](https://arxiv.org/abs/1407.4001v1)

   Fixed v1, Section 2 and Table 1. Nineteen J-band exposures, satellite-spot calibration and the adopted stellar spectrum belong to the published analysis; the tutorial selects three later-reduced public cubes.

4. [GPI Data Pipeline 1.4.0 data formats](https://docs.planetimager.org/pipeline/ifs/dataformats.html)

   SCI/DQ extensions, quality-bit definitions, coordinates and exposure metadata. Raw cards are preserved; old CDELT values and the explicitly inaccurate PAR\_ANG card are not used for sky orientation.

5. [Jason Wang and contributors, original public GPI data commit](https://github.com/semaphoreP/pyklip/tree/72a7517b1a34bdc29c33211f2ef591ddff64dcf9/tests/data)

   Pinned author-repository commit from 9 August 2016. S20131210S0092, S0099 and S0111; exact SCI/DQ ranges and original headers have SHA256 checks. Software BSD licensing does not establish a data-specific redistribution grant.

6. [Samland et al., Spectral cube extraction for the VLT/SPHERE IFS (2022)](https://arxiv.org/abs/2210.06390v1)

   Fixed v1, Sections 3.4, 4.2–4.3, 4.6, 5.2–5.3 and 6. Raw-detector PSFlet fitting and spectral cross-talk occur upstream of the already-reduced GPI cubes used here.
