Exploring spatial and temporal filtering
This example will walk through a more advanced reduction exploiting geometric and temporal filtering techniques.
Setup
Let's begin by importing the necessary libraries. You may need to add these packages if they are not already on your system.
(@v1.5) pkg> add HCIDatasets Plots
In addition, a Project.toml
file exists in the examples/ folder with the necessary dependencies. Start the REPL in the base ADI.jl folder, then from Pkg mode
(@v1.5) pkg> activate examples
(examples) pkg> instantiate
julia> include("examples/geometries.jl")
using ADI
using HCIDatasets: HR8799
using Plots
# set up plotting
function imshow(img; kwargs...)
xs, ys = axes(img)
heatmap(xs, ys, transpose(img); aspect_ratio=1,
xlim=extrema(xs), ylim=extrema(ys), kwargs...)
end;
Initial Reduction
First, lets load the data and do some initial reductions
cube, angles = HR8799[:cube, :pa]
fwhm = 8.2
name = "PCA(10) - Full Frame"
res = PCA(10)(cube, angles)
results = Dict(name => res)
imshow(res, title=name)
The four companions (HR8799b,c,d, and e) should be evident in this residual.
Geometric Filtering
Geometric filtering is the process of using sub-region(s) in each frame to use as the target and reference libraries. Geometric filtering is useful to select pixels with similar noise distributions, such as an annulus, as well as to reduce the total number of pixels, increasing runtime performance.
For our example, lets start by looking at annuli for each companion and optimizing the number of principal components. We can use AnnulusView
to wrap cube
and filter the input. AnnulusView
works by calculating the indices for a single annulus and creates a view into cube
with those indices. It does not copy any data, and lets us access only the pixels within the annulus.
av = AnnulusView(cube; inner=31, outer=51)
imshow(av[:, :, 1], xlim=(198, 304), ylim=(198, 304))
because this annulus should have similar noise characteristics, we can automatically choose the number of components by trying to minimize the noise in the residual frame. The algorithm will increase ncomps
until the noise does not improve by at least noise_error
.
alg = PCA(:noise, noise_error=25)
res_e = alg(av, angles)
imshow(res_e, title="PCA - HR8799e", xlim=(198, 304), ylim=(198, 304))
av = AnnulusView(cube; inner=57, outer=77)
res_d = alg(av, angles)
imshow(res_d, title="PCA - HR8799d", xlim=(170, 332), ylim=(170, 332))
av = AnnulusView(cube; inner=86, outer=106)
res_c = alg(av, angles)
imshow(res_c, title="PCA - HR8799c", xlim=(142, 360), ylim=(142, 360))
av = AnnulusView(cube; inner=163, outer=183)
res_b = alg(av, angles)
imshow(res_b, title="PCA - HR8799b", xlim=(57, 445), ylim=(57, 445))
combined_res = sum([res_e, res_d, res_c, res_b])
imshow(combined_res, title="PCA - Annular", xlim=(57, 445), ylim=(57, 445))
Handling multiple annuli
Instead of doing each annulus by hand, we can use MultiAnnulusView
to assemble the annuli
width = 20
radii = [41, 67, 96, 173]
mav = MultiAnnulusView(cube, width, radii);
res = alg(mav, angles)
name = "PCA(noise_error=25) - Annular"
push!(results, name => res)
imshow(res, title=name, xlim=(57, 445), ylim=(57, 445))
When reducing MultiAnnulusView
, we can specify a separate algorithm for each annulus, and even combine that with Framewise
algs = [PCA(6), PCA(5), PCA(5), PCA(3)]
res = process(algs, mav, angles)
name = "PCA([6, 5, 5, 3]) - Annular"
push!(results, name => res)
imshow(res, title=name, xlim=(57, 445), ylim=(57, 445))
Framewise reduction and temporal filtering
As pointed out in Marois et al. 2006, we can filter the reference data in the time domain by rejecting frames which have not rotated a sufficient amount. In order to enable this, we have to fit each frame in the target data cube separately, since we calculate the frames to reject for each of them. We call this process framewise reduction, which is enabled by wrapping an algorithm in Framewise
.
By default, Framewise
will reject frames which have not rotated at least 1 FWHM, set by the delta_rot
keyword argument.
fr_alg = Framewise(algs, delta_rot=1)
res = fr_alg(mav, angles; fwhm=fwhm)
name = "PCA([6, 5, 5, 3]) - Annular\n(delta_rot=1)"
push!(results, name => res)
imshow(res, title=name, xlim=(57, 445), ylim=(57, 445))
According to Absil et al. 2013, a slightly better contrast can be reached for the innermost annuli if we consider a delta_rot
as small as 0.1 FWHM. This is because at very small separation, the effect of speckle correlation is more significant than self-subtraction.
We can set delta_rot
as a tuple or vector to use varying parallactic angle thresholds for each annulus.
fr_alg = Framewise(algs, delta_rot=(0.1, 1))
res = fr_alg(mav, angles; fwhm=fwhm)
name = "PCA([6, 5, 5, 3]) - Annular\n(delta_rot=(0.1, 1))"
push!(results, name => res)
imshow(res, title=name, xlim=(57, 445), ylim=(57, 445))
We can also limit the number of frames used in the reference library, I.E. the k
nearest frames. For example, to recreate the algorithm derived in § 5.2 of Marois et al. 2006, which uses the 4 closest frames (which have rotated at least 1.5 FWHM) to construct the reference library.
# subtract median frame
resid_cube = subtract(Classic(), cube)
# form annuli
mav = MultiAnnulusView(resid_cube, width, radii)
# 1.5 FWHM rotation, keep closest 4 frames
fr_alg = Framewise(Classic(), delta_rot=1.5, limit=4)
res = fr_alg(mav, angles; fwhm=fwhm)
name = "Classic - Annular\n(delta_rot=1.5, limit=4)"
push!(results, name => res)
imshow(res, title=name, xlim=(57, 445), ylim=(57, 445))
Gallery of results
p = plot(layout=(2, 3), ticks=false, xlim=(57, 445), ylim=(57, 445),
aspect_ratio=1, size=(800, 400), titlefontsize=9)
for (i, (name, res)) in enumerate(results)
heatmap!(transpose(res); title=name, sp=i)
end
S/N maps
For comparing reductions, we'll use signal-to-noise ratio (S/N, SNR) of the residual frame. All the frames below are shown on the same color scale, from S/N=0 to 13.
p = plot(layout=(2, 3), size=(800, 550), clim=(0, 13),
cbar=false, ticks=false, aspect_ratio=1, xlim=(57, 445),
ylim=(57, 445), titlefontsize=9)
for (i, (name, res)) in enumerate(results)
sn = detectionmap(res, fwhm)
heatmap!(transpose(sn); title=name, sp=i)
end
This page was generated using Literate.jl.