/********************************************************************\ Name: tdccalib.c Created by: Stefan Ritt Contents: PiBeta Analyzer module for TDC calibration $Log: tdccalib.c,v $ Revision 1999/12/20 WL Added codes for refined tdc offsets determination Revision 1.26 1999/08/20 14:23:12 midas Added errors to gauss_fit() Revision 1.25 1999/08/20 13:38:13 midas Put histo clearing in BOR routines instead EOR Revision 1.24 1999/08/19 15:27:34 midas Clear histos independent of global histo clear flag Revision 1.23 1999/08/19 15:17:58 midas Added "guess initial param" flag to gauss_fit Revision 1.22 1999/08/18 08:03:39 midas Don't clear raw ADC histos after each run Revision 1.21 1999/08/16 10:48:41 midas Introduced 2D histos by CLS Revision 1.20 1999/08/02 09:12:01 midas Switched over to common stop mode for all TDCs Revision 1.19 1999/07/14 08:09:24 midas Re-arranged histo ID's Revision 1.18 1999/07/08 10:35:13 midas Fixed compiler warning Revision 1.17 1999/07/08 06:55:08 midas Fixed bug that PV's didn't get linearized Revision 1.16 1999/07/06 09:44:50 midas Filling of corrected TDC histos Revision 1.15 1999/06/11 11:32:32 midas Added code for common stop TDC decoding Revision 1.14 1999/05/03 09:44:47 midas Fixed bug in valid bit Revision 1.13 1999/05/03 09:33:11 midas Added TVAL bank with "TDC valid bits" Revision 1.12 1999/02/16 10:32:06 midas Defined INVALID as -1000 Revision 1.11 1999/01/22 10:36:25 midas Added TDC width histos (2500+) Revision 1.10 1999/01/20 13:02:31 midas Fixed compiler warnings Revision 1.9 1998/12/09 06:18:41 midas Removed n_hit histos (2500+) Revision 1.8 1998/12/09 06:16:29 midas Removed marking of TDC histos if TDC calibration is off Revision 1.7 1998/12/03 12:30:56 midas Fixed but which crashed TDC calibration for small ADC values Revision 1.6 1998/12/03 11:22:49 midas Added Log in header \********************************************************************/ /*-- Include files -------------------------------------------------*/ /* standard includes */ #include #include #include "util.h" #include /* WL */ /* midas includes */ #include "midas.h" #include "hardware.h" #include "experim.h" #include "analyzer.h" /* cernlib includes */ #ifdef OS_WINNT #define VISUAL_CPLUSPLUS #endif #ifdef OS_LINUX #define f2cFortran #endif #include #include /*-- Parameters ----------------------------------------------------*/ extern GLOBAL_PARAM global_param; extern ADC_CALIBRATION_PARAM adccalib_param; TDC_CALIBRATION_PARAM tdccalib_param; extern char *analyzer_name; #define TDC_WINDOW 200 /* first 200 ns */ /* WL */ typedef struct { INT channel; float time; }TIM_HISTO; #define N_DATA 350 /*-- Hardware parameters -------------------------------------------*/ #define FS_TDC 10 /* leftmost module */ #define FS_TDC_CLUSTER 6 /* cluster TDC with common stop */ typedef struct { int slot; int n_channels; } CHANNEL_MAP; CHANNEL_MAP tdc_map[] = { { FS_TDC-0, 96 }, /* 480 channels CsI+Target+PV+Cosmic+Cluster */ { FS_TDC-1, 96 }, { FS_TDC-2, 96 }, { FS_TDC-3, 96 }, { FS_TDC-4, 96 }, { FS_TDC-5, 16 }, /* 16 channels trigger input bits */ { 0 } }; /*-- Module declaration --------------------------------------------*/ INT tdc_calib(EVENT_HEADER*,void*); INT tdc_calib_init(void); INT tdc_calib_bor(INT run_number); INT tdc_calib_eor(INT run_number); TDC_CALIBRATION_PARAM_STR(tdc_calibration_param_str); ANA_MODULE tdc_calib_module = { "TDC calibration", /* module name */ "Stefan Ritt", /* author */ tdc_calib, /* event routine */ tdc_calib_bor, /* BOR routine */ tdc_calib_eor, /* EOR routine */ tdc_calib_init, /* init routine */ NULL, /* exit routine */ &tdccalib_param, /* parameter structure */ sizeof(tdccalib_param), /* structure size */ tdc_calibration_param_str, /* initial parameters */ }; /*-- init routine --------------------------------------------------*/ #define TDC_N_BINS 512 #define TDC_X_LOW -512 #define TDC_X_HIGH 0 #define TDC_CORR_N_BINS 81 #define TDC_CORR_X_LOW -20 #define TDC_CORR_X_HIGH 20 INT tdc_calib_init(void) { /* tdc hit histos */ HBOOK2(TDCCALIB_ID_BASE, "TDC", TDC_N_BINS, (float)TDC_X_LOW, (float)TDC_X_HIGH, N_TDC, (float)0, (float)N_TDC, 0.f); HBOOK2(TDC_COR_ID_BASE, "TDC corr", TDC_CORR_N_BINS, (float)TDC_CORR_X_LOW, (float)TDC_CORR_X_HIGH, N_TDC, (float)0, (float)N_TDC, 0.f); return SUCCESS; } /*-- bor routine ---------------------------------------------------*/ INT tdc_calib_bor(INT run_number) { /* clear TDC histos */ HRESET(TDCCALIB_ID_BASE, " "); HRESET(TDC_COR_ID_BASE, " "); return SUCCESS; } /*-- eor routine ---------------------------------------------------*/ static float yfloat[N_TDC][TDC_N_BINS]; INT tdc_calib_eor(INT run_number) { int i, i_channel; double x[TDC_N_BINS], y[TDC_N_BINS]; double param[3], error[3], chisqr, ymax; char str[80]; HNDLE hDB, hkey; cm_get_experiment_database(&hDB, NULL); if (tdccalib_param.correct_offsets == 1) { HUNPAK(TDCCALIB_ID_BASE, yfloat[0][0], "HIST", 1); /*---- analyze TDC histos ------- --------------------------------*/ for (i=0 ; i ymax && i>0) ymax = y[i]; } if (ymax > 10) { chisqr = gauss_fit(x, y, TDC_N_BINS, param, error, TRUE); if (chisqr != -1) { tdccalib_param.offset[i_channel] = (float) param[1]; tdccalib_param.sigma[i_channel] = (float) fabs(param[2]/2.35482); } } } /* write new offsets to online database. */ sprintf(str,"/%s/Parameters/TDC calibration", analyzer_name); db_find_key(hDB, 0, str, &hkey); db_set_record(hDB, hkey, &tdccalib_param, sizeof(tdccalib_param), 0); cm_msg(MTALK, "tdc_calib_eor", "New TDC offsets have been written to ODB"); } return SUCCESS; } /*-- event routine -------------------------------------------------*/ /* define Three global variables to transmit raw tdc and channel to histo.c WWL*/ INT n_data_histo; /* WL */ TIM_HISTO tim_histo[N_DATA]; /* WL */ float time_deg_normal = INVALID; /* WL */ INT tdc_calib(EVENT_HEADER *pheader, void *pevent) { INT i, j, k, channel, n_data, count; LRS1877_DATA *lrs1877; LRS1877_HEADER *lrs1877_header; float tdc_time[N_TDC], tdc_width[N_TDC]; float tdc_pre[N_TDC], tdc_post[N_TDC]; INT tdc_n_hit[N_TDC], tdc_valid[N_TDC]; float *pf, time, width, tdc_corr, *cadc, adc, cdata1, cdata2; WORD *trig, *pw; BOOL valid; n_data_histo = 0; /* WL */ /* look for LTDC bank, return if not present */ n_data = bk_locate(pevent, "LTDC", &lrs1877); if (n_data == 0) return 1; if (bk_locate(pevent, "TRIG", &trig) == 0 || bk_locate(pevent, "CADC", &cadc) == 0) return 0; /*---- TDC decoding ----------------------------------------------*/ /* zero arrays */ memset(tdc_n_hit, 0, sizeof(tdc_n_hit)); memset(tdc_width, 0, sizeof(tdc_width)); for (i=0 ; i 0 && lrs1877[i+j].geo_addr != tdc_map[k].slot ; k++) channel += tdc_map[k].n_channels; channel += lrs1877[i+j].channel; if (channel > N_TDC) continue; valid = TRUE; /* if channel data is sent twice, skip this one */ if (lrs1877[i+j].edge == lrs1877[i+j-1].edge && lrs1877[i+j].data == lrs1877[i+j-1].data && lrs1877[i+j].channel == lrs1877[i+j-1].channel && lrs1877[i+j].geo_addr == lrs1877[i+j-1].geo_addr) { continue; } /* if present data same as next, forward to next */ while (lrs1877[i+j].edge == lrs1877[i+j+1].edge && lrs1877[i+j].data == lrs1877[i+j+1].data && lrs1877[i+j].channel == lrs1877[i+j+1].channel && lrs1877[i+j].geo_addr == lrs1877[i+j+1].geo_addr) { j++; } /* extract data, correct sign for common stop TDCs */ cdata1 = lrs1877[i+j].data * 0.5f; cdata2 = lrs1877[i+j+1].data * 0.5f; if (lrs1877[i+j].geo_addr == FS_TDC_CLUSTER || N_TDC > 480) { cdata1 = -cdata1; cdata2 = -cdata2; } /* look for trailing edge which have a corresponding leading edge */ if (lrs1877[i+j].edge == 1 && lrs1877[i+j+1].edge == 0 && lrs1877[i+j].channel == lrs1877[i+j+1].channel && lrs1877[i+j].geo_addr == lrs1877[i+j+1].geo_addr && cdata1 > cdata2) { time = cdata2; width = cdata1 - cdata2; j++; } /* if only leading edge is found, trailing edge must be after TDC stop */ else if (lrs1877[i+j].edge == 0) { time = cdata1; width = 0; valid = FALSE; } /* else if (lrs1877[i+j].edge == 0 && lrs1877[i+j].data * 0.5 > 256) { * if only leading edge is found, trailing edge must lie outside TDC window * time = (float) (lrs1877[i+j].data * 0.5); width = 256.f; valid = FALSE; } else if (lrs1877[i+j].edge == 0 && lrs1877[i+j].data * 0.5 > 512) { * if leading edge comes after timeout, discard it * continue; } * look for "hidden" leading edge after trailing edge * else if (lrs1877[i+j].edge == 1 && lrs1877[i+j+1].edge == 1 && lrs1877[i+j].channel == lrs1877[i+j+1].channel && lrs1877[i+j].geo_addr == lrs1877[i+j+1].geo_addr) { * guess leading edge 1ns after previous trailing edge * time = (float) (lrs1877[i+j+1].data * 0.5 + 1); width = (float) (lrs1877[i+j].data * 0.5) - time; valid = FALSE; } */ else { /* found "lonely" edge, discard it */ /* printf("Serial %d\n", pheader->serial_number); */ continue; } /* these two variables are for histo.c WL */ tim_histo[n_data_histo].time = time; tim_histo[n_data_histo].channel = channel; /* fill histos with raw TDC value and width */ HF2(TDCCALIB_ID_BASE, time, (float)channel, 1.f); /* normalize to self timing peak */ time -= tdccalib_param.offset[channel]; if(channel == 402) /* record DEG timing WL*/ time_deg_normal = time; /* do ADC/TDC linearization for CsI, PV, CV, and target */ if (channel < N_CSI+N_PVETO+N_CVETO+14 && cadc[channel] > 0 && tdccalib_param.par3[channel] > 0) { adc = cadc[channel]; if (channel < N_CSI) adc /= adccalib_param.mev_per_channel_csi; else if (channel < CHN_PVETO + N_PVETO) adc /= adccalib_param.mev_per_channel_pv; if (adc > tdccalib_param.par4[channel]) { tdc_corr = tdccalib_param.par1[channel]+ (tdccalib_param.par3[channel] * (float) pow( adc-tdccalib_param.par4[channel], tdccalib_param.par2[channel])); time -= tdc_corr; } } tim_histo[n_data_histo].time = time; /* WL */ /* fill corrected TDC histos */ HF2(TDC_COR_ID_BASE,time , (float)channel, 1.f); n_data_histo++; /* WL */ /* look if close to self timing peak */ if (fabs(time) < fabs(tdc_time[channel])) { if (tdc_time[channel] > time) tdc_post[channel] = tdc_time[channel]; tdc_time[channel] = time; tdc_width[channel] = width; } else { /* look for first leading edge before STP */ if (time < 0 && time > tdc_pre[channel]) tdc_pre[channel] = time; } /* set valid bit, if it is once false for this channel, keep it false */ if (tdc_valid[channel]) tdc_valid[channel] = valid; /* count hits inside window */ if (time < TDC_WINDOW) tdc_n_hit[channel]++; } i += count; } /*---- create banks ----------------------------------------------*/ bk_create(pevent, "TTIM", TID_FLOAT, &pf); for (i=0 ; i