ERIS Pipeline Reference Manual 1.9.2
eris_nix_wavecal_utils.c
1/* $Id$
2 *
3 * This file is part of the ERIS/NIX Pipeline
4 * Copyright (C) 2017 European Southern Observatory
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 /*
22 * $Author$
23 * $Date$
24 * $Rev$
25 */
26
27#ifdef HAVE_CONFIG_H
28#include <config.h>
29#endif
30
31/*-----------------------------------------------------------------------------
32 Includes
33 -----------------------------------------------------------------------------*/
34
35#include "eris_nix_wavecal_utils.h"
36
37/*----------------------------------------------------------------------------*/
41/*----------------------------------------------------------------------------*/
42
45/*----------------------------------------------------------------------------*/
85/*----------------------------------------------------------------------------*/
86
87cpl_matrix * enwu_linepos_2d(const hdrl_image * spectrum2d,
88 const cpl_size slice_index,
89 const cpl_vector * guess_pos) {
90
91 cpl_matrix * line_pos = NULL;
92 cpl_vector * next_guess_pos = NULL;
93 cpl_vector * spectrum1d = NULL;
94
95 if (cpl_error_get_code() != CPL_ERROR_NONE) return NULL;
96
97 cpl_ensure(spectrum2d, CPL_ERROR_NULL_INPUT, NULL);
98 cpl_ensure(guess_pos, CPL_ERROR_NULL_INPUT, NULL);
99 cpl_ensure(cpl_vector_get_size(guess_pos) > 0,
100 CPL_ERROR_ILLEGAL_INPUT, NULL);
101
102 cpl_size nlines = cpl_vector_get_size(guess_pos);
103
104 const cpl_size nx = hdrl_image_get_size_x(spectrum2d);
105 line_pos = cpl_matrix_new(nx, nlines);
106 cpl_matrix_fill(line_pos, NAN);
107
108 /* loop through slices on RH side of image. Remember that cpl_image
109 indeces are 1-based, cpl_vector and cpl_matrix 0-based - fab! */
110
111 next_guess_pos = cpl_vector_duplicate(guess_pos);
112
113 for (cpl_size ix = slice_index; ix < nx; ix++) {
114
115 /* fit the lines in this slice to get accurate peak positions */
116
117 spectrum1d = cpl_vector_new_from_image_column(
118 hdrl_image_get_image_const(spectrum2d), ix+1);
119
120 for (cpl_size line_id=0; line_id < nlines; line_id++) {
121 double line_guess_pos = cpl_vector_get(next_guess_pos, line_id);
122 double fitted_pos = enwu_linepos_1d(spectrum1d, line_guess_pos);
123 if (!isnan(fitted_pos)) {
124
125 /* set the fit peak as the measured position of the line,
126 set next_guess_pos to the actual line positions so that
127 it can follow slow variations with ix */
128
129 cpl_matrix_set(line_pos, ix, line_id, fitted_pos);
130 cpl_vector_set(next_guess_pos, line_id, fitted_pos);
131 }
132 }
133 cpl_vector_delete(spectrum1d);
134 }
135 cpl_vector_delete(next_guess_pos);
136
137 /* now loop through slices on LH side of image */
138
139 next_guess_pos = cpl_vector_duplicate(guess_pos);
140
141 for (cpl_size ix = slice_index-1; ix >= 0; ix--) {
142 spectrum1d = cpl_vector_new_from_image_column(
143 hdrl_image_get_image_const(spectrum2d), ix+1);
144
145 for (cpl_size line_id=0; line_id < nlines; line_id++) {
146 double line_guess_pos = cpl_vector_get(next_guess_pos, line_id);
147 double fitted_pos = enwu_linepos_1d(spectrum1d, line_guess_pos);
148 if (!isnan(fitted_pos)) {
149 cpl_matrix_set(line_pos, ix, line_id, fitted_pos);
150 cpl_vector_set(next_guess_pos, line_id, fitted_pos);
151 }
152 }
153 cpl_vector_delete(spectrum1d);
154 }
155 cpl_vector_delete(next_guess_pos);
156
157 /* Return NULL on error */
158
159 if (cpl_error_get_code() != CPL_ERROR_NONE) {
160 cpl_matrix_delete(line_pos);
161 line_pos = NULL;
162 }
163
164 return line_pos;
165}
166
171/*----------------------------------------------------------------------------*/
190/*----------------------------------------------------------------------------*/
191
192double enwu_linepos_1d(const cpl_vector * spectrum1d,
193 const double guess_pos) {
194
195 if (cpl_error_get_code() != CPL_ERROR_NONE) return NAN;
196 cpl_ensure(spectrum1d, CPL_ERROR_NULL_INPUT, NAN);
197
198 cpl_polynomial * line_fit = NULL;
199 double result = NAN;
200
201 cpl_size half_width = 4;
202 cpl_size istart = (cpl_size) guess_pos - half_width;
203 cpl_size istop = (cpl_size) guess_pos + half_width;
204 cpl_size npos = istop - istart + 1;
205
206 /* set up pixel positions of chunk */
207
208 cpl_matrix * pos_chunk = cpl_matrix_new(1, npos);
209 for (cpl_size i = 0; i < npos; i++) {
210 cpl_matrix_set(pos_chunk, 0, i, (double) (i + istart));
211 }
212
213 /* get spectrum data for chunk, spec_ok goes False if any points
214 bad (=0) or are NaN, the fitting routine can't handle NaNs */
215
216 cpl_vector * spectrum_chunk = cpl_vector_extract(spectrum1d,
217 istart, istop, 1);
218 const double * spectrum_chunk_data = cpl_vector_get_data_const(
219 spectrum_chunk);
220 int spec_ok = 1;
221 for (cpl_size i = 0; i < npos; i++) {
222 spec_ok = spec_ok &&
223 spectrum_chunk_data[i] != 0.0 &&
224 !isnan(spectrum_chunk_data[i]);
225 }
226
227 /* fit a parabola to the line peak if the data are good */
228
229 if (spec_ok) {
230 line_fit = cpl_polynomial_new(1);
231 const cpl_size maxdeg1d = 2;
232 cpl_polynomial_fit(line_fit, pos_chunk, NULL, spectrum_chunk, NULL,
233 CPL_FALSE, NULL, &maxdeg1d);
234
235 /* set the fit peak as the measured position of the line,
236 set next_guess_pos to the actual line positions so that
237 it can follow slow variations with ix */
238
239 cpl_size pow = 1;
240 double poly_b = cpl_polynomial_get_coeff(line_fit, &pow);
241 pow = 2;
242 double poly_c = cpl_polynomial_get_coeff(line_fit, &pow);
243 result = -poly_b / (2.0 * poly_c);
244
245 /* if the fitted line centre is outside the expected range
246 then something has probably gone wrong - errant pixel or
247 something - ignore it */
248
249 if (fabs(result - guess_pos) > half_width) {
250 result = NAN;
251 }
252 }
253
254 cpl_matrix_delete(pos_chunk);
255 cpl_vector_delete(spectrum_chunk);
256 cpl_polynomial_delete(line_fit);
257
258 if (cpl_error_get_code() != CPL_ERROR_NONE) {
259 result = NAN;
260 }
261
262 return result;
263}
264
cpl_matrix * enwu_linepos_2d(const hdrl_image *spectrum2d, const cpl_size slice_index, const cpl_vector *guess_pos)
Fit the line peaks of a wave calibration spectrum.
cpl_size hdrl_image_get_size_x(const hdrl_image *self)
return size of X dimension of image
Definition: hdrl_image.c:525
const cpl_image * hdrl_image_get_image_const(const hdrl_image *himg)
get data as cpl image
Definition: hdrl_image.c:118