File: trace.rst

package info (click to toggle)
specreduce 1.8.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 12,632 kB
  • sloc: python: 5,094; makefile: 109
file content (169 lines) | stat: -rw-r--r-- 5,946 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
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
.. _tracing:

Tracing
=======

The `specreduce.tracing` module provides three ``Trace`` classes that are used to define the
spatial position (trace) of a spectrum across a 2D detector image: `~specreduce.tracing.FlatTrace`,
`~specreduce.tracing.FitTrace`, and `~specreduce.tracing.ArrayTrace`. Each trace class requires
the 2D spectral image as input, along with trace-specific parameters that control how the trace
is determined.

FlatTrace
---------

`~specreduce.tracing.FlatTrace` assumes that the spectrum follows a straight line across the
detector, and is best for well-aligned spectrographs with minimal optical distortion. To
initialize a `~specreduce.tracing.FlatTrace`, specify the fixed cross-dispersion pixel
position with the ``trace_pos`` argument:

.. code-block:: python

    trace = specreduce.tracing.FlatTrace(image, trace_pos=6)


.. plot::

    import numpy as np
    import matplotlib.pyplot as plt
    from scipy.stats import norm

    fw = 10
    nd, ncd = 31, 13
    xd, xcd = np.arange(nd), np.arange(ncd)

    spectrum = np.zeros((ncd, nd))
    spectrum[:,:] = norm(6.0, 1.5).pdf(xcd)[:, None]

    plt.rc('font', size=13)
    fig, ax = plt.subplots(figsize=(fw, fw*(ncd/nd)), constrained_layout=True)
    ax.imshow(spectrum, origin='lower')
    ax.plot((0, nd-1), (6, 6), c='k')
    ax.set_xticks(xd+0.5, minor=True)
    ax.set_yticks(xcd+0.5, minor=True)
    ax.grid(alpha=0.25, lw=1, which='minor')
    plt.setp(ax, xlabel='Dispersion axis', ylabel='Cross-dispersion axis')
    fig.show()

FitTrace
--------

`~specreduce.tracing.FitTrace` fits a polynomial function to automatically detected spectrum
positions, and is suitable for typical spectra with smooth, continuous trace profiles. The trace
model can be chosen from `~astropy.modeling.polynomial.Chebyshev1D`,
`~astropy.modeling.polynomial.Legendre1D`, `~astropy.modeling.polynomial.Polynomial1D`,
or `~astropy.modeling.spline.Spline1D`, and the fitting can be optimized by binning the spectrum
along the dispersion axis.

.. code-block:: python

    trace = specreduce.tracing.FitTrace(image, bins=10, trace_model=Polynomial1D(3))

.. plot::

    import numpy as np
    import matplotlib.pyplot as plt
    from scipy.stats import norm
    plt.rc('font', size=13)

    fw = 10
    nd, ncd = 31, 13
    xd, xcd = np.arange(nd), np.arange(ncd)

    tr = np.poly1d([-0.01, 0.2, 7.0])
    spectrum = np.zeros((ncd, nd))
    for i,x in enumerate(xd):
        spectrum[:,i] = norm(tr(x), 1.0).pdf(xcd)

    fig, ax = plt.subplots(figsize=(fw, fw*(ncd/nd)), constrained_layout=True)
    ax.imshow(spectrum, origin='lower')
    ax.plot(xd, tr(xd), 'k')
    ax.set_xticks(xd+0.5, minor=True)
    ax.set_yticks(xcd+0.5, minor=True)
    ax.grid(alpha=0.25, lw=1, which='minor')
    plt.setp(ax, xlabel='Dispersion axis', ylabel='Cross-dispersion axis')
    fig.show()

The method works by (optionally) binning the 2D spectrum along the dispersion axis, finding
the PSF peak position along the cross-dispersion for each bin, and then fitting a 1D polynomial to
the cross-dispersion and dispersion axis positions. Binning is optional, and the native image
resolution is used by default. Binning can significantly increase the reliability of the fitting
with low SNR spectra, and always increases the speed.

The peak detection method can be chosen from ``max``, ``centroid``, and ``gaussian``. Of these
methods, ``max`` is the fastest but yields an integer pixel precision.  Both ``centroid`` and
``gaussian`` can be used when sub-pixel precision is required, and ``gaussian``, while being the
slowest method of the three, is the best option if the data is significantly contaminated by
non-finite values.

.. plot::

    import numpy as np
    import matplotlib.pyplot as plt
    from scipy.stats import norm
    from numpy.random import seed, normal
    from astropy.modeling.models import Gaussian1D
    from astropy.modeling.fitting import DogBoxLSQFitter
    plt.rc('font', size=13)
    seed(5)

    fw = 10
    nd, ncd = 31, 13
    xd, xcd = np.arange(nd), np.arange(ncd)

    psf = norm(5.4, 1.5).pdf(xcd) + normal(0, 0.01, ncd)
    fitter = DogBoxLSQFitter()
    m = fitter(Gaussian1D(), xcd, psf)

    fig, ax = plt.subplots(figsize=(fw, fw*(ncd/nd)), constrained_layout=True)
    ax.step(xcd, psf, where='mid', c='k')
    ax.axvline(xcd[np.argmax(psf)], label='max')
    ax.axvline(np.average(xcd, weights=psf), ls='--', label='centroid')
    ax.axvline(m.mean.value, ls=':', label='gaussian')
    ax.plot(xcd, m(xcd), ls=':')
    ax.legend()
    plt.setp(ax, yticks=[], ylabel='Flux', xlabel='Cross-dispersion axis [pix]', xlim=(0, ncd-1))
    fig.show()

ArrayTrace
----------

`~specreduce.tracing.ArrayTrace` uses a pre-defined array of positions for maximum flexibility
and is ideal for complex or unusual trace shapes that are difficult to model mathematically.
To initialize `~specreduce.tracing.ArrayTrace`, provide a 1D array of cross-dispersion pixel
positions via the ``trace`` argument. The size of this array must match the number of
pixels along the dispersion axis of the image.

.. code-block:: python

    trace = specreduce.tracing.ArrayTrace(image, trace=positions)

.. plot::

    import numpy as np
    import matplotlib.pyplot as plt
    from scipy.stats import norm
    plt.rc('font', size=13)

    fw = 10
    nd, ncd = 31, 13
    xd, xcd = np.arange(nd), np.arange(ncd)

    tr = np.full_like(xd, 6)
    tr[:6] = 4
    tr[15:23] = 8

    spectrum = np.zeros((ncd, nd))

    for i,x in enumerate(xd):
        spectrum[:,i] = norm(tr[i], 1.0).pdf(xcd)

    plt.rc('font', size=13)
    fig, ax = plt.subplots(figsize=(fw, fw*(ncd/nd)), constrained_layout=True)
    ax.imshow(spectrum, origin='lower')
    ax.plot(xd, tr, 'k')
    ax.set_xticks(xd+0.5, minor=True)
    ax.set_yticks(xcd+0.5, minor=True)
    ax.grid(alpha=0.25, lw=1, which='minor')
    plt.setp(ax, xlabel='Dispersion axis', ylabel='Cross-dispersion axis')
    fig.show()