summaryrefslogtreecommitdiff
path: root/spectro/i1pro_imp.c
diff options
context:
space:
mode:
Diffstat (limited to 'spectro/i1pro_imp.c')
-rw-r--r--spectro/i1pro_imp.c1703
1 files changed, 1244 insertions, 459 deletions
diff --git a/spectro/i1pro_imp.c b/spectro/i1pro_imp.c
index 2211bd4..b6d6747 100644
--- a/spectro/i1pro_imp.c
+++ b/spectro/i1pro_imp.c
@@ -7,7 +7,7 @@
* Author: Graeme W. Gill
* Date: 24/11/2006
*
- * Copyright 2006 - 2013 Graeme W. Gill
+ * Copyright 2006 - 2014 Graeme W. Gill
* All rights reserved.
*
* This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
@@ -100,21 +100,25 @@
#undef ENABLE_WRITE /* [Und] Enable writing of calibration and log data to the EEProm */
#define ENABLE_NONVCAL /* [Def] Enable saving calibration state between program runs in a file */
#define ENABLE_NONLINCOR /* [Def] Enable non-linear correction */
+#define ENABLE_BKDRIFTC /* [Def] Enable Emis. Black drift compensation using sheilded cell values */
+#define HEURISTIC_BKDRIFTC /* [Def] Enable heusristic black drift correction */
#define WLCALTOUT (24 * 60 * 60) /* [24 Hrs] Wavelength calibration timeout in seconds */
#define DCALTOUT ( 60 * 60) /* [60 Minuites] Dark Calibration timeout in seconds */
#define DCALTOUT2 ( 1 * 60 * 60) /* [1 Hr] i1pro2 Dark Calibration timeout in seconds */
#define WCALTOUT ( 1 * 60 * 60) /* [1 Hr] White Calibration timeout in seconds */
-#define MAXSCANTIME 15.0 /* [15] Maximum scan time in seconds */
+#define MAXSCANTIME 20.0 /* [20] Maximum scan time in seconds */
#define SW_THREAD_TIMEOUT (10 * 60.0) /* [10 Min] Switch read thread timeout */
#define SINGLE_READ /* [Def] Use a single USB read for scan to eliminate latency issues. */
#define HIGH_RES /* [Def] Enable high resolution spectral mode code. Dissable */
/* to break dependency on rspl library. */
+# undef FAST_HIGH_RES_SETUP /* Slightly better accuracy ? */
/* Debug [Und] */
#undef DEBUG /* Turn on debug printfs */
#undef PLOT_DEBUG /* Use plot to show readings & processing */
#undef PLOT_REFRESH /* Plot refresh rate measurement info */
+#undef PLOT_UPDELAY /* Plot data used to determine display update delay */
#undef DUMP_SCANV /* Dump scan readings to a file "i1pdump.txt" */
#undef DUMP_DARKM /* Append raw dark readings to file "i1pddump.txt" */
#undef APPEND_MEAN_EMMIS_VAL /* Append averaged uncalibrated reading to file "i1pdump.txt" */
@@ -124,6 +128,7 @@
#undef IGNORE_WHITE_INCONS /* Ignore define reference reading inconsistency */
#undef HIGH_RES_DEBUG
#undef HIGH_RES_PLOT
+#undef ANALIZE_EXISTING /* Analize the manufacturers existing filter shape */
#undef PLOT_BLACK_SUBTRACT /* Plot temperature corrected black subtraction */
#undef FAKE_AMBIENT /* Fake the ambient mode for a Rev A */
@@ -143,18 +148,18 @@
#define ADARKINT_MAX2 4.0 /* Max cal time for adaptive dark cal Rev E or no high gain */
#define EMIS_SCALE_FACTOR 1.0 /* Emission mode scale factor */
-#define AMB_SCALE_FACTOR (1.0/3.141592654) /* Ambient mode scale factor - convert */
- /* from Lux to Lux/PI */
- /* These factors get the same behaviour as the GMB drivers. */
+#define AMB_SCALE_FACTOR 1.0 /* Ambient mode scale factor for Lux */
+//#define AMB_SCALE_FACTOR (1.0/3.141592654) /* Ambient mode scale factor - convert */
+// /* from Lux to Lux/PI */
+// /* These factors get the same behaviour as the GMB drivers. */
#define NSEN_MAX 140 /* Maximum nsen value we can cope with */
/* High res mode settings */
-#define HIGHRES_SHORT 350
-#define HIGHRES_LONG 740
+#define HIGHRES_SHORT 370.0 /* i1pro2 uses more of the CCD, */
+#define HIGHRES_LONG 730.0 /* leaving less scope for extenion */
#define HIGHRES_WIDTH (10.0/3.0) /* (The 3.3333 spacing and lanczos2 seems a good combination) */
#define HIGHRES_REF_MIN 375.0 /* Too much stray light below this in reflective mode */
- /* (i1pro2 could go lower with different correction) */
#include "i1pro.h"
#include "i1pro_imp.h"
@@ -162,6 +167,8 @@
/* - - - - - - - - - - - - - - - - - - */
#define LAMP_OFF_TIME 1500 /* msec to make sure lamp is dark for dark measurement */
#define PATCH_CONS_THR 0.1 /* Dark measurement consistency threshold */
+
+#define USE_RD_SYNC /* Use mutex syncronisation, else depend on TRIG_DELAY */
#define TRIG_DELAY 10 /* Measure trigger delay to allow pending read, msec */
/* - - - - - - - - - - - - - - - - - - */
@@ -260,6 +267,58 @@ void plot_wav_2(i1proimp *m, int hires, double *data1, double *data2) {
/* ============================================================ */
+/* Return a linear interpolated spectral value. Clip to ends */
+static double wav_lerp(i1proimp *m, int hires, double *ary, double wl) {
+ int jj;
+ double wl0, wl1, bl;
+ double rv;
+
+ jj = (int)floor(XSPECT_DIX(m->wl_short[hires], m->wl_long[hires], m->nwav[hires], wl));
+ if (jj < 0)
+ jj = 0;
+ else if (jj > (m->nwav[hires]-2))
+ jj = m->nwav[hires]-2;
+
+ wl0 = XSPECT_WL(m->wl_short[hires], m->wl_long[hires], m->nwav[hires], jj);
+ wl1 = XSPECT_WL(m->wl_short[hires], m->wl_long[hires], m->nwav[hires], jj+1);
+
+ bl = (wl - wl0)/(wl1 - wl0);
+ if (bl < 0.0)
+ bl = 0;
+ else if (bl > 1.0)
+ bl = 1.0;
+
+ rv = (1.0 - bl) * ary[jj] + bl * ary[jj+1];
+
+ return rv;
+}
+
+/* Same as above, but return cv value on clip */
+static double wav_lerp_cv(i1proimp *m, int hires, double *ary, double wl, double cv) {
+ int jj;
+ double wl0, wl1, bl;
+ double rv;
+
+ jj = (int)floor(XSPECT_DIX(m->wl_short[hires], m->wl_long[hires], m->nwav[hires], wl));
+ if (jj < 0)
+ jj = 0;
+ else if (jj > (m->nwav[hires]-2))
+ jj = m->nwav[hires]-2;
+
+ wl0 = XSPECT_WL(m->wl_short[hires], m->wl_long[hires], m->nwav[hires], jj);
+ wl1 = XSPECT_WL(m->wl_short[hires], m->wl_long[hires], m->nwav[hires], jj+1);
+
+ bl = (wl - wl0)/(wl1 - wl0);
+ if (bl < 0.0 || bl > 1.0)
+ return cv;
+
+ rv = (1.0 - bl) * ary[jj] + bl * ary[jj+1];
+
+ return rv;
+}
+
+/* ============================================================ */
+
/* Implementation struct */
/* Add an implementation structure */
@@ -316,7 +375,8 @@ void del_i1proimp(i1pro *p) {
a1logd(p->log,5,"i1pro switch thread termination failed\n");
}
m->th->del(m->th);
- usb_uninit_cancel(&m->cancelt); /* Don't need cancel token now */
+ usb_uninit_cancel(&m->sw_cancel); /* Don't need cancel token now */
+ usb_uninit_cancel(&m->rd_sync); /* Don't need sync token now */
}
a1logd(p->log,5,"i1pro switch thread terminated\n");
@@ -403,7 +463,8 @@ i1pro_code i1pro_imp_init(i1pro *p) {
if ((ev = i1pro_reset(p, 0x1f)) != I1PRO_OK)
return ev;
- usb_init_cancel(&m->cancelt); /* Init cancel token */
+ usb_init_cancel(&m->sw_cancel); /* Init switch cancel token */
+ usb_init_cancel(&m->rd_sync); /* Init reading sync token */
#ifdef USE_THREAD
/* Setup the switch monitoring thread */
@@ -1246,7 +1307,7 @@ i1pro_code i1pro_imp_set_mode(
) {
i1proimp *m = (i1proimp *)p->m;
- a1logd(p->log,2,"i1pro_imp_set_mode called with %d\n",mmode);
+ a1logd(p->log,2,"i1pro_imp_set_mode called with mode no %d and mask 0x%x\n",mmode,m);
switch(mmode) {
case i1p_refl_spot:
case i1p_refl_scan:
@@ -1266,6 +1327,15 @@ i1pro_code i1pro_imp_set_mode(
return I1PRO_INT_ILLEGALMODE;
}
m->spec_en = (mode & inst_mode_spectral) != 0;
+
+ if ((mode & inst_mode_highres) != 0) {
+ i1pro_code rv;
+ if ((rv = i1pro_set_highres(p)) != I1PRO_OK)
+ return rv;
+ } else {
+ i1pro_set_stdres(p); /* Ignore any error */
+ }
+
m->uv_en = 0;
if (mmode == i1p_refl_spot
@@ -1356,6 +1426,19 @@ i1pro_code i1pro_imp_get_n_a_cals(i1pro *p, inst_cal_type *pn_cals, inst_cal_typ
a_cals |= inst_calt_emis_int_time;
}
+ /* Special case high res. emissive cal fine calibration, */
+ /* needs reflective cal. */
+ /* Hmmm. Should we do this every time for emission, in case */
+ /* we switch to hires mode ??? */
+ if ((cs->emiss || cs->trans) /* We're in an emissive mode */
+ && m->hr_inited /* and hi-res has been setup */
+ && (!m->emis_hr_cal || (n_cals & inst_calt_em_dark)) /* and the emis cal hasn't been */
+ /* fine tuned or we will be doing a dark cal */
+ && p->itype != instI1Monitor) { /* i1Monitor doesn't have reflective cal capability */
+ n_cals |= inst_calt_ref_white; /* Need a reflective white calibration */
+ a_cals |= inst_calt_ref_white;
+ }
+
if (pn_cals != NULL)
*pn_cals = n_cals;
@@ -1380,7 +1463,7 @@ i1pro_code i1pro_imp_calibrate(
i1proimp *m = (i1proimp *)p->m;
int mmode = m->mmode;
i1pro_state *cs = &m->ms[m->mmode];
- int sx1, sx2, sx;
+ int sx1, sx2, sx3, sx;
time_t cdate = time(NULL);
int nummeas = 0;
int ltocmode = 0; /* 1 = Lamp turn on compensation mode */
@@ -1403,7 +1486,7 @@ i1pro_code i1pro_imp_calibrate(
else if (*calt == inst_calt_available)
*calt = available & inst_calt_n_dfrble_mask;
- a1logd(p->log,4,"i1pro_imp_calibrate: doing calt 0x%x\n",calt);
+ a1logd(p->log,4,"i1pro_imp_calibrate: doing calt 0x%x\n",*calt);
if ((*calt & inst_calt_n_dfrble_mask) == 0) /* Nothing todo */
return I1PRO_OK;
@@ -1411,17 +1494,26 @@ i1pro_code i1pro_imp_calibrate(
/* See if it's a calibration we understand */
if (*calt & ~available & inst_calt_all_mask) {
+ a1logd(p->log,4,"i1pro_imp_calibrate: unsupported, calt 0x%x, available 0x%x\n",*calt,available);
return I1PRO_UNSUPPORTED;
}
if (*calt & inst_calt_ap_flag) {
- sx1 = 0; sx2 = i1p_no_modes; /* Go through all the modes */
+ sx1 = 0; sx2 = sx3 = i1p_no_modes; /* Go through all the modes */
} else {
- sx1 = m->mmode; sx2 = sx1 + 1; /* Just current mode */
+ /* Special case - doing reflective cal. to fix emiss hires */
+ if ((cs->emiss || cs->trans) /* We're in an emissive mode */
+ && (*calt & inst_calt_ref_white)) { /* but we're asked for a ref white cal */
+ sx1 = m->mmode; sx2 = sx1 + 1; /* Just current mode */
+ sx3 = i1p_refl_spot; /* no extra mode */
+ } else {
+ sx1 = m->mmode; sx2 = sx1 + 1; /* Just current mode */
+ sx3 = i1p_no_modes; /* no extra mode */
+ }
}
/* Go through the modes we are going to cover */
- for (sx = sx1; sx < sx2; sx++) {
+ for (sx = sx1; sx < sx2; (++sx >= sx2 && sx3 != i1p_no_modes) ? sx = sx3, sx2 = sx+1, sx3 = i1p_no_modes : 0) {
i1pro_state *s = &m->ms[sx];
m->mmode = sx; /* A lot of functions we call rely on this */
@@ -1459,15 +1551,15 @@ i1pro_code i1pro_imp_calibrate(
free_dvector(wlraw, -1, m->nraw-1);
- /* Compute normal res. reflective wavelength corrected filters */
- if ((ev = i1pro2_compute_wav_filters(p, 1)) != I1PRO_OK) {
- a1logd(p->log,2,"i1pro2_compute_wav_filters() failed\n");
+ /* Compute normal res. emissive/transmissive wavelength corrected filters */
+ if ((ev = i1pro_compute_wav_filters(p, 0, 0)) != I1PRO_OK) {
+ a1logd(p->log,2,"i1pro_compute_wav_filters() failed\n");
return ev;
}
- /* Compute normal res. emissive/transmissive wavelength corrected filters */
- if ((ev = i1pro2_compute_wav_filters(p, 0)) != I1PRO_OK) {
- a1logd(p->log,2,"i1pro2_compute_wav_filters() failed\n");
+ /* Compute normal res. reflective wavelength corrected filters */
+ if ((ev = i1pro_compute_wav_filters(p, 0, 1)) != I1PRO_OK) {
+ a1logd(p->log,2,"i1pro_compute_wav_filters() failed\n");
return ev;
}
@@ -2112,13 +2204,28 @@ i1pro_code i1pro_imp_calibrate(
return ev;
}
/* Compute a calibration factor given the reading of the white reference. */
- i1pro_compute_white_cal(p, s->cal_factor[0], m->white_ref[0], s->cal_factor[0],
- s->cal_factor[1], m->white_ref[1], s->cal_factor[1]);
+ ev = i1pro_compute_white_cal(p,
+ s->cal_factor[0], m->white_ref[0], s->cal_factor[0],
+ s->cal_factor[1], m->white_ref[1], s->cal_factor[1],
+ !s->scan); /* Use this for emis hires fine tune if not scan */
+
+ if (ev != I1PRO_RD_TRANSWHITEWARN && ev != I1PRO_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
- } else {
+ } else { /* transmissive */
/* Compute a calibration factor given the reading of the white reference. */
- m->transwarn |= i1pro_compute_white_cal(p, s->cal_factor[0], NULL, s->cal_factor[0],
- s->cal_factor[1], NULL, s->cal_factor[1]);
+ ev = i1pro_compute_white_cal(p, s->cal_factor[0], NULL, s->cal_factor[0],
+ s->cal_factor[1], NULL, s->cal_factor[1], 0);
+ if (ev == I1PRO_RD_TRANSWHITEWARN) {
+ m->transwarn |= 1;
+ ev = I1PRO_OK;
+ }
+ if (ev != I1PRO_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
}
s->cal_valid = 1;
s->cfdate = cdate;
@@ -2195,8 +2302,16 @@ i1pro_code i1pro_imp_calibrate(
} /* Look at next mode */
m->mmode = mmode; /* Restore actual mode */
- /* Make sure there's the right condition for any remaining calibrations */
- if (*calt & inst_calt_wavelength) { /* Wavelength calibration */
+ /* Make sure there's the right condition for any remaining calibrations. */
+ /* Do ref_white first in case we are doing a high res fine tune. */
+
+ if (*calt & (inst_calt_ref_dark | inst_calt_ref_white)) {
+ sprintf(id, "Serial no. %d",m->serno);
+ if (*calc != inst_calc_man_ref_white) {
+ *calc = inst_calc_man_ref_white; /* Calibrate using white tile */
+ return I1PRO_CAL_SETUP;
+ }
+ } else if (*calt & inst_calt_wavelength) { /* Wavelength calibration */
if (cs->emiss && cs->ambient) {
id[0] = '\000';
if (*calc != inst_calc_man_am_dark) {
@@ -2210,12 +2325,6 @@ i1pro_code i1pro_imp_calibrate(
return I1PRO_CAL_SETUP;
}
}
- } else if (*calt & (inst_calt_ref_dark | inst_calt_ref_white)) {
- sprintf(id, "Serial no. %d",m->serno);
- if (*calc != inst_calc_man_ref_white) {
- *calc = inst_calc_man_ref_white; /* Calibrate using white tile */
- return I1PRO_CAL_SETUP;
- }
} else if (*calt & inst_calt_em_dark) { /* Emissive Dark calib */
id[0] = '\000';
if (*calc != inst_calc_man_em_dark) {
@@ -2286,6 +2395,154 @@ int icoms2i1pro_err(int se) {
}
/* - - - - - - - - - - - - - - - - */
+/* Measure a display update delay. It is assumed that a */
+/* white to black change has been made to the displayed color, */
+/* and this will measure the time it took for the update to */
+/* be noticed by the instrument, up to 0.6 seconds. */
+/* inst_misread will be returned on failure to find a transition to black. */
+#define NDMXTIME 0.7 /* Maximum time to take */
+#define NDSAMPS 500 /* Debug samples */
+
+typedef struct {
+ double sec;
+ double rgb[3];
+ double tot;
+} i1rgbdsamp;
+
+i1pro_code i1pro_imp_meas_delay(
+i1pro *p,
+int *msecdelay) { /* Return the number of msec */
+ i1pro_code ev = I1PRO_OK;
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_state *s = &m->ms[m->mmode];
+ int i, j, k, mm;
+ double **multimeas; /* Spectral measurements */
+ int nummeas;
+ double rgbw[3] = { 610.0, 520.0, 460.0 };
+ double ucalf = 1.0; /* usec_time calibration factor */
+ double inttime;
+ i1rgbdsamp *samp;
+ double stot, etot, del, thr;
+ double etime;
+ int isdeb;
+
+ /* Read the samples */
+ inttime = m->min_int_time;
+ nummeas = (int)(NDMXTIME/inttime + 0.5);
+ multimeas = dmatrix(0, nummeas-1, -1, m->nwav[m->highres]-1);
+ if ((samp = (i1rgbdsamp *)calloc(sizeof(i1rgbdsamp), nummeas)) == NULL) {
+ a1logd(p->log, 1, "i1pro_meas_delay: malloc failed\n");
+ return I1PRO_INT_MALLOC;
+ }
+
+//printf("~1 %d samples at %f int\n",nummeas,inttime);
+ if ((ev = i1pro_read_patches_all(p, multimeas, nummeas, &inttime, 0)) != inst_ok) {
+ free_dmatrix(multimeas, 0, nummeas-1, 0, m->nwav[m->highres]-1);
+ free(samp);
+ return ev;
+ }
+
+ /* Convert the samples to RGB */
+ for (i = 0; i < nummeas; i++) {
+ samp[i].sec = i * inttime;
+ samp[i].rgb[0] = samp[i].rgb[1] = samp[i].rgb[2] = 0.0;
+ for (j = 0; j < m->nwav[m->highres]; j++) {
+ double wl = XSPECT_WL(m->wl_short[m->highres], m->wl_long[m->highres], m->nwav[m->highres], j);
+
+//printf("~1 multimeas %d %d = %f\n",i, j, multimeas[i][j]);
+ for (k = 0; k < 3; k++) {
+ double tt = (double)(wl - rgbw[k]);
+ tt = (50.0 - fabs(tt))/50.0;
+ if (tt < 0.0)
+ tt = 0.0;
+ samp[i].rgb[k] += sqrt(tt) * multimeas[i][j];
+ }
+ }
+ samp[i].tot = samp[i].rgb[0] + samp[i].rgb[1] + samp[i].rgb[2];
+ }
+ free_dmatrix(multimeas, 0, nummeas-1, 0, m->nwav[m->highres]-1);
+
+ a1logd(p->log, 3, "i1pro_measure_refresh: Read %d samples for refresh calibration\n",nummeas);
+
+#ifdef PLOT_UPDELAY
+ /* Plot the raw sensor values */
+ {
+ double xx[NDSAMPS];
+ double y1[NDSAMPS];
+ double y2[NDSAMPS];
+ double y3[NDSAMPS];
+ double y4[NDSAMPS];
+
+ for (i = 0; i < nummeas && i < NDSAMPS; i++) {
+ xx[i] = samp[i].sec;
+ y1[i] = samp[i].rgb[0];
+ y2[i] = samp[i].rgb[1];
+ y3[i] = samp[i].rgb[2];
+ y4[i] = samp[i].tot;
+//printf("%d: %f -> %f\n",i,samp[i].sec, samp[i].tot);
+ }
+ printf("Display update delay measure sensor values and time (sec)\n");
+ do_plot6(xx, y1, y2, y3, y4, NULL, NULL, nummeas);
+ }
+#endif
+
+ /* Over the first 100msec, locate the maximum value */
+ etime = samp[nummeas-1].sec;
+ stot = -1e9;
+ for (i = 0; i < nummeas; i++) {
+ if (samp[i].tot > stot)
+ stot = samp[i].tot;
+ if (samp[i].sec > 0.1)
+ break;
+ }
+
+ /* Over the last 100msec, locate the maximum value */
+ etime = samp[nummeas-1].sec;
+ etot = -1e9;
+ for (i = nummeas-1; i >= 0; i--) {
+ if (samp[i].tot > etot)
+ etot = samp[i].tot;
+ if ((etime - samp[i].sec) > 0.1)
+ break;
+ }
+
+ del = stot - etot;
+ thr = etot + 0.30 * del; /* 30% of transition threshold */
+
+#ifdef PLOT_UPDELAY
+ a1logd(p->log, 0, "i1pro_meas_delay: start tot %f end tot %f del %f, thr %f\n", stot, etot, del, thr);
+#endif
+
+ /* Check that there has been a transition */
+ if (del < 5.0) {
+ free(samp);
+ a1logd(p->log, 1, "i1pro_meas_delay: can't detect change from white to black\n");
+ return I1PRO_RD_NOTRANS_FOUND;
+ }
+
+ /* Locate the time at which the values are above the end values */
+ for (i = nummeas-1; i >= 0; i--) {
+ if (samp[i].tot > thr)
+ break;
+ }
+ if (i < 0) /* Assume the update was so fast that we missed it */
+ i = 0;
+
+ a1logd(p->log, 2, "i1pro_meas_delay: stoped at sample %d time %f\n",i,samp[i].sec);
+
+ *msecdelay = (int)(samp[i].sec * 1000.0 + 0.5);
+
+#ifdef PLOT_UPDELAY
+ a1logd(p->log, 0, "i1pro_meas_delay: returning %d msec\n",*msecdelay);
+#endif
+ free(samp);
+
+ return I1PRO_OK;
+}
+#undef NDSAMPS
+#undef NDMXTIME
+
+/* - - - - - - - - - - - - - - - - */
/* Measure a patch or strip in the current mode. */
/* To try and speed up the reaction time between */
/* triggering a scan measurement and being able to */
@@ -2799,10 +3056,11 @@ i1pro_code i1pro_imp_meas_refrate(
tt = (40.0 - fabs(tt))/40.0;
if (tt < 0.0)
tt = 0.0;
- samp[i].rgb[k] += tt * multimeas[i][j];
+ samp[i].rgb[k] += sqrt(tt) * multimeas[i][j];
}
}
}
+ free_dmatrix(multimeas, 0, nummeas-1, 0, m->nwav[m->highres]-1);
nfsamps = i;
a1logd(p->log, 3, "i1pro_measure_refresh: Read %d samples for refresh calibration\n",nfsamps);
@@ -3325,6 +3583,7 @@ i1pro_code i1pro_imp_meas_refrate(
if (brange > 0.05) {
a1logd(p->log, 3, "Readings are too inconsistent (brange %.1f%%) - should retry ?\n",brange * 100.0);
} else {
+
if (ref_rate != NULL)
*ref_rate = brate;
@@ -3399,7 +3658,7 @@ i1pro_code i1pro_restore_refspot_cal(i1pro *p) {
} else
s->gainmode = 0;
- /* Get the calibration integrattion time */
+ /* Get the calibration integration time */
if ((dp = m->data->get_doubles(m->data, &count, key_inttime + offst)) == NULL || count < 1) {
a1logd(p->log,2,"Failed to read calibration integration time from EEPRom\n");
return I1PRO_OK;
@@ -3470,8 +3729,12 @@ i1pro_code i1pro_restore_refspot_cal(i1pro *p) {
return I1PRO_OK;
}
/* Compute a calibration factor given the reading of the white reference. */
- i1pro_compute_white_cal(p, s->cal_factor[0], m->white_ref[0], s->cal_factor[0],
- s->cal_factor[1], m->white_ref[1], s->cal_factor[1]);
+ ev = i1pro_compute_white_cal(p, s->cal_factor[0], m->white_ref[0], s->cal_factor[0],
+ s->cal_factor[1], m->white_ref[1], s->cal_factor[1], 1);
+ if (ev != I1PRO_RD_TRANSWHITEWARN && ev != I1PRO_OK) {
+ a1logd(p->log,2,"i1pro_compute_white_cal failed to convert EEProm data to calibration\n");
+ return I1PRO_OK;
+ }
/* We've sucessfully restored the calibration */
s->cal_valid = 1;
@@ -4300,6 +4563,7 @@ i1pro_code i1pro_dark_measure_2(
/* absolute linearised sensor values. */
if ((ev = i1pro_sens_to_absraw(p, multimes, buf, nummeas, inttime, gainmode, &darkthresh))
!= I1PRO_OK) {
+ free_dmatrix(multimes, 0, nummeas-1, -1, m->nraw-1);
return ev;
}
@@ -5459,6 +5723,7 @@ i1pro_trigger_one_measure(
}
/* Trigger a measurement */
+ usb_reinit_cancel(&m->rd_sync); /* Prepare to sync rd and trigger */
if (p->itype != instI1Pro2) {
if ((ev = i1pro_triggermeasure(p, TRIG_DELAY)) != I1PRO_OK)
return ev;
@@ -6819,14 +7084,21 @@ void i1pro_sub_absraw(
a1logd(p->log,2,"Black shielded value = %f, Reading shielded value = %f\n",sub[-1], avgscell);
/* Compute the adjusted black */
+ /* [ Unlike the ColorMunki, using the black drift comp. for reflective */
+ /* seems to be OK and even beneficial. ] */
for (j = 0; j < m->nraw; j++) {
-#ifdef NEVER
+#ifdef ENABLE_BKDRIFTC
+# ifdef HEURISTIC_BKDRIFTC
+ /* heuristic scaled correction */
+ asub[j] = zero - (zero - sub[j]) * (zero - avgscell)/(zero - sub[-1]);
+# else
/* simple additive correction */
-# pragma message("######### i1pro2 Simple shielded cell temperature correction! ########")
+# pragma message("######### i1pro2 Simple shielded cell temperature correction! ########")
asub[j] = sub[j] + avgscell - sub[-1];
+# endif
#else
- /* heuristic scaled correction */
- asub[j] = zero - (zero - sub[j]) * (zero - avgscell)/(zero - sub[-1]);
+# pragma message("######### i1pro2 No shielded cell temperature correction! ########")
+ asub[j] = sub[j]; /* Just use the calibration dark data */
#endif
}
@@ -7448,9 +7720,11 @@ i1pro_code i1pro2_match_wl_meas(i1pro *p, double *pled_off, double *wlraw) {
return ev;
}
-/* Compute standard res. downsampling filters for the given mode */
-/* given the current wl_led_off, and set them as current. */
-i1pro_code i1pro2_compute_wav_filters(i1pro *p, int refl) {
+/* Compute standard/high res. downsampling filters for the given mode */
+/* given the current wl_led_off, and set them as current, */
+/* using triangular filters of the lagrange interpolation of the */
+/* CCD values. */
+i1pro_code i1pro_compute_wav_filters(i1pro *p, int hr, int refl) {
i1proimp *m = (i1proimp *)p->m;
i1pro_state *s = &m->ms[m->mmode];
i1pro_code ev = I1PRO_OK;
@@ -7461,28 +7735,28 @@ i1pro_code i1pro2_compute_wav_filters(i1pro *p, int refl) {
double trh, trx; /* Triangle height and triangle equation x weighting */
int i, j, k;
- a1logd(p->log,2,"i1pro2_compute_wav_filters called with correction %f raw\n",s->wl_led_off - m->wl_led_ref_off);
+ a1logd(p->log,2,"i1pro_compute_wav_filters called with correction %f raw\n",s->wl_led_off - m->wl_led_ref_off);
- twidth = (m->wl_long[0] - m->wl_short[0])/(m->nwav[0] - 1.0); /* Filter width */
+ twidth = (m->wl_long[hr] - m->wl_short[hr])/(m->nwav[hr] - 1.0); /* Filter width */
trh = 1.0/twidth; /* Triangle height */
trx = trh/twidth; /* Triangle equation x weighting */
/* Allocate separate space for the calibrated versions, so that the */
/* original eeprom values are preserved */
- if (m->mtx_c[0][refl].index == NULL) {
+ if (m->mtx_c[hr][refl].index == NULL) {
- if ((m->mtx_c[0][refl].index = (int *)calloc(m->nwav[0], sizeof(int))) == NULL) {
+ if ((m->mtx_c[hr][refl].index = (int *)calloc(m->nwav[hr], sizeof(int))) == NULL) {
a1logd(p->log,1,"i1pro: malloc ndex1 failed!\n");
return I1PRO_INT_MALLOC;
}
- if ((m->mtx_c[0][refl].nocoef = (int *)calloc(m->nwav[0], sizeof(int))) == NULL) {
+ if ((m->mtx_c[hr][refl].nocoef = (int *)calloc(m->nwav[hr], sizeof(int))) == NULL) {
a1logd(p->log,1,"i1pro: malloc nocoef failed!\n");
return I1PRO_INT_MALLOC;
}
- if ((m->mtx_c[0][refl].coef = (double *)calloc(16 * m->nwav[0], sizeof(double)))
+ if ((m->mtx_c[hr][refl].coef = (double *)calloc(16 * m->nwav[hr], sizeof(double)))
== NULL) {
a1logd(p->log,1,"i1pro: malloc coef failed!\n");
return I1PRO_INT_MALLOC;
@@ -7490,9 +7764,9 @@ i1pro_code i1pro2_compute_wav_filters(i1pro *p, int refl) {
}
/* For each output wavelength */
- wlcop = m->mtx_c[0][refl].coef;
- for (wlix = 0; wlix < m->nwav[0]; wlix++) {
- double owl = wlix/(m->nwav[0]-1.0) * (m->wl_long[0] - m->wl_short[0]) + m->wl_short[0];
+ wlcop = m->mtx_c[hr][refl].coef;
+ for (wlix = 0; wlix < m->nwav[hr]; wlix++) {
+ double owl = wlix/(m->nwav[hr]-1.0) * (m->wl_long[hr] - m->wl_short[hr]) + m->wl_short[hr];
int lip; /* Lagrange interpolation position */
// printf("Generating filter for %.1f nm width %.1f nm\n",owl, twidth);
@@ -7503,11 +7777,14 @@ i1pro_code i1pro2_compute_wav_filters(i1pro *p, int refl) {
/* Do a dumb search from high to low nm */
for (six = 0; six < m->nraw; six++) {
+//printf("~1 (raw2wav (six %d) %f <? (owl %f + twidth %f) %f\n",six,i1pro_raw2wav(p, refl, (double)six),owl,twidth,owl + twidth);
+
if (i1pro_raw2wav(p, refl, (double)six) < (owl + twidth))
break;
}
+
if (six < 2 || six >= m->nraw) {
- a1loge(p->log,1,"i1pro: compute_wav_filters() six %d out of raw range to cover output filter %.1f nm width %.1f nm\n",six, owl, twidth);
+ a1loge(p->log,1,"i1pro: compute_wav_filters() six %d, exceeds raw range to cover output filter %.1f nm width %.1f nm\n",six, owl, twidth);
return I1PRO_INT_ASSERT;
}
eix = six;
@@ -7518,30 +7795,30 @@ i1pro_code i1pro2_compute_wav_filters(i1pro *p, int refl) {
break;
}
if (eix > (m->nraw - 2) ) {
- a1loge(p->log,1,"i1pro: compute_wav_filters() eix %d out of raw range to cover output filter %.1f nm width %.1f nm\n",eix, owl, twidth);
+ a1loge(p->log,1,"i1pro: compute_wav_filters() eix %d, exceeds raw range to cover output filter %.1f nm width %.1f nm\n",eix, owl, twidth);
return I1PRO_INT_ASSERT;
}
- eix += 2;
+ eix += 2; /* Outside */
// for (j = six; j < eix; j++)
// printf("Using raw %d @ %.1f nm\n",j, i1pro_raw2wav(p, refl, (double)j));
/* Set start index for this wavelength */
- m->mtx_c[0][refl].index[wlix] = six;
+ m->mtx_c[hr][refl].index[wlix] = six;
/* Set number of filter coefficients */
- m->mtx_c[0][refl].nocoef[wlix] = eix - six;
+ m->mtx_c[hr][refl].nocoef[wlix] = eix - six;
- if (m->mtx_c[0][refl].nocoef[wlix] > 16) {
- a1loge(p->log,1,"i1pro: compute_wav_filters() too many filter %d\n",m->mtx_c[0][refl].nocoef[wlix]);
+ if (m->mtx_c[hr][refl].nocoef[wlix] > 16) {
+ a1loge(p->log,1,"i1pro: compute_wav_filters() too many filter %d\n",m->mtx_c[hr][refl].nocoef[wlix]);
return I1PRO_INT_ASSERT;
}
/* Start with zero filter weightings */
- for (i = 0; i < m->mtx_c[0][refl].nocoef[wlix]; i++)
+ for (i = 0; i < m->mtx_c[hr][refl].nocoef[wlix]; i++)
wlcop[i] = 0.0;
- /* for each Lagrange interpolation position */
+ /* for each Lagrange interpolation position (adjacent CCD locations) */
for (lip = six; (lip + 3) < eix; lip++) {
double rwav[4]; /* Relative wavelength of these Lagrange points */
double den[4]; /* Denominator values for points */
@@ -7656,14 +7933,14 @@ i1pro_code i1pro2_compute_wav_filters(i1pro *p, int refl) {
}
}
// printf("~1 Weightings for for %.1f nm are:\n",owl);
-// for (i = 0; i < m->mtx_c[0][refl].nocoef[wlix]; i++)
+// for (i = 0; i < m->mtx_c[hr][refl].nocoef[wlix]; i++)
// printf("~1 comp %d weight %e\n",i,wlcop[i]);
- wlcop += m->mtx_c[0][refl].nocoef[wlix]; /* Next group of weightings */
+ wlcop += m->mtx_c[hr][refl].nocoef[wlix]; /* Next group of weightings */
}
#ifdef DEBUG
/* Check against orginal filters */
- {
+ if (!hr) {
int ix1, ix1c;
double aerr = 0.0;
@@ -7712,7 +7989,7 @@ i1pro_code i1pro2_compute_wav_filters(i1pro *p, int refl) {
#endif /* DEBUG */
/* Switch normal res. to use wavelength calibrated version */
- m->mtx[0][refl] = m->mtx_c[0][refl];
+ m->mtx[hr][refl] = m->mtx_c[hr][refl];
return ev;
}
@@ -7721,16 +7998,34 @@ i1pro_code i1pro2_compute_wav_filters(i1pro *p, int refl) {
/* =============================================== */
#ifdef HIGH_RES
-#undef ANALIZE_EXISTING /* Analize the manufacturers existing filter shape */
+/*
+ It turns out that using the sharpest possible resampling filter
+ may make accuracy worse (particularly on the RevE), because it
+ enhances bumps in the raw response that mightn't be there
+ after calibrating for the instrument spectral sensitivity.
+ A better scheme (which we could sythesise using the hi-res
+ emissive calibration logic) would be to calibrate the raw CCD
+ values and then resample with possible sharpening.
+ Another approach would be to sharpen after filtering with
+ non-sharpening resampling filters.
+ The bottom line is that it's best to use a gausian hi-res
+ filter to avoid sharpening in non calibrated spectral space.
+ */
/* High res congiguration */
/* Pick one of these: */
-#define USE_LANCZOS2 /* [def] Use lanczos2 filter shape */
+#undef USE_TRI_LAGRANGE /* [und] Use normal res filter shape */
+#undef USE_LANCZOS2 /* [und] Use lanczos2 filter shape */
+#undef USE_LANCZOS3 /* [und] Use lanczos3 filter shape */
#undef USE_DECONV /* [und] Use deconvolution curve */
-#undef USE_GAUSSIAN /* [und] Use gaussian filter shape*/
#undef USE_BLACKMAN /* [und] Use Blackman windowed sinc shape */
+#define USE_GAUSSIAN /* [def] Use gaussian filter shape*/
#undef USE_CUBIC /* [und] Use cubic spline filter */
+#define DO_CCDNORM /* [def] Normalise CCD values to original */
+#define DO_CCDNORMAVG /* [und] Normalise averages rather than per CCD bin */
+ /* (We relly on fine cal & white cal to fix it) */
+
#undef COMPUTE_DISPERSION /* Compute slit & optics dispersion from red laser data */
#ifdef NEVER
@@ -7766,7 +8061,7 @@ static void i1pro_debug_plot_mtx_coef(i1pro *p) {
free_dvector(xx, -1, m->nraw-1);
free_dmatrix(yy, 0, 2, -1, m->nraw-1);
}
-#endif
+#endif /* NEVER */
#ifdef COMPUTE_DISPERSION
@@ -7876,7 +8171,7 @@ static double lin_fshape(i1pro_fs *fsh, int n, double x) {
/* Generate a sample from a lanczos2 filter shape */
/* wi is the width of the filter */
static double lanczos2(double wi, double x) {
- double y;
+ double y = 0.0;
#ifdef USE_DECONV
/* For 3.333, created by i1deconv.c */
@@ -7948,11 +8243,21 @@ static double lanczos2(double wi, double x) {
x = fabs(1.0 * x/wi);
if (x >= 2.0)
return 0.0;
- if (x < 1e-5)
+ if (x < 1e-6)
return 1.0;
y = sin(DBL_PI * x)/(DBL_PI * x) * sin(DBL_PI * x/2.0)/(DBL_PI * x/2.0);
#endif
+#ifdef USE_LANCZOS3
+ /* lanczos3 */
+ x = fabs(1.0 * x/wi);
+ if (x >= 3.0)
+ return 0.0;
+ if (x < 1e-6)
+ return 1.0;
+ y = sin(DBL_PI * x)/(DBL_PI * x) * sin(DBL_PI * x/3.0)/(DBL_PI * x/3.0);
+#endif
+
#ifdef USE_BLACKMAN /* Use Blackman windowed sinc shape */
double xx = x, w;
double a0, a1, a2, a3;
@@ -8034,16 +8339,126 @@ static int gcc_bug_fix(int i) {
}
#endif /* APPLE */
+/* Re-create calibration factors for hi-res */
+/* Set emisonly to only recompute emissive factors */
+i1pro_code i1pro_create_hr_calfactors(i1pro *p, int eonly) {
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_code ev = I1PRO_OK;
+ int i, j;
+
+ /* Generate high res. per mode calibration factors. */
+ if (m->hr_inited) {
+
+ for (i = 0; i < i1p_no_modes; i++) {
+ i1pro_state *s = &m->ms[i];
+
+ if (s->cal_factor[1] == NULL)
+ s->cal_factor[1] = dvectorz(0, m->nwav[1]-1);
+
+ switch(i) {
+ case i1p_refl_spot:
+ case i1p_refl_scan:
+ if (eonly)
+ continue;
+ if (s->cal_valid) {
+ /* (Using cal_factor[] as temp. for i1pro_absraw_to_abswav()) */
+#ifdef NEVER
+ printf("~1 regenerating calibration for reflection\n");
+ printf("~1 raw white data:\n");
+ plot_raw(s->white_data);
+#endif /* NEVER */
+ i1pro_absraw_to_abswav(p, 0, s->reflective, 1, &s->cal_factor[0], &s->white_data);
+#ifdef NEVER
+ printf("~1 Std res intmd. cal_factor:\n");
+ plot_wav(m, 0, s->cal_factor[0]);
+#endif /* NEVER */
+ i1pro_absraw_to_abswav(p, 1, s->reflective, 1, &s->cal_factor[1], &s->white_data);
+#ifdef NEVER
+ printf("~1 High intmd. cal_factor:\n");
+ plot_wav(m, 1, s->cal_factor[1]);
+ printf("~1 Std res white ref:\n");
+ plot_wav(m, 0, m->white_ref[0]);
+ printf("~1 High res white ref:\n");
+ plot_wav(m, 1, m->white_ref[1]);
+#endif /* NEVER */
+ ev = i1pro_compute_white_cal(p,
+ s->cal_factor[0], m->white_ref[0], s->cal_factor[0],
+ s->cal_factor[1], m->white_ref[1], s->cal_factor[1],
+ i == i1p_refl_spot);
+ if (ev != I1PRO_RD_TRANSWHITEWARN && ev != I1PRO_OK) {
+ return ev;
+ }
+#ifdef NEVER
+ printf("~1 Std res final cal_factor:\n");
+ plot_wav(m, 0, s->cal_factor[0]);
+ printf("~1 High final cal_factor:\n");
+ plot_wav(m, 1, s->cal_factor[1]);
+#endif /* NEVER */
+ }
+ break;
+
+ case i1p_emiss_spot_na:
+ case i1p_emiss_spot:
+ case i1p_emiss_scan:
+ for (j = 0; j < m->nwav[1]; j++)
+ s->cal_factor[1][j] = EMIS_SCALE_FACTOR * m->emis_coef[1][j];
+ break;
+
+ case i1p_amb_spot:
+ case i1p_amb_flash:
+#ifdef FAKE_AMBIENT
+ for (j = 0; j < m->nwav[1]; j++)
+ s->cal_factor[1][j] = EMIS_SCALE_FACTOR * m->emis_coef[1][j];
+ s->cal_valid = 1;
+#else
+
+ if (m->amb_coef[0] != NULL) {
+ for (j = 0; j < m->nwav[1]; j++)
+ s->cal_factor[1][j] = AMB_SCALE_FACTOR * m->emis_coef[1][j] * m->amb_coef[1][j];
+ s->cal_valid = 1;
+ }
+#endif
+ break;
+ case i1p_trans_spot:
+ case i1p_trans_scan:
+ if (eonly)
+ continue;
+ if (s->cal_valid) {
+ /* (Using cal_factor[] as temp. for i1pro_absraw_to_abswav()) */
+ i1pro_absraw_to_abswav(p, 0, s->reflective, 1, &s->cal_factor[0], &s->white_data);
+ i1pro_absraw_to_abswav(p, 1, s->reflective, 1, &s->cal_factor[1], &s->white_data);
+ ev = i1pro_compute_white_cal(p, s->cal_factor[0], NULL, s->cal_factor[0],
+ s->cal_factor[1], NULL, s->cal_factor[1], 0);
+ if (ev != I1PRO_RD_TRANSWHITEWARN && ev != I1PRO_OK) {
+ return ev;
+ }
+ }
+ break;
+ }
+ }
+ }
+ return ev;
+}
+
+#ifdef SALONEINSTLIB
+# define ONEDSTRAYLIGHTUS
+#endif
+
/* Create or re-create high resolution mode references */
i1pro_code i1pro_create_hr(i1pro *p) {
i1proimp *m = (i1proimp *)p->m;
i1pro_code ev = I1PRO_OK;
int refl;
+ double twidth = HIGHRES_WIDTH;
int i, j, k, cx, sx;
/* If we don't have any way of converting raw2wav (ie. RevE polinomial equations), */
/* use the orginal filters to figure this out. */
- if (p->itype != instI1Pro2 && m->raw2wav == NULL) {
+ if (m->raw2wav == NULL
+#ifndef ANALIZE_EXISTING
+ && p->itype != instI1Pro2
+#endif
+ ) {
i1pro_fc coeff[100][16]; /* Existing filter cooefficients */
i1pro_xp xp[101]; /* Crossover points each side of filter */
i1pro_fs fshape[100 * 16]; /* Existing filter shape */
@@ -8101,51 +8516,55 @@ i1pro_code i1pro_create_hr(i1pro *p) {
}
#endif /* HIGH_RES_PLOT */
+// a1logd(p->log,3,"computing crossover points\n");
/* Compute the crossover points between each filter */
for (i = 0; i < (m->nwav[0]-1); i++) {
double den, y1, y2, y3, y4, yn, xn; /* Location of intersection */
+ double eps = 1e-6; /* Numerical tollerance */
+ double besty = -1e6;
/* between filter i and i+1, we want to find the two */
/* raw indexes where the weighting values cross over */
/* Do a brute force search to avoid making assumptions */
- /* about the raw order */
+ /* about the raw order. */
for (j = 0; j < (m->mtx_o.nocoef[i]-1); j++) {
for (k = 0; k < (m->mtx_o.nocoef[i+1]-1); k++) {
-// printf("~1 checking %d, %d: %d = %d, %d = %d\n",j,k, coeff[i][j].ix, coeff[i+1][k].ix, coeff[i][j+1].ix, coeff[i+1][k+1].ix);
if (coeff[i][j].ix == coeff[i+1][k].ix
- && coeff[i][j+1].ix == coeff[i+1][k+1].ix
- && coeff[i][j].we > 0.0 && coeff[i][j+1].we > 0.0
- && coeff[i][k].we > 0.0 && coeff[i][k+1].we > 0.0
- && (( coeff[i][j].we >= coeff[i+1][k].we
- && coeff[i][j+1].we <= coeff[i+1][k+1].we)
- || ( coeff[i][j].we <= coeff[i+1][k].we
- && coeff[i][j+1].we >= coeff[i+1][k+1].we))) {
-// printf("~1 got it at %d, %d: %d = %d, %d = %d\n",j,k, coeff[i][j].ix, coeff[i+1][k].ix, coeff[i][j+1].ix, coeff[i+1][k+1].ix);
- goto gotit;
+ && coeff[i][j+1].ix == coeff[i+1][k+1].ix) {
+
+// a1logd(p->log,3,"got it at %d, %d: %d = %d, %d = %d\n",j,k, coeff[i][j].ix, coeff[i+1][k].ix, coeff[i][j+1].ix, coeff[i+1][k+1].ix);
+
+ /* Compute the intersection of the two line segments */
+ y1 = coeff[i][j].we;
+ y2 = coeff[i][j+1].we;
+ y3 = coeff[i+1][k].we;
+ y4 = coeff[i+1][k+1].we;
+// a1logd(p->log,3,"y1 %f, y2 %f, y3 %f, y4 %f\n",y1, y2, y3, y4);
+ den = -y4 + y3 + y2 - y1;
+ if (fabs(den) < eps)
+ continue;
+ yn = (y2 * y3 - y1 * y4)/den;
+ xn = (y3 - y1)/den;
+ if (xn < -eps || xn > (1.0 + eps))
+ continue;
+// a1logd(p->log,3,"den = %f, yn = %f, xn = %f\n",den,yn,xn);
+ if (yn > besty) {
+ xp[i+1].wav = XSPECT_WL(m->wl_short[0], m->wl_long[0], m->nwav[0], i + 0.5);
+ xp[i+1].raw = (1.0 - xn) * coeff[i][j].ix + xn * coeff[i][j+1].ix;
+ xp[i+1].wei = yn;
+ besty = yn;
+// a1logd(p->log,3,"Intersection %d: wav %f, raw %f, wei %f\n",i+1,xp[i+1].wav,xp[i+1].raw,xp[i+1].wei);
+// a1logd(p->log,3,"Found new best y %f\n",yn);
+ }
+// a1logd(p->log,3,"\n");
}
}
}
- gotit:;
- if (j >= m->mtx_o.nocoef[i]) { /* Assert */
- a1loge(p->log,1,"i1pro: failed to locate crossover between resampling filters\n");
+ if (besty < 0.0) { /* Assert */
+ a1logw(p->log,"i1pro: failed to locate crossover between resampling filters\n");
return I1PRO_INT_ASSERT;
}
-// printf("~1 %d: overlap at %d, %d: %f : %f, %f : %f\n",i, j,k, coeff[i][j].we, coeff[i+1][k].we, coeff[i][j+1].we, coeff[i+1][k+1].we);
-
- /* Compute the intersection of the two line segments */
- y1 = coeff[i][j].we;
- y2 = coeff[i][j+1].we;
- y3 = coeff[i+1][k].we;
- y4 = coeff[i+1][k+1].we;
- den = -y4 + y3 + y2 - y1;
- yn = (y2 * y3 - y1 * y4)/den;
- xn = (y3 - y1)/den;
-// printf("~1 den = %f, yn = %f, xn = %f\n",den,yn,xn);
- xp[i+1].wav = XSPECT_WL(m->wl_short[0], m->wl_long[0], m->nwav[0], i + 0.5);
- xp[i+1].raw = (1.0 - xn) * coeff[i][j].ix + xn * coeff[i][j+1].ix;
- xp[i+1].wei = yn;
-// printf("Intersection %d: wav %f, raw %f, wei %f\n",i+1,xp[i+1].wav,xp[i+1].raw,xp[i+1].wei);
-// printf("\n");
+// a1logd(p->log,3,"\n");
}
/* Add the two points for the end filters */
@@ -8177,7 +8596,7 @@ i1pro_code i1pro_create_hr(i1pro *p) {
}
}
if (j >= m->mtx_o.nocoef[0]) { /* Assert */
- a1loge(p->log,1,"i1pro: failed to end crossover\n");
+ a1loge(p->log,1,"i1pro: failed to find end crossover\n");
return I1PRO_INT_ASSERT;
}
@@ -8216,7 +8635,7 @@ i1pro_code i1pro_create_hr(i1pro *p) {
}
}
if (j >= m->mtx_o.nocoef[m->nwav[0]-1]) { /* Assert */
- a1loge(p->log,1,"i1pro: failed to end crossover\n");
+ a1loge(p->log,1,"i1pro: failed to find end crossover\n");
return I1PRO_INT_ASSERT;
}
den = -y4 + y3 + y2 - y1;
@@ -8277,6 +8696,7 @@ i1pro_code i1pro_create_hr(i1pro *p) {
avgdev[0] = 0.0;
m->raw2wav->fit_rspl(m->raw2wav, 0, sd, m->nwav[0]+1, glow, ghigh, gres, vlow, vhigh, 0.5, avgdev, NULL);
+ }
#ifdef HIGH_RES_PLOT
/* Plot raw to wav lookup */
@@ -8299,99 +8719,98 @@ i1pro_code i1pro_create_hr(i1pro *p) {
}
printf("CCD bin to wavelength mapping of original filters + rspl:\n");
- do_plot6(xx, yy, y2, NULL, NULL, NULL, NULL, m->nwav+1);
+ do_plot6(xx, yy, y2, NULL, NULL, NULL, NULL, m->nwav[0]+1);
free_dvector(xx, 0, m->nwav[0]+1);
free_dvector(yy, 0, m->nwav[0]+1);
free_dvector(y2, 0, m->nwav[0]+1);
}
#endif /* HIGH_RES_PLOT */
- }
- }
#ifdef ANALIZE_EXISTING
- /* Convert each weighting curves values into normalized values and */
- /* accumulate into a single curve. */
- if (!m->hr_inited) {
- for (i = 0; i < m->nwav[0]; i++) {
- double cwl; /* center wavelegth */
- double weight = 0.0;
+ /* Convert each weighting curves values into normalized values and */
+ /* accumulate into a single curve. */
+ if (!m->hr_inited) {
+ for (i = 0; i < m->nwav[0]; i++) {
+ double cwl; /* center wavelegth */
+ double weight = 0.0;
- for (j = 0; j < (m->mtx_o.nocoef[i]); j++) {
- double w1, w2, cellw;
+ for (j = 0; j < (m->mtx_o.nocoef[i]); j++) {
+ double w1, w2, cellw;
- /* Translate CCD cell boundaries index to wavelength */
- w1 = i1pro_raw2wav_uncal(p, (double)coeff[i][j].ix - 0.5);
+ /* Translate CCD cell boundaries index to wavelength */
+ w1 = i1pro_raw2wav_uncal(p, (double)coeff[i][j].ix - 0.5);
- w2 = i1pro_raw2wav_uncal(p, (double)coeff[i][j].ix + 0.5);
+ w2 = i1pro_raw2wav_uncal(p, (double)coeff[i][j].ix + 0.5);
- cellw = fabs(w2 - w1);
+ cellw = fabs(w2 - w1);
- cwl = XSPECT_WL(m->wl_short[0], m->wl_long[0], m->nwav[0], i);
+ cwl = XSPECT_WL(m->wl_short[0], m->wl_long[0], m->nwav[0], i);
- /* Translate CCD index to wavelength */
- fshape[ncp].wl = i1pro_raw2wav_uncal(p, (double)coeff[i][j].ix) - cwl;
- fshape[ncp].we = coeff[i][j].we / (0.09 * cellw);
- ncp++;
+ /* Translate CCD index to wavelength */
+ fshape[ncp].wl = i1pro_raw2wav_uncal(p, (double)coeff[i][j].ix) - cwl;
+ fshape[ncp].we = coeff[i][j].we / (0.09 * cellw);
+ ncp++;
+ }
}
- }
- /* Now sort by wavelength */
+ /* Now sort by wavelength */
#define HEAP_COMPARE(A,B) (A.wl < B.wl)
- HEAPSORT(i1pro_fs, fshape, ncp)
+ HEAPSORT(i1pro_fs, fshape, ncp)
#undef HEAP_COMPARE
- /* Strip out leading zero's */
- for (i = 0; i < ncp; i++) {
- if (fshape[i].we != 0.0)
- break;
- }
- if (i > 1 && i < ncp) {
- memmove(&fshape[0], &fshape[i-1], sizeof(i1pro_fs) * (ncp - i + 1));
- ncp = ncp - i + 1;
+ /* Strip out leading zero's */
for (i = 0; i < ncp; i++) {
if (fshape[i].we != 0.0)
break;
}
- }
+ if (i > 1 && i < ncp) {
+ memmove(&fshape[0], &fshape[i-1], sizeof(i1pro_fs) * (ncp - i + 1));
+ ncp = ncp - i + 1;
+ for (i = 0; i < ncp; i++) {
+ if (fshape[i].we != 0.0)
+ break;
+ }
+ }
#ifdef HIGH_RES_PLOT
- /* Plot the shape of the accumulated curve */
- {
- double *x1 = dvectorz(0, ncp-1);
- double *y1 = dvectorz(0, ncp-1);
+ /* Plot the shape of the accumulated curve */
+ {
+ double *x1 = dvectorz(0, ncp-1);
+ double *y1 = dvectorz(0, ncp-1);
- for (i = 0; i < ncp; i++) {
- double x;
- x1[i] = fshape[i].wl;
- y1[i] = fshape[i].we;
- }
- printf("Accumulated curve:\n");
- do_plot(x1, y1, NULL, NULL, ncp);
+ for (i = 0; i < ncp; i++) {
+ double x;
+ x1[i] = fshape[i].wl;
+ y1[i] = fshape[i].we;
+ }
+ printf("Original accumulated curve:\n");
+ do_plot(x1, y1, NULL, NULL, ncp);
- free_dvector(x1, 0, ncp-1);
- free_dvector(y1, 0, ncp-1);
- }
+ free_dvector(x1, 0, ncp-1);
+ free_dvector(y1, 0, ncp-1);
+ }
#endif /* HIGH_RES_PLOT */
#ifdef HIGH_RES_DEBUG
- /* Check that the orginal filter sums to a constant */
- {
- double x, sum;
-
- for (x = 0.0; x < 10.0; x += 0.2) {
- sum = 0;
- sum += lin_fshape(fshape, ncp, x - 30.0);
- sum += lin_fshape(fshape, ncp, x - 20.0);
- sum += lin_fshape(fshape, ncp, x - 10.0);
- sum += lin_fshape(fshape, ncp, x - 0.0);
- sum += lin_fshape(fshape, ncp, x + 10.0);
- sum += lin_fshape(fshape, ncp, x + 20.0);
- printf("Offset %f, sum %f\n",x, sum);
+ /* Check that the orginal filter sums to a constant */
+ {
+ double x, sum;
+
+ for (x = 0.0; x < 10.0; x += 0.2) {
+ sum = 0;
+ sum += lin_fshape(fshape, ncp, x - 30.0);
+ sum += lin_fshape(fshape, ncp, x - 20.0);
+ sum += lin_fshape(fshape, ncp, x - 10.0);
+ sum += lin_fshape(fshape, ncp, x - 0.0);
+ sum += lin_fshape(fshape, ncp, x + 10.0);
+ sum += lin_fshape(fshape, ncp, x + 20.0);
+ printf("Offset %f, sum %f\n",x, sum);
+ }
}
- }
#endif /* HIGH_RES_DEBUG */
- }
+ }
#endif /* ANALIZE_EXISTING */
+ } /* End of compute wavelength cal from existing filters */
#ifdef COMPUTE_DISPERSION
if (!m->hr_inited) {
@@ -8498,7 +8917,7 @@ i1pro_code i1pro_create_hr(i1pro *p) {
datao vlow, vhigh;
int gres[2];
double avgdev[2];
- int ii;
+ int ix, ii;
co pp;
if ((trspl = new_rspl(RSPL_NOFLAGS, 1, 1)) == NULL) {
@@ -8506,6 +8925,7 @@ i1pro_code i1pro_create_hr(i1pro *p) {
return I1PRO_INT_NEW_RSPL_FAILED;
}
+ /* For ref, emis, ambient */
for (ii = 0; ii < 3; ii++) {
double **ref2, *ref1;
double smooth = 1.0;
@@ -8513,17 +8933,26 @@ i1pro_code i1pro_create_hr(i1pro *p) {
if (ii == 0) {
ref1 = m->white_ref[0];
ref2 = &m->white_ref[1];
- smooth = 0.5;
+// smooth = 0.5;
+ smooth = 1.5;
} else if (ii == 1) {
+ /* Don't create high res. from low res., if there is */
+ /* a better, calibrated cal read from .cal file */
+ if (m->emis_coef[1] != NULL) {
+ if (m->emis_hr_cal)
+ continue;
+ free(m->emis_coef[1]); /* Regenerate it anyway */
+ }
ref1 = m->emis_coef[0];
ref2 = &m->emis_coef[1];
- smooth = 500.0; /* Hmm. Lagrange may work better ?? */
+ m->emis_hr_cal = 0;
+ smooth = 10.0;
} else {
if (m->amb_coef[0] == NULL)
break;
ref1 = m->amb_coef[0];
ref2 = &m->amb_coef[1];
- smooth = 0.2;
+ smooth = 1.0;
}
if (ref1 == NULL)
@@ -8531,46 +8960,58 @@ i1pro_code i1pro_create_hr(i1pro *p) {
vlow[0] = 1e6;
vhigh[0] = -1e6;
- for (i = 0; i < m->nwav[0]; i++) {
+ for (ix = i = 0; i < m->nwav[0]; i++) {
- sd[i].p[0] = XSPECT_WL(m->wl_short[0], m->wl_long[0], m->nwav[0], i);
- sd[i].v[0] = ref1[i];
- sd[i].w = 1.0;
+ sd[ix].p[0] = XSPECT_WL(m->wl_short[0], m->wl_long[0], m->nwav[0], i);
+ sd[ix].v[0] = ref1[i];
+ sd[ix].w = 1.0;
- if (sd[i].v[0] < vlow[0])
- vlow[0] = sd[i].v[0];
- if (sd[i].v[0] > vhigh[0])
- vhigh[0] = sd[i].v[0];
+ if (sd[ix].v[0] < vlow[0])
+ vlow[0] = sd[ix].v[0];
+ if (sd[ix].v[0] > vhigh[0])
+ vhigh[0] = sd[ix].v[0];
+ ix++;
}
- if (ii == 1) { /* fudge factors */
+ /* Our upsampling is OK for reflective and ambient cal's, */
+ /* but isn't so good for the emissive cal., especially */
+ /* on the i1pro2. We'll get an opportunity to fix it */
+ /* when we do a reflective calibration, by using the */
+ /* smoothness of the lamp as a reference. */
-#ifdef NEVER /* Doesn't help */
- /* Increase boost at short wavelegths */
- if (m->wl_short[1] < 380.0) {
- sd[i].p[0] = m->wl_short[1];
- sd[i].v[0] = sd[0].v[0] * (1.0 + (380.0 - m->wl_short[1])/20.0);
- sd[i++].w = 0.6;
- }
-#endif
+ /* Add inbetween points to restrain dips and peaks in interp. */
+ for (i = 0; i < (m->nwav[0]-1); i++) {
-#ifdef NEVER /* Doesn't help */
- /* Reduces boost at long wavelegths */
- if (m->wl_long[1] > 730.0) {
- sd[i].p[0] = m->wl_long[1];
- sd[i].v[0] = sd[m->nwav[0]-1].v[0] * (1.0 + (m->wl_long[1] - 730.0)/100.0);
- sd[i++].w = 0.3;
- }
-#endif
+ /* Use linear interp extra points */
+ double wt = 0.05;
+
+ sd[ix].p[0] = XSPECT_WL(m->wl_short[0], m->wl_long[0], m->nwav[0], i + 0.3333);
+ sd[ix].v[0] = (2.0 * ref1[i] + ref1[i+1])/3.0;
+ sd[ix].w = wt;
+
+ if (sd[ix].v[0] < vlow[0])
+ vlow[0] = sd[ix].v[0];
+ if (sd[ix].v[0] > vhigh[0])
+ vhigh[0] = sd[ix].v[0];
+ ix++;
+
+ sd[ix].p[0] = XSPECT_WL(m->wl_short[0], m->wl_long[0], m->nwav[0], i + 0.66667);
+ sd[ix].v[0] = (ref1[i] + 2.0 * ref1[i+1])/3.0;
+ sd[ix].w = wt;
+
+ if (sd[ix].v[0] < vlow[0])
+ vlow[0] = sd[ix].v[0];
+ if (sd[ix].v[0] > vhigh[0])
+ vhigh[0] = sd[ix].v[0];
+ ix++;
}
-
+
glow[0] = m->wl_short[1];
ghigh[0] = m->wl_long[1];
- gres[0] = m->nwav[1];
+ gres[0] = 3 * m->nwav[1];
avgdev[0] = 0.0;
- trspl->fit_rspl_w(trspl, 0, sd, i, glow, ghigh, gres, vlow, vhigh, smooth, avgdev, NULL);
-
+ trspl->fit_rspl_w(trspl, 0, sd, ix, glow, ghigh, gres, vlow, vhigh, smooth, avgdev, NULL);
if ((*ref2 = (double *)calloc(m->nwav[1], sizeof(double))) == NULL) {
trspl->del(trspl);
a1logw(p->log, "i1pro: malloc ref2 failed!\n");
@@ -8583,6 +9024,7 @@ i1pro_code i1pro_create_hr(i1pro *p) {
trspl->interp(trspl, &pp);
(*ref2)[i] = pp.v[0];
}
+
#ifdef HIGH_RES_PLOT
/* Plot original and upsampled reference */
{
@@ -8593,27 +9035,13 @@ i1pro_code i1pro_create_hr(i1pro *p) {
for (i = 0; i < m->nwav[1]; i++) {
double wl = m->wl_short[1] + (double)i * (m->wl_long[1] - m->wl_short[1])/(m->nwav[1]-1.0);
x1[i] = wl;
- y1[i] = (*ref2)[i];
- if (wl < m->wl_short[0] || wl > m->wl_long[0]) {
- y2[i] = 0.0;
- } else {
- double x, wl1, wl2;
- for (j = 0; j < (m->nwav[0]-1); j++) {
- wl1 = XSPECT_WL(m->wl_short[0], m->wl_long[0], m->nwav[0], j);
- wl2 = XSPECT_WL(m->wl_short[0], m->wl_long[0], m->nwav[0], j+1);
- if (wl >= wl1 && wl <= wl2)
- break;
- }
- x = (wl - wl1)/(wl2 - wl1);
- y2[i] = ref1[j] + (ref1[j+1] - ref1[j]) * x;
- }
+ y1[i] = wav_lerp_cv(m, 0, ref1, wl, 0.0);
+ y2[i] = (*ref2)[i];
}
printf("Original and up-sampled ");
if (ii == 0) {
printf("Reflective cal. curve:\n");
} else if (ii == 1) {
- ref1 = m->emis_coef[0];
- ref2 = &m->emis_coef[1];
printf("Emission cal. curve:\n");
} else {
printf("Ambient cal. curve:\n");
@@ -8630,7 +9058,7 @@ i1pro_code i1pro_create_hr(i1pro *p) {
/* Upsample stray light */
if (p->itype == instI1Pro2) {
-#ifdef SALONEINSTLIB
+#ifdef ONEDSTRAYLIGHTUS
double **slp; /* 2D Array of stray light values */
/* Then the 2D stray light using linear interpolation */
@@ -8676,7 +9104,7 @@ i1pro_code i1pro_create_hr(i1pro *p) {
}
}
}
-#else /* !SALONEINSTLIB */
+#else /* !ONEDSTRAYLIGHTUS */
/* Then setup 2D stray light using rspl */
if ((trspl = new_rspl(RSPL_NOFLAGS, 2, 1)) == NULL) {
a1logd(p->log,1,"i1pro: creating rspl for high res conversion failed\n");
@@ -8707,7 +9135,7 @@ i1pro_code i1pro_create_hr(i1pro *p) {
avgdev[1] = 0.0;
trspl->fit_rspl_w(trspl, 0, sd, m->nwav[0] * m->nwav[0], glow, ghigh, gres, NULL, NULL, 0.5, avgdev, NULL);
-#endif /* !SALONEINSTLIB */
+#endif /* !ONEDSTRAYLIGHTUS */
m->straylight[1] = dmatrixz(0, m->nwav[1]-1, 0, m->nwav[1]-1);
@@ -8717,7 +9145,7 @@ i1pro_code i1pro_create_hr(i1pro *p) {
double p0, p1;
p0 = XSPECT_WL(m->wl_short[1], m->wl_long[1], m->nwav[1], i);
p1 = XSPECT_WL(m->wl_short[1], m->wl_long[1], m->nwav[1], j);
-#ifdef SALONEINSTLIB
+#ifdef ONEDSTRAYLIGHTUS
/* Do linear interp with clipping at ends */
{
int x0, x1, y0, y1;
@@ -8748,11 +9176,11 @@ i1pro_code i1pro_create_hr(i1pro *p) {
+ w1 * v0 * slp[x1][y0]
+ w1 * v1 * slp[x1][y1];
}
-#else /* !SALONEINSTLIB */
+#else /* !ONEDSTRAYLIGHTUS */
pp.p[0] = p0;
pp.p[1] = p1;
trspl->interp(trspl, &pp);
-#endif /* !SALONEINSTLIB */
+#endif /* !ONEDSTRAYLIGHTUS */
m->straylight[1][i][j] = pp.v[0] * HIGHRES_WIDTH/10.0;
if (m->straylight[1][i][j] > 0.0)
m->straylight[1][i][j] = 0.0;
@@ -8823,39 +9251,48 @@ i1pro_code i1pro_create_hr(i1pro *p) {
}
#endif /* HIGH_RES_PLOT */
-#ifdef SALONEINSTLIB
+#ifdef ONEDSTRAYLIGHTUS
free_dmatrix(slp, 0, m->nwav[0]-1, 0, m->nwav[0]-1);
-#else /* !SALONEINSTLIB */
+#else /* !ONEDSTRAYLIGHTUS */
trspl->del(trspl);
-#endif /* !SALONEINSTLIB */
+#endif /* !ONEDSTRAYLIGHTUS */
}
}
/* Create or re-create the high resolution filters */
for (refl = 0; refl < 2; refl++) { /* for emis/trans and reflective */
+#define MXNOWL 500 /* Max hires bands */
+#define MXNOFC 64 /* Max hires coeffs */
+
+#ifndef USE_TRI_LAGRANGE /* Use decimation filter */
+ int super = 0; /* nz if we're super sampling */
double fshmax; /* filter shape max wavelength from center */
-#define MXNOFC 64
- i1pro_fc coeff2[500][MXNOFC]; /* New filter cooefficients */
- double twidth;
+ i1pro_fc coeff2[MXNOWL][MXNOFC]; /* New filter cooefficients */
/* Construct a set of filters that uses more CCD values */
- twidth = HIGHRES_WIDTH;
- if (m->nwav[1] > 500) { /* Assert */
+ if (twidth < 3.0)
+ super = 1;
+
+ if (m->nwav[1] > MXNOWL) { /* Assert */
a1loge(p->log,1,"High res filter has too many bands\n");
return I1PRO_INT_ASSERT;
}
- /* Use a simple means of determining width */
- for (fshmax = 50.0; fshmax >= 0.0; fshmax -= 0.1) {
- if (fabs(lanczos2(twidth, fshmax)) > 0.0001) {
- fshmax += 0.1;
- break;
+ if (super) {
+ fshmax = 5.0;
+ } else {
+ /* Use a simple means of determining width */
+ for (fshmax = 50.0; fshmax >= 0.0; fshmax -= 0.1) {
+ if (fabs(lanczos2(twidth, fshmax)) > 0.0001) {
+ fshmax += 0.1;
+ break;
+ }
+ }
+ if (fshmax <= 0.0) {
+ a1logw(p->log, "i1pro: fshmax search failed\n");
+ return I1PRO_INT_ASSERT;
}
- }
- if (fshmax <= 0.0) {
- a1logw(p->log, "i1pro: fshmax search failed\n");
- return I1PRO_INT_ASSERT;
}
// printf("~1 fshmax = %f\n",fshmax);
@@ -8886,164 +9323,108 @@ i1pro_code i1pro_create_hr(i1pro *p) {
return I1PRO_INT_MALLOC;
}
- /* For all the useful CCD bands */
- for (i = 1; i < 127; i++) {
- double w1, wl, w2;
+ if (super) { /* Use linear interpolation */
- /* Translate CCD center and boundaries to calibrated wavelength */
- wl = i1pro_raw2wav(p, refl, (double)i);
- w1 = i1pro_raw2wav(p, refl, (double)i - 0.5);
- w2 = i1pro_raw2wav(p, refl, (double)i + 0.5);
+ /* For all the useful CCD bands */
+ for (i = 1; i < (127-1); i++) {
+ double wl, wh;
-// printf("~1 CCD %d, w1 %f, wl %f, w2 %f\n",i,w1,wl,w2);
-
- /* For each filter */
- for (j = 0; j < m->nwav[1]; j++) {
- double cwl, rwl; /* center, relative wavelegth */
- double we;
-
- cwl = m->wl_short[1] + (double)j * (m->wl_long[1] - m->wl_short[1])/(m->nwav[1]-1.0);
- rwl = wl - cwl; /* relative wavelength to filter */
-
- if (fabs(w1 - cwl) > fshmax && fabs(w2 - cwl) > fshmax)
- continue; /* Doesn't fall into this filter */
+ /* Translate CCD centers to calibrated wavelength */
+ wh = i1pro_raw2wav(p, refl, (double)(i+0));
+ wl = i1pro_raw2wav(p, refl, (double)(i+1));
- /* Integrate in 0.05 nm increments from filter shape */
- /* using triangular integration. */
- {
- int nn;
- double lw, ll;
-
- nn = (int)(fabs(w2 - w1)/0.05 + 0.5); /* Number to integrate over */
-
- lw = w1; /* start at lower boundary of CCD cell */
- ll = lanczos2(twidth, w1- cwl);
- we = 0.0;
- for (k = 0; k < nn; k++) {
- double cw, cl;
-
-#if defined(__APPLE__) && defined(__POWERPC__)
- gcc_bug_fix(k);
-#endif
- cw = w1 + (k+1.0)/(nn +1.0) * (w2 - w1); /* wl to sample */
- cl = lanczos2(twidth, cw- cwl);
- we += 0.5 * (cl + ll) * (lw - cw); /* Area under triangle */
- ll = cl;
- lw = cw;
+ /* For each filter */
+ for (j = 0; j < m->nwav[1]; j++) {
+ double cwl; /* Center wavelength */
+ double we; /* Weighting */
+ double wwwe = 1.0;
+
+ cwl = m->wl_short[1] + (double)j * (m->wl_long[1] - m->wl_short[1])
+ /(m->nwav[1]-1.0);
+//printf("~1 wl %f, wh %f, cwl %f\n",wl,wh,cwl);
+ if (cwl < (wl - 1e-6) || cwl > (wh + 1e-6))
+ continue; /* Doesn't fall into this filter */
+
+ if ((m->mtx_c[1][refl].nocoef[j]+1) >= MXNOFC) {
+ a1logw(p->log, "i1pro: run out of high res filter space\n");
+ return I1PRO_INT_ASSERT;
}
- }
-
- if (m->mtx_c[1][refl].nocoef[j] >= MXNOFC) {
- a1logw(p->log, "i1pro: run out of high res filter space\n");
- return I1PRO_INT_ASSERT;
- }
-
- coeff2[j][m->mtx_c[1][refl].nocoef[j]].ix = i;
- coeff2[j][m->mtx_c[1][refl].nocoef[j]++].we = we;
-// printf("~1 filter %d, cwl %f, rwl %f, ix %d, we %f, nocoefs %d\n",j,cwl,rwl,i,we,m->mtx_c[1][refl].nocoef[j]-1);
- }
- }
-
-#ifdef HIGH_RES_PLOT
- /* Plot resampled curves */
- {
- double *xx, *ss;
- double **yy;
-
- xx = dvectorz(-1, m->nraw-1); /* X index */
- yy = dmatrixz(0, 5, -1, m->nraw-1); /* Curves distributed amongst 5 graphs */
-
- for (i = 0; i < m->nraw; i++)
- xx[i] = i;
- /* For each output wavelength */
- for (j = 0; j < m->nwav[1]; j++) {
- i = j % 5;
+ we = (cwl - wl)/(wh - wl);
+// wwwe = 3.3/(wh - wl);
- /* For each matrix value */
- for (k = 0; k < m->mtx_c[1][refl].nocoef[j]; k++) {
- yy[5][coeff2[j][k].ix] += 0.5 * coeff2[j][k].we;
- yy[i][coeff2[j][k].ix] = coeff2[j][k].we;
+ coeff2[j][m->mtx_c[1][refl].nocoef[j]].ix = i;
+ coeff2[j][m->mtx_c[1][refl].nocoef[j]++].we = wwwe * we;
+//printf("~1 filter %d, cwl %f, ix %d, we %f, nocoefs %d\n",j,cwl,i,we,m->mtx_c[1][refl].nocoef[j]);
+ coeff2[j][m->mtx_c[1][refl].nocoef[j]].ix = i+1;
+ coeff2[j][m->mtx_c[1][refl].nocoef[j]++].we = wwwe * (1.0 - we);
+//printf("~1 filter %d, cwl %f, ix %d, we %f, nocoefs %d\n",j,cwl,i+1,1.0-we,m->mtx_c[1][refl].nocoef[j]);
}
}
- printf("Hi-Res wavelength sampling curves:\n");
- do_plot6(xx, yy[0], yy[1], yy[2], yy[3], yy[4], yy[5], m->nraw);
- free_dvector(xx, -1, m->nraw-1);
- free_dmatrix(yy, 0, 2, -1, m->nraw-1);
- }
-#endif /* HIGH_RES_PLOT */
-
- /* Normalise the filters area in CCD space, while maintaining the */
- /* total contribution of each CCD at the target too. */
- {
- int ii;
- double tot = 0.0;
- double ccdweight[128], avgw; /* Weighting determined by cell widths */
- double ccdsum[128];
-
- /* Normalize the overall filter weightings */
- for (j = 0; j < m->nwav[1]; j++)
- for (k = 0; k < m->mtx_c[1][refl].nocoef[j]; k++)
- tot += coeff2[j][k].we;
- tot /= (double)m->nwav[1];
- for (j = 0; j < m->nwav[1]; j++)
- for (k = 0; k < m->mtx_c[1][refl].nocoef[j]; k++)
- coeff2[j][k].we /= tot;
-
- /* Determine the relative weights for each CCD */
- avgw = 0.0;
+ } else {
+ /* For all the useful CCD bands */
for (i = 1; i < 127; i++) {
+ double w1, wl, w2;
- ccdweight[i] = i1pro_raw2wav(p, refl, (double)i - 0.5)
- - i1pro_raw2wav(p, refl, (double)i + 0.5);
- ccdweight[i] = fabs(ccdweight[i]);
- avgw += ccdweight[i];
- }
- avgw /= 126.0;
- // ~~this isn't right because not all CCD's get used!!
+ /* Translate CCD center and boundaries to calibrated wavelength */
+ wl = i1pro_raw2wav(p, refl, (double)i);
+ w1 = i1pro_raw2wav(p, refl, (double)i - 0.5);
+ w2 = i1pro_raw2wav(p, refl, (double)i + 0.5);
-#ifdef NEVER
- /* Itterate */
- for (ii = 0; ; ii++) {
+// printf("~1 CCD %d, w1 %f, wl %f, w2 %f\n",i,w1,wl,w2);
- /* Normalize the individual filter weightings */
+ /* For each filter */
for (j = 0; j < m->nwav[1]; j++) {
- double err;
- tot = 0.0;
- for (k = 0; k < m->mtx_c[1][refl].nocoef[j]; k++)
- tot += coeff2[j][k].we;
- err = 1.0 - tot;
-
- for (k = 0; k < m->mtx_c[1][refl].nocoef[j]; k++)
- coeff2[j][k].we += err/m->mtx_c[1][refl].nocoef[j];
-// for (k = 0; k < m->mtx_c[1][refl].nocoef[j]; k++)
-// coeff2[j][k].we *= 1.0/tot;
- }
+ double cwl, rwl; /* center, relative wavelegth */
+ double we;
- /* Check CCD sums */
- for (i = 1; i < 127; i++)
- ccdsum[i] = 0.0;
+ cwl = m->wl_short[1] + (double)j * (m->wl_long[1] - m->wl_short[1])
+ /(m->nwav[1]-1.0);
+ rwl = wl - cwl; /* relative wavelength to filter */
- for (j = 0; j < m->nwav[1]; j++) {
- for (k = 0; k < m->mtx_c[1][refl].nocoef[j]; k++)
- ccdsum[coeff2[j][k].ix] += coeff2[j][k].we;
- }
+ if (fabs(w1 - cwl) > fshmax && fabs(w2 - cwl) > fshmax)
+ continue; /* Doesn't fall into this filter */
- if (ii >= 6)
- break;
+ /* Integrate in 0.05 nm increments from filter shape */
+ /* using triangular integration. */
+ {
+ int nn;
+ double lw, ll;
+#ifdef FAST_HIGH_RES_SETUP
+# define FINC 0.2
+#else
+# define FINC 0.05
+#endif
+ nn = (int)(fabs(w2 - w1)/0.2 + 0.5); /* Number to integrate over */
+
+ lw = w1; /* start at lower boundary of CCD cell */
+ ll = lanczos2(twidth, w1- cwl);
+ we = 0.0;
+ for (k = 0; k < nn; k++) {
+ double cw, cl;
- /* Readjust CCD sum */
- for (i = 1; i < 127; i++) {
- ccdsum[i] = ccdtsum[i]/ccdsum[i]; /* Amount to adjust */
- }
+#if defined(__APPLE__) && defined(__POWERPC__)
+ gcc_bug_fix(k);
+#endif
+ cw = w1 + (k+1.0)/(nn +1.0) * (w2 - w1); /* wl to sample */
+ cl = lanczos2(twidth, cw- cwl);
+ we += 0.5 * (cl + ll) * (lw - cw); /* Area under triangle */
+ ll = cl;
+ lw = cw;
+ }
+ }
- for (j = 0; j < m->nwav[1]; j++) {
- for (k = 0; k < m->mtx_c[1][refl].nocoef[j]; k++)
- coeff2[j][k].we *= ccdsum[coeff2[j][k].ix];
+ if (m->mtx_c[1][refl].nocoef[j] >= MXNOFC) {
+ a1logw(p->log, "i1pro: run out of high res filter space\n");
+ return I1PRO_INT_ASSERT;
+ }
+
+ coeff2[j][m->mtx_c[1][refl].nocoef[j]].ix = i;
+ coeff2[j][m->mtx_c[1][refl].nocoef[j]++].we = we;
+// printf("~1 filter %d, cwl %f, rwl %f, ix %d, we %f, nocoefs %d\n",j,cwl,rwl,i,we,m->mtx_c[1][refl].nocoef[j]);
}
}
-#endif /* NEVER */
}
#ifdef HIGH_RES_PLOT
@@ -9069,7 +9450,7 @@ i1pro_code i1pro_create_hr(i1pro *p) {
}
}
- printf("Normalized Hi-Res wavelength sampling curves:\n");
+ printf("Hi-Res wavelength sampling curves %s:\n",refl ? "refl" : "emis");
do_plot6(xx, yy[0], yy[1], yy[2], yy[3], yy[4], yy[5], m->nraw);
free_dvector(xx, -1, m->nraw-1);
free_dmatrix(yy, 0, 2, -1, m->nraw-1);
@@ -9109,93 +9490,229 @@ i1pro_code i1pro_create_hr(i1pro *p) {
/* Set high res tables to new allocations */
m->mtx[1][refl] = m->mtx_c[1][refl];
}
- }
- /* Generate high res. per mode calibration factors. */
- if (!m->hr_inited) {
+#else /* USE_TRI_LAGRANGE, use triangle over lagrange interp */
- m->hr_inited = 1; /* Set so that i1pro_compute_white_cal() etc. does right thing */
+ /* Compute high res. reflective wavelength corrected filters */
+ if ((ev = i1pro_compute_wav_filters(p, 1, refl)) != I1PRO_OK) {
+ a1logd(p->log,2,"i1pro_compute_wav_filters() failed\n");
+ return ev;
+ }
+#endif /* USE_TRI_LAGRANGE */
- for (i = 0; i < i1p_no_modes; i++) {
- i1pro_state *s = &m->ms[i];
+ /* Normalise the filters area in CCD space, while maintaining the */
+ /* total contribution of each CCD at the target too. */
+ /* Hmm. This will wreck super-sample. We should fix it */
+#ifdef DO_CCDNORM /* Normalise CCD values to original */
+ {
+ double x[4], y[4];
+ double avg[2], max[2];
+ double ccdsum[2][128]; /* Target weight/actual for each CCD */
+ double dth[2];
- if (s->cal_factor[1] == NULL)
- s->cal_factor[1] = dvectorz(0, m->nwav[1]-1);
+ avg[0] = avg[1] = 0.0;
+ max[0] = max[1] = 0.0;
+ for (j = 0; j < 128; j++) {
+ ccdsum[0][j] = 0.0;
+ ccdsum[1][j] = 0.0;
+ }
- switch(i) {
- case i1p_refl_spot:
- case i1p_refl_scan:
- if (s->cal_valid) {
- /* (Using cal_factor[] as temp. for i1pro_absraw_to_abswav()) */
-#ifdef NEVER
- printf("~1 regenerating calibration for reflection\n");
- printf("~1 raw white data:\n");
- plot_raw(s->white_data);
-#endif /* NEVER */
- i1pro_absraw_to_abswav(p, 0, s->reflective, 1, &s->cal_factor[0], &s->white_data);
-#ifdef NEVER
- printf("~1 Std res intmd. cal_factor:\n");
- plot_wav(m, 0, s->cal_factor[0]);
-#endif /* NEVER */
- i1pro_absraw_to_abswav(p, 1, s->reflective, 1, &s->cal_factor[1], &s->white_data);
-#ifdef NEVER
- printf("~1 High intmd. cal_factor:\n");
- plot_wav(m, 1, s->cal_factor[1]);
- printf("~1 Std res white ref:\n");
- plot_wav(m, 0, m->white_ref[0]);
- printf("~1 High res white ref:\n");
- plot_wav(m, 1, m->white_ref[1]);
-#endif /* NEVER */
- i1pro_compute_white_cal(p, s->cal_factor[0], m->white_ref[0], s->cal_factor[0],
- s->cal_factor[1], m->white_ref[1], s->cal_factor[1]);
-#ifdef NEVER
- printf("~1 Std res final cal_factor:\n");
- plot_wav(m, 0, s->cal_factor[0]);
- printf("~1 High final cal_factor:\n");
- plot_wav(m, 1, s->cal_factor[1]);
-#endif /* NEVER */
+ /* Compute the weighting of each CCD value in the normal output */
+ for (cx = j = 0; j < m->nwav[0]; j++) { /* For each wavelength */
+
+ /* For each matrix value */
+ sx = m->mtx_o.index[j]; /* Starting index */
+ for (k = 0; k < m->mtx_o.nocoef[j]; k++, cx++, sx++) {
+ ccdsum[0][sx] += m->mtx_o.coef[cx];
+//printf("~1 Norm CCD [%d] %f += [%d] %f\n",sx,ccdsum[0][sx],cx, m->mtx_o.coef[cx]);
+ }
+ }
+
+ /* Compute the weighting of each CCD value in the hires output */
+ for (cx = j = 0; j < m->nwav[1]; j++) { /* For each wavelength */
+
+ /* For each matrix value */
+ sx = m->mtx_c[1][refl].index[j]; /* Starting index */
+ for (k = 0; k < m->mtx_c[1][refl].nocoef[j]; k++, cx++, sx++) {
+ ccdsum[1][sx] += m->mtx_c[1][refl].coef[cx];
+//printf("~1 HiRes CCD [%d] %f += [%d] %f\n",sx,ccdsum[1][sx],cx, m->mtx_c[1][refl].coef[cx]);
+ }
+ }
+
+ /* Figure valid range and extrapolate to edges */
+ dth[0] = 0.0; /* ref */
+// dth[1] = 0.007; /* hires */
+ dth[1] = 0.004; /* hires */
+
+ for (k = 0; k < 2; k++) {
+
+ for (i = 0; i < 128; i++) {
+ if (ccdsum[k][i] > max[k])
+ max[k] = ccdsum[k][i];
+ }
+
+//printf("~1 max[%d] = %f\n",k, max[k]);
+ /* Figure out the valid range */
+ for (i = 64; i >= 0; i--) {
+ if (ccdsum[k][i] > (0.8 * max[k])) {
+ x[0] = (double)i;
+ } else {
+ break;
}
- break;
+ }
+ for (i = 64; i < 128; i++) {
+ if (ccdsum[k][i] > (0.8 * max[k])) {
+ x[3] = (double)i;
+ } else {
+ break;
+ }
+ }
+ /* Space off the last couple of entries */
+ x[0] += (3.0 + 3.0);
+ x[3] -= (3.0 + 3.0);
+ x[1] = floor((2 * x[0] + x[3])/3.0);
+ x[2] = floor((x[0] + 2 * x[3])/3.0);
+
+ for (i = 0; i < 4; i++) {
+ y[i] = 0.0;
+ for (j = -3; j < 4; j++) {
+ y[i] += ccdsum[k][(int)x[i]+j];
+ }
+ y[i] /= 7.0;
+ }
- case i1p_emiss_spot_na:
- case i1p_emiss_spot:
- case i1p_emiss_scan:
- for (j = 0; j < m->nwav[1]; j++)
- s->cal_factor[1][j] = EMIS_SCALE_FACTOR * m->emis_coef[1][j];
- break;
+//printf("~1 extrap nodes %f, %f, %f, %f\n",x[0],x[1],x[2],x[3]);
+//printf("~1 extrap value %f, %f, %f, %f\n",y[0],y[1],y[2],y[3]);
- case i1p_amb_spot:
- case i1p_amb_flash:
-#ifdef FAKE_AMBIENT
- for (j = 0; j < m->nwav[1]; j++)
- s->cal_factor[1][j] = EMIS_SCALE_FACTOR * m->emis_coef[1][j];
- s->cal_valid = 1;
-#else
+ for (i = 0; i < 128; i++) {
+ double xw, yw;
- if (m->amb_coef[0] != NULL) {
- for (j = 0; j < m->nwav[1]; j++)
- s->cal_factor[1][j] = AMB_SCALE_FACTOR * m->emis_coef[1][j] * m->amb_coef[1][j];
- s->cal_valid = 1;
+ xw = (double)i;
+
+ /* Compute interpolated value using Lagrange: */
+ yw = y[0] * (xw-x[1]) * (xw-x[2]) * (xw-x[3])
+ /((x[0]-x[1]) * (x[0]-x[2]) * (x[0]-x[3]))
+ + y[1] * (xw-x[0]) * (xw-x[2]) * (xw-x[3])
+ /((x[1]-x[0]) * (x[1]-x[2]) * (x[1]-x[3]))
+ + y[2] * (xw-x[0]) * (xw-x[1]) * (xw-x[3])
+ /((x[2]-x[0]) * (x[2]-x[1]) * (x[2]-x[3]))
+ + y[3] * (xw-x[0]) * (xw-x[1]) * (xw-x[2])
+ /((x[3]-x[0]) * (x[3]-x[1]) * (x[3]-x[2]));
+
+ if ((xw < x[0] || xw > x[3])
+ && fabs(ccdsum[k][i] - yw)/yw > dth[k]) {
+ ccdsum[k][i] = yw;
}
+ avg[k] += ccdsum[k][i];
+ }
+ avg[k] /= 128.0;
+ }
+
+#ifdef HIGH_RES_PLOT
+ /* Plot target CCD values */
+ {
+ double xx[128], y1[128], y2[128];
+
+ for (i = 0; i < 128; i++) {
+ xx[i] = i;
+ y1[i] = ccdsum[0][i]/avg[0];
+ y2[i] = ccdsum[1][i]/avg[1];
+ }
+
+ printf("Target and actual CCD weight sums:\n");
+ do_plot(xx, y1, y2, NULL, 128);
+ }
#endif
- break;
- case i1p_trans_spot:
- case i1p_trans_scan:
- if (s->cal_valid) {
- /* (Using cal_factor[] as temp. for i1pro_absraw_to_abswav()) */
- i1pro_absraw_to_abswav(p, 0, s->reflective, 1, &s->cal_factor[0], &s->white_data);
- i1pro_absraw_to_abswav(p, 1, s->reflective, 1, &s->cal_factor[1], &s->white_data);
- i1pro_compute_white_cal(p, s->cal_factor[0], NULL, s->cal_factor[0],
- s->cal_factor[1], NULL, s->cal_factor[1]);
+
+#ifdef DO_CCDNORMAVG /* Just correct by average */
+ for (cx = j = 0; j < m->nwav[1]; j++) { /* For each wavelength */
+
+ /* For each matrix value */
+ sx = m->mtx_c[1][refl].index[j]; /* Starting index */
+ for (k = 0; k < m->mtx_c[1][refl].nocoef[j]; k++, cx++, sx++) {
+ m->mtx_c[1][refl].coef[cx] *= 10.0/twidth * avg[0]/avg[1];
+ }
+ }
+
+#else /* Correct by CCD bin */
+
+ /* Correct the weighting of each CCD value in the hires output */
+ for (i = 0; i < 128; i++) {
+ ccdsum[1][i] = 10.0/twidth * ccdsum[0][i]/ccdsum[1][i]; /* Correction factor */
+ }
+ for (cx = j = 0; j < m->nwav[1]; j++) { /* For each wavelength */
+
+ /* For each matrix value */
+ sx = m->mtx_c[1][refl].index[j]; /* Starting index */
+ for (k = 0; k < m->mtx_c[1][refl].nocoef[j]; k++, cx++, sx++) {
+ m->mtx_c[1][refl].coef[cx] *= ccdsum[1][sx];
+ }
+ }
+#endif
+ }
+#endif /* DO_CCDNORM */
+
+#ifdef HIGH_RES_PLOT
+ {
+ static i1pro_fc coeff2[MXNOWL][MXNOFC];
+ double *xx, *ss;
+ double **yy;
+
+ /* Convert the native filter cooeficient representation to */
+ /* a 2D array we can randomly index. */
+ for (cx = j = 0; j < m->nwav[1]; j++) { /* For each output wavelength */
+ if (j >= MXNOWL) { /* Assert */
+ a1loge(p->log,1,"i1pro: number of hires output wavelenths is > %d\n",MXNOWL);
+ return I1PRO_INT_ASSERT;
+ }
+
+ /* For each matrix value */
+ sx = m->mtx[1][refl].index[j]; /* Starting index */
+ for (k = 0; k < m->mtx[1][refl].nocoef[j]; k++, cx++, sx++) {
+ if (k >= MXNOFC) { /* Assert */
+ a1loge(p->log,1,"i1pro: number of hires filter coeefs is > %d\n",MXNOFC);
+ return I1PRO_INT_ASSERT;
}
- break;
+ coeff2[j][k].ix = sx;
+ coeff2[j][k].we = m->mtx[1][refl].coef[cx];
+// printf("Output %d, filter %d weight = %e\n",j,k,coeff2[j][k].we);
+ }
+ }
+
+ xx = dvectorz(-1, m->nraw-1); /* X index */
+ yy = dmatrixz(0, 5, -1, m->nraw-1); /* Curves distributed amongst 5 graphs */
+
+ for (i = 0; i < m->nraw; i++)
+ xx[i] = i;
+
+ /* For each output wavelength */
+ for (j = 0; j < m->nwav[1]; j++) {
+ i = j % 5;
+
+ /* For each matrix value */
+ for (k = 0; k < m->mtx_c[1][refl].nocoef[j]; k++) {
+ yy[5][coeff2[j][k].ix] += 0.5 * coeff2[j][k].we;
+ yy[i][coeff2[j][k].ix] = coeff2[j][k].we;
+ }
}
+
+ printf("Normalized Hi-Res wavelength sampling curves: %s\n",refl ? "refl" : "emis");
+ do_plot6(xx, yy[0], yy[1], yy[2], yy[3], yy[4], yy[5], m->nraw);
+ free_dvector(xx, -1, m->nraw-1);
+ free_dmatrix(yy, 0, 2, -1, m->nraw-1);
}
- }
+#endif /* HIGH_RES_PLOT */
+#undef MXNOWL
+#undef MXNOFC
+ } /* Do next filter */
/* Hires has been initialised */
m->hr_inited = 1;
+ /* Generate high res. per mode calibration factors. */
+ if ((ev = i1pro_create_hr_calfactors(p, 0)) != I1PRO_OK)
+ return ev;
+
return ev;
}
@@ -9373,6 +9890,7 @@ i1pro_code i1pro_conv2XYZ(
if (!m->spec_en) {
vals[i].sp.spec_n = 0;
}
+
}
conv->del(conv);
@@ -9447,20 +9965,280 @@ i1pro_code i1pro_check_white_reference1(
}
/* Compute a mode calibration factor given the reading of the white reference. */
-/* Return 1 if any of the transmission wavelengths are low. */
-int i1pro_compute_white_cal(
+/* We will also calibrate & smooth hi-res emis_coef[1] if they are present. */
+/* Return I1PRO_RD_TRANSWHITEWARN if any of the transmission wavelengths are low. */
+/* May return some other error (malloc) */
+i1pro_code i1pro_compute_white_cal(
i1pro *p,
double *cal_factor0, /* [nwav[0]] Calibration factor to compute */
double *white_ref0, /* [nwav[0]] White reference to aim for, NULL for 1.0 */
double *white_read0, /* [nwav[0]] The white that was read */
double *cal_factor1, /* [nwav[1]] Calibration factor to compute */
double *white_ref1, /* [nwav[1]] White reference to aim for, NULL for 1.0 */
- double *white_read1 /* [nwav[1]] The white that was read */
+ double *white_read1, /* [nwav[1]] The white that was read */
+ int do_emis_ft /* Do emission hires fine tune with this info. */
) {
i1proimp *m = (i1proimp *)p->m;
i1pro_state *s = &m->ms[m->mmode];
- int j, warn = 0;;
+ int j, warn = I1PRO_OK;;
+
+#ifdef HIGH_RES
+ /* If we need to, fine calibrate the emission */
+ /* calibration coefficients, using the reflectance cal. */
+ /* illuminant as an (assumed) smooth light source reference. */
+ /* (Do this first, befor white_read0/cal_factor0 is overwritten by white cal.) */
+ if (do_emis_ft && m->hr_inited != 0 && white_ref1 != NULL) {
+ i1pro_code ev = I1PRO_OK;
+ int i;
+ double *lincal;
+ double *fudge;
+ xspect illA;
+#ifdef HIGH_RES_PLOT
+ double *targ_smth; /* Hires target in smooth space */
+ double *old_emis;
+ double avgl;
+
+ if ((targ_smth = (double *)calloc(m->nwav[1], sizeof(double))) == NULL) {
+ return I1PRO_INT_MALLOC;
+ }
+ if ((old_emis = (double *)calloc(m->nwav[1], sizeof(double))) == NULL) {
+ return I1PRO_INT_MALLOC;
+ }
+ for (i = 0; i < m->nwav[1]; i++)
+ old_emis[i] = m->emis_coef[1][i];
+#endif
+
+ if ((lincal = (double *)calloc(m->nwav[0], sizeof(double))) == NULL) {
+ return I1PRO_INT_MALLOC;
+ }
+ if ((fudge = (double *)calloc(m->nwav[0], sizeof(double))) == NULL) {
+ return I1PRO_INT_MALLOC;
+ }
+
+ /* Fill in an xpsect with a standard illuminant spectrum */
+ if (standardIlluminant(&illA, icxIT_Ptemp, 2990.0)) {
+ a1loge(p->log,1,"i1pro_compute_white_cal: standardIlluminant() failed");
+ return I1PRO_INT_ASSERT;
+ }
+
+ for (j = 0; j < m->nwav[0]; j++) {
+ double wl = XSPECT_WL(m->wl_short[0], m->wl_long[0], m->nwav[0], j);
+
+ lincal[j] = white_read0[j] * m->emis_coef[0][j]
+ / (white_ref0[j] * value_xspect(&illA, wl));
+ }
+
+#ifndef NEVER
+ /* Generate the hires emis_coef by interpolating lincal */
+ /* using rspl, and reversing computation through hi-res readings */
+ {
+ rspl *trspl; /* Upsample rspl */
+ cow sd[40]; /* Scattered data points of existing references */
+ datai glow, ghigh;
+ datao vlow, vhigh;
+ int gres[1];
+ double avgdev[1];
+ int ix;
+ co pp;
+
+ if ((trspl = new_rspl(RSPL_NOFLAGS, 1, 1)) == NULL) {
+ a1logd(p->log,1,"i1pro: creating rspl for high res conversion failed\n");
+ return I1PRO_INT_NEW_RSPL_FAILED;
+ }
+
+ vlow[0] = 1e6;
+ vhigh[0] = -1e6;
+ for (ix = i = 0; i < m->nwav[0]; i++) {
+
+ sd[ix].p[0] = XSPECT_WL(m->wl_short[0], m->wl_long[0], m->nwav[0], i);
+ sd[ix].v[0] = lincal[i];
+ sd[ix].w = 1.0;
+
+ if (sd[ix].v[0] < vlow[0])
+ vlow[0] = sd[ix].v[0];
+ if (sd[ix].v[0] > vhigh[0])
+ vhigh[0] = sd[ix].v[0];
+ ix++;
+ }
+
+ glow[0] = m->wl_short[1];
+ ghigh[0] = m->wl_long[1];
+ gres[0] = 6 * m->nwav[1];
+ avgdev[0] = 0.0;
+
+ /* The smoothness factor of 0.02 seems critical in tuning the RevE */
+ /* hires accuracy, as measured on an LCD display */
+ trspl->fit_rspl_w(trspl, 0, sd, ix, glow, ghigh, gres, vlow, vhigh, 0.05, avgdev, NULL);
+
+ /* Create a linear interp fudge factor to place interp at low */
+ /* res. exactly on lowres linear curve. This compensates */
+ /* if the rspl moves the target at the lowres points */
+ for (j = 0; j < m->nwav[0]; j++) {
+ double wl = XSPECT_WL(m->wl_short[0], m->wl_long[0], m->nwav[0], j);
+ pp.p[0] = wl;
+ trspl->interp(trspl, &pp);
+
+ fudge[j] = lincal[j] / pp.v[0];
+ }
+
+ /* Compute hires emis_coef */
+ for (i = 0; i < m->nwav[1]; i++) {
+ double wl = XSPECT_WL(m->wl_short[1], m->wl_long[1], m->nwav[1], i);
+ double ff;
+
+ pp.p[0] = wl;
+ trspl->interp(trspl, &pp);
+
+#ifdef HIGH_RES_PLOT
+ targ_smth[i] = pp.v[0];
+#endif
+ /* Invert lincal at high res */
+ ff = wav_lerp(m, 0, fudge, wl);
+ m->emis_coef[1][i] = (ff * pp.v[0] * white_ref1[i] * value_xspect(&illA, wl))
+ /white_read1[i];
+ }
+ trspl->del(trspl);
+ }
+
+#else
+ /* Generate the hires emis_coef by interpolating lincal */
+ /* using lagrange, and reversing computation through hi-res readings */
+ for (i = 0; i < m->nwav[1]; i++) {
+ int k;
+ double x[4], xw;
+ double y[4], yw;
+
+ xw = XSPECT_WL(m->wl_short[1], m->wl_long[1], m->nwav[1], i);
+
+ /* Locate lowres index below it */
+ j = (int)floor(XSPECT_DIX(m->wl_short[0], m->wl_long[0], m->nwav[0], xw)) -1;
+ if (j < 0)
+ j = 0;
+ if (j > (m->nwav[0]-4))
+ j = (m->nwav[0]-4);
+
+ /* Setup the surrounding point values */
+ for (k = 0; k < 4; k++) {
+ x[k] = XSPECT_WL(m->wl_short[0], m->wl_long[0], m->nwav[0], j+k);
+ y[k] = lincal[j+k];
+ }
+
+ /* Compute interpolated value using Lagrange: */
+ yw = y[0] * (xw-x[1]) * (xw-x[2]) * (xw-x[3])
+ /((x[0]-x[1]) * (x[0]-x[2]) * (x[0]-x[3]))
+ + y[1] * (xw-x[0]) * (xw-x[2]) * (xw-x[3])
+ /((x[1]-x[0]) * (x[1]-x[2]) * (x[1]-x[3]))
+ + y[2] * (xw-x[0]) * (xw-x[1]) * (xw-x[3])
+ /((x[2]-x[0]) * (x[2]-x[1]) * (x[2]-x[3]))
+ + y[3] * (xw-x[0]) * (xw-x[1]) * (xw-x[2])
+ /((x[3]-x[0]) * (x[3]-x[1]) * (x[3]-x[2]));
+
+ targ_smth[i] = yw;
+
+ /* Invert lincal at high res */
+ m->emis_coef[1][i] = (yw * white_ref1[i] * value_xspect(&illA, xw))/white_read1[i];
+ }
+#endif /* NEVER */
+
+#ifdef HIGH_RES_PLOT
+ /* Plot linear target curve and measured curve */
+ {
+ double *xx, *y1, *y2, *y3, *y4;
+
+ xx = dvector(0, m->nwav[1]); /* X wl */
+ y1 = dvector(0, m->nwav[1]);
+ y2 = dvector(0, m->nwav[1]);
+ y3 = dvector(0, m->nwav[1]);
+ y4 = dvector(0, m->nwav[1]);
+
+ for (j = 0; j < (m->nwav[1]); j++) {
+ xx[j] = XSPECT_WL(m->wl_short[1], m->wl_long[1], m->nwav[1], j);
+ y1[j] = wav_lerp_cv(m, 0, lincal, xx[j], 0.0);
+ y2[j] = targ_smth[j];
+ y3[j] = white_read1[j] * wav_lerp(m, 0, m->emis_coef[0], xx[j])
+ /(white_ref1[j] * value_xspect(&illA, xx[j]));
+ y4[j] = white_read1[j] * old_emis[j]
+ /(white_ref1[j] * value_xspect(&illA, xx[j]));
+ }
+
+ printf("stdres interp targ (bk), smoothed targ (rd), measured hires resp. (gn), previous cal resp.(bu):\n");
+ do_plot6(xx, y1, y2, y3, y4, NULL, NULL, m->nwav[1]);
+ free_dvector(xx, 0, m->nwav[1]);
+ free_dvector(y1, 0, m->nwav[1]);
+ free_dvector(y2, 0, m->nwav[1]);
+ free_dvector(y4, 0, m->nwav[1]);
+ }
+ /* Plot target and achieved smooth space responses */
+ {
+ double *xx, *y2;
+
+ xx = dvector(0, m->nwav[1]);
+ y2 = dvector(0, m->nwav[1]);
+
+ for (j = 0; j < (m->nwav[1]); j++) {
+ xx[j] = XSPECT_WL(m->wl_short[1], m->wl_long[1], m->nwav[1], j);
+ y2[j] = white_read1[j] * m->emis_coef[1][j]
+ /(white_ref1[j] * value_xspect(&illA, xx[j]));
+ }
+
+ printf("target smooth curve, achived smooth curve:\n");
+ do_plot6(xx, targ_smth, y2, NULL, NULL, NULL, NULL, m->nwav[1]);
+
+ free_dvector(xx, 0, m->nwav[1]);
+ free_dvector(y2, 0, m->nwav[1]);
+ }
+ /* Plot lowres and hires lamp response */
+ {
+ double *xx, *y1, *y2;
+
+ xx = dvector(0, m->nwav[1]);
+ y1 = dvector(0, m->nwav[1]);
+ y2 = dvector(0, m->nwav[1]);
+
+ for (j = 0; j < (m->nwav[1]); j++) {
+ xx[j] = XSPECT_WL(m->wl_short[1], m->wl_long[1], m->nwav[1], j);
+ y1[j] = wav_lerp(m, 0, white_read0, xx[j]) * wav_lerp(m, 0, m->emis_coef[0], xx[j])
+ /wav_lerp(m, 0, white_ref0, xx[j]);
+ y2[j] = white_read1[j] * m->emis_coef[1][j]
+ /white_ref1[j];
+ }
+
+ printf("lowres, high res lamp response:\n");
+ do_plot6(xx, y1, y2, NULL, NULL, NULL, NULL, m->nwav[1]);
+
+ free_dvector(xx, 0, m->nwav[1]);
+ free_dvector(y1, 0, m->nwav[1]);
+ free_dvector(y2, 0, m->nwav[1]);
+ }
+ /* Plot hires emis calibration */
+ {
+ double *xx;
+
+ xx = dvector(0, m->nwav[1]); /* X wl */
+
+ for (j = 0; j < (m->nwav[1]); j++) {
+ xx[j] = XSPECT_WL(m->wl_short[1], m->wl_long[1], m->nwav[1], j);
+ }
+
+ printf("orig upsampled + smoothed hires emis_coef:\n");
+ do_plot6(xx, old_emis, m->emis_coef[1], NULL, NULL, NULL, NULL, m->nwav[1]);
+ free_dvector(xx, 0, m->nwav[1]);
+ }
+ free(old_emis);
+ free(targ_smth);
+#endif /* HIGH_RES_PLOT */
+ free(fudge);
+ free(lincal);
+
+ m->emis_hr_cal = 1; /* We don't have to do a reflective calibration */
+
+ /* Make sure these are updated */
+ if ((ev = i1pro_create_hr_calfactors(p, 1)) != I1PRO_OK)
+ return ev;
+ }
+#endif /* HIGH_RES */
+
if (white_ref0 == NULL) { /* transmission white reference */
double avgwh = 0.0;
@@ -9474,7 +10252,7 @@ int i1pro_compute_white_cal(
/* If reference is < 0.4% of average */
if (white_read0[j]/avgwh < 0.004) {
cal_factor0[j] = 1.0/(0.004 * avgwh);
- warn = 1;
+ warn = I1PRO_RD_TRANSWHITEWARN;
} else {
cal_factor0[j] = 1.0/white_read0[j];
}
@@ -9508,7 +10286,7 @@ int i1pro_compute_white_cal(
/* If reference is < 0.4% of average */
if (white_read1[j]/avgwh < 0.004) {
cal_factor1[j] = 1.0/(0.004 * avgwh);
- warn = 1;
+ warn = I1PRO_RD_TRANSWHITEWARN;
} else {
cal_factor1[j] = 1.0/white_read1[j];
}
@@ -9523,8 +10301,8 @@ int i1pro_compute_white_cal(
else
cal_factor1[j] = white_ref1[j]/white_read1[j];
}
- }
#endif /* HIGH_RES */
+ }
return warn;
}
@@ -10136,8 +10914,12 @@ i1pro_delayed_trigger(void *pp) {
a1logd(p->log,2,"i1pro_delayed_trigger: start sleep @ %d msec\n", msec_time() - m->msec);
+#ifdef USE_RD_SYNC
+ p->icom->usb_wait_io(p->icom, &m->rd_sync); /* Wait for read to start */
+#else
/* Delay the trigger */
msec_sleep(m->trig_delay);
+#endif
m->tr_t1 = msec_time(); /* Diagnostic */
@@ -10197,7 +10979,7 @@ i1pro_triggermeasure(i1pro *p, int delay) {
/* A buffer full of bytes is returned. */
/* (This will fail on a Rev. A if there is more than about a 40 msec delay */
/* between triggering the measurement and starting this read. */
-/* It appears though that the read can be pending before triggering though. */
+/* It appears that the read can be pending before triggering though. */
/* Scan reads will also terminate if there is too great a delay beteween each read.) */
i1pro_code
i1pro_readmeasurement(
@@ -10268,7 +11050,7 @@ i1pro_readmeasurement(
m->tr_t6 = msec_time(); /* Diagnostic, start of subsequent reads */
if (m->tr_t3 == 0) m->tr_t3 = m->tr_t6; /* Diagnostic, start of first read */
- se = p->icom->usb_read(p->icom, NULL, 0x82, buf, size, &rwbytes, top);
+ se = p->icom->usb_read(p->icom, &m->rd_sync, 0x82, buf, size, &rwbytes, top);
m->tr_t5 = m->tr_t7;
m->tr_t7 = msec_time(); /* Diagnostic, end of subsequent reads */
@@ -10538,7 +11320,7 @@ i1pro_code i1pro_waitfor_switch_th(i1pro *p, double top) {
(stime = msec_time()) - m->msec);
/* Now read 1 byte */
- se = p->icom->usb_read(p->icom, &m->cancelt, 0x84, buf, 1, &rwbytes, top);
+ se = p->icom->usb_read(p->icom, &m->sw_cancel, 0x84, buf, 1, &rwbytes, top);
if (se & ICOM_TO) {
a1logd(p->log,2,"i1pro_waitfor_switch_th: read 0x%x bytes, timed out (%d msec)\n",
@@ -10596,7 +11378,7 @@ i1pro_terminate_switch(
msec_sleep(50);
if (m->th_termed == 0) {
a1logd(p->log,3,"i1pro terminate switch thread failed, canceling I/O\n");
- p->icom->usb_cancel_io(p->icom, &m->cancelt);
+ p->icom->usb_cancel_io(p->icom, &m->sw_cancel);
}
return rv;
@@ -10731,9 +11513,12 @@ i1pro2_delayed_trigger(void *pp) {
a1logd(p->log,2,"i1pro2_delayed_trigger: Rev E start sleep @ %d msec\n",
msec_time() - m->msec);
-
+#ifdef USE_RD_SYNC
+ p->icom->usb_wait_io(p->icom, &m->rd_sync); /* Wait for read to start */
+#else
/* Delay the trigger */
msec_sleep(m->trig_delay);
+#endif
m->tr_t1 = msec_time(); /* Diagnostic */