//////////////////////////////////////////////////////////////// // // MFadc // // #include "MFadc.hxx" #include "MMcEvt.hxx" #include "TROOT.h" #include #include #include #include "TH1.h" #include "TObjArray.h" #include "MGFadcSignal.hxx" using namespace std; MFadc::MFadc(Int_t pix, Int_t shape, Float_t integral, Float_t fwhm, Int_t shapeout, Float_t integralout, Float_t fwhmout, Float_t trigger_delay, Float_t fadc_slices_per_ns, Int_t fadc_slices_written, Int_t gainswitchamp, Int_t shiftfromswitch2lowgain, Float_t hi2logainpeak) { // // Constructor overloaded II // // Input variables: // 1. integral(out) = integration of the single phe response for inner // (outer) pixels. // 2. fwhm(out) = width at half high of the single phe response for // inner (outer) pixels. // // trigger_delay: shift of signals towards later times in FADC, in order // to center the signals in a good range. It acts as a sort of delay of // the signals (before being sent to the FADC) with respect to the trigger. // // The procedure is the following: // 1. some parameters of the trigger are set to default. // this parameters of the trigger may be changed // 3. Then the all signals are set to zero numpix=pix; fwhm_resp = fwhm; integ_resp = integral; fwhm_resp_outer = fwhmout; integ_resp_outer = integralout; shape_resp = shape; shape_resp_outer = shapeout; fFadcSlicesPerNanosec = fadc_slices_per_ns; fFadcSlices = fadc_slices_written; fGainSwitchAmp = gainswitchamp; fShiftFromSwitch2LowGain = shiftfromswitch2lowgain; fHi2LoGainPeak = hi2logainpeak; fSlices_mFadc = (Int_t)(TOTAL_TRIGGER_TIME*fFadcSlicesPerNanosec); for (Int_t i = 0; i < CAMERA_PIXELS; i++) { sig[i] = new Float_t[fSlices_mFadc]; sig_LG[i] = new Float_t[fSlices_mFadc]; } noise = new Float_t[fSlices_mFadc*1001]; noise_outer = new Float_t[fSlices_mFadc*1001]; digital_noise = new Float_t[fSlices_mFadc*1001]; for (Int_t i = 0; i < CAMERA_PIXELS; i++) { output[i] = new Float_t[fFadcSlices]; output_lowgain[i] = new Float_t[fFadcSlices]; } cout<< "[MFadc] Setting up the MFadc with this values "<< endl ; cout<< "[MFadc] FADC sampling frequency: " << fFadcSlicesPerNanosec << " GHz" << endl ; cout<< "[MFadc] - Inner pixels : "<< endl ; switch(shape_resp){ case 0: cout<< "[MFadc] Pulse shape : Gaussian ("<0)? 0.5 : -0.5; sing_resp[i] = (Float_t) (p0*exp(-p1*(exp(-p1*zed_slices)+zed_slices))+ p3+p4*exp(-p1*(exp(-p1*zed_slices)+ p5*zed_slices))+p6*d); response_sum_inner += sing_resp[i]; // Now the low gain: zed_slices = x * FADC_SLICES_PER_NSEC - p2_LG; d = (zed_slices>0)? 0.5 : -0.5; sing_resp_lowgain[i] = (Float_t) (p0_LG*exp(-p1_LG*(exp(-p1_LG*zed_slices)+zed_slices))+ p3_LG+p4_LG*exp(-p1_LG*(exp(-p1_LG*zed_slices)+ p5_LG*zed_slices))+p6_LG*d); response_sum_inner_LG += sing_resp_lowgain[i]; } break; default: cout<<"[MFadc] MFadc::MFadc : Shape of FADC pulse for inner pixel unknown." <0)? 0.5 : -0.5; sing_resp_outer[i] = (Float_t) (p0*exp(-p1*(exp(-p1*zed_slices)+ zed_slices))+p3+ p4*exp(-p1*(exp(-p1*zed_slices)+ p5*zed_slices))+p6*d); response_sum_outer += sing_resp_outer[i]; // Now the low gain: zed_slices = x * FADC_SLICES_PER_NSEC - p2_LG; d = (zed_slices>0)? 0.5 : -0.5; sing_resp_outer_lowgain[i] = (Float_t) (p0_LG*exp(-p1_LG*(exp(-p1_LG*zed_slices)+zed_slices))+ p3_LG+p4_LG*exp(-p1_LG*(exp(-p1_LG*zed_slices)+ p5_LG*zed_slices))+p6_LG*d); response_sum_outer_LG += sing_resp_outer_lowgain[i]; } break; default: cout<<"[MFadc] MFadc::MFadc : Shape of FADC pulse for inner pixel unknown." < numpix ) { cout << " WARNING: MFadc::Fill() : iPix greater than Pixels in Camera = " << numpix << endl; exit(987); } if ( used[iPix] == FALSE ) { used [iPix] = TRUE; for (i=0; i < (Int_t) fSlices_mFadc; i++ ) { sig[iPix][i] = 0.; sig_LG[iPix][i] = 0.; } } // // then select the time slice to use (ichan) // if ( time < TOTAL_TRIGGER_TIME+fadc_time_offset ) { // // Convert time into units of the width of the analog // signal histogram, sing_resp: // ichan = (Int_t) ( time * fFadcSlicesPerNanosec * SUBBINS); // // putting the response slices in the right sig slices. // Be careful, because both slices have different widths. // // We want to put the single phe response given by sing_resp into the // array sig[][], but only one of each SUBBINS bins, since the binning // of sing_resp is finer than that of sig[][]. We want that the start of // sing_resp coincides with the time "time" with respect to the begining // of sig[][] // We take the pulse height in the middle of FADC slices, we start in the // first such point after the time "time" (=ichan in response bins). Each // FADC slice corresponds to SUBBINS response bins. Int_t first_i = Int_t(SUBBINS/2) - ichan%(Int_t)SUBBINS; first_i = first_i < 0 ? (Int_t)SUBBINS+first_i : first_i; // // // first_i is the first bin of sing_resp which matches the center of one // bin of sig[][] // for ( i = first_i ; i < (Int_t)fResponseSlicesFadc; i += (Int_t)SUBBINS) { ichanfadc = (Int_t) ((ichan+i)/SUBBINS) ; if ( ichanfadc < 0 ) continue; // // fSlices_mFadc is by default 48. sig[][] is not the final FADC output; that // will be later filled (from sig[][]) in MFadc::TriggeredFadc() // if ( (ichanfadc) < (Int_t) fSlices_mFadc ) { sig[iPix][ichanfadc] += (amplitude * sing_resp[i] ); sig_LG[iPix][ichanfadc] += (amplitude * sing_resp_lowgain[i] ); } } } else cout << " WARNING! Fadc::Fill " << time << " out of TriggerTimeRange " << TOTAL_TRIGGER_TIME+fadc_time_offset << endl ; } void MFadc::FillOuter( Int_t iPix, Float_t time, Float_t amplitude ) { // // fills the information about one single Phe in the Trigger class // for an outer pixel // // See explanations of the code in function Fill() above // Int_t i, ichan, ichanfadc ; if ( iPix > numpix ) { cout << " WARNING: MFadc::FillOuter() : iPix greater than CAMERA_PIXELS" << endl ; exit(987) ; } if ( used[iPix] == FALSE ) { used [iPix] = TRUE ; for (i=0; i < (Int_t) fSlices_mFadc; i++) { sig[iPix][i] = 0.; sig_LG[iPix][i] = 0.; } } if ( time < TOTAL_TRIGGER_TIME+fadc_time_offset ) { ichan = (Int_t) ( time * fFadcSlicesPerNanosec * SUBBINS); Int_t first_i = Int_t(SUBBINS/2) - ichan%(Int_t)SUBBINS; first_i = first_i < 0 ? (Int_t)SUBBINS+first_i : first_i; for ( i = first_i ; i < (Int_t)fResponseSlicesFadc; i += (Int_t)SUBBINS) { ichanfadc = (Int_t) ((ichan+i)/SUBBINS); if ( ichanfadc < 0 ) continue; if ( (ichanfadc) < (Int_t)fSlices_mFadc ) { sig[iPix][ichanfadc] += (amplitude * sing_resp_outer[i] ); sig_LG[iPix][ichanfadc] += (amplitude * sing_resp_outer_lowgain[i] ); } } } else { cout << " WARNING! Fadc::FillOuter " << time << " out of TriggerTimeRange " << TOTAL_TRIGGER_TIME+fadc_time_offset << endl ; } } void MFadc::AddSignal( Int_t iPix, Float_t *resp) { // // Adds signals to the fadc reponse from a given array // Parameters are the number of the pixel and the values to be added // With add the signal equally to the high and low gain branch. The low // gain branch is not yet scaled down!! // Int_t i ; // // first we have to check if the pixel iPix is used or not until now // if this is the first use, reset all signal for that pixels // if ( iPix > numpix ) { cout << " WARNING: MFadc::Fill() : iPix greater than CAMERA_PIXELS" << endl ; exit(987) ; } if ( used[iPix] == FALSE ) { used [iPix] = TRUE ; for (i=0; i < (Int_t)fSlices_mFadc; i++ ) { sig[iPix][i] = 0. ; sig_LG[iPix][i] = 0. ; } } for ( i = 0 ; i<(Int_t)fSlices_mFadc; i++ ) { sig[iPix][i] += resp[i] ; sig_LG[iPix][i] += resp[i] ; } } void MFadc::SetPedestals( Int_t ped) { // It sets pedestal for each pixel flat randomly dstributed between 0 and ped // It uses the instance of TRandom GenElec. Int_t i; for(i=0;iRndm()); } } void MFadc::SetPedestals( Float_t *ped) { // It sets pedestal for each pixel from ped array Int_t i; for(i=0;iGaus(0., value1 ); noise_outer[i]=GenElec->Gaus(0., value2 ); } cout<<"MFadc::SetElecNoise ... done"<Integer(((Int_t)fSlices_mFadc)*1000); if ( used[i] == FALSE ) { used [i] = TRUE ; if (i < fInnerPixelsNum) { memcpy( (Float_t*)&sig[i][0], (Float_t*)&noise[startslice], ((Int_t) fSlices_mFadc)*sizeof(Float_t)); memcpy( (Float_t*)&sig_LG[i][0], (Float_t*)&noise[startslice], ((Int_t) fSlices_mFadc)*sizeof(Float_t)); } else { memcpy( (Float_t*)&sig[i][0], (Float_t*)&noise_outer[startslice], ((Int_t) fSlices_mFadc)*sizeof(Float_t)); memcpy( (Float_t*)&sig_LG[i][0], (Float_t*)&noise_outer[startslice], ((Int_t) fSlices_mFadc)*sizeof(Float_t)); } } // // If pixel already in use, the noise is added each time slice // else { if (i < fInnerPixelsNum) for ( Int_t is = 0 ; is < (Int_t)fSlices_mFadc ; is++ ) { sig[i][is] += noise[startslice+is]; sig_LG[i][is] += noise[startslice+is]; } else for ( Int_t is = 0 ; is < (Int_t)fSlices_mFadc ; is++ ) { sig[i][is] += noise_outer[startslice+is]; sig_LG[i][is] += noise_outer[startslice+is]; } } } } void MFadc::SetDigitalNoise(Float_t value){ UInt_t i; Float_t xrdm; cout<<"MFadc::SetDigitalNoise ... generating database for electronic noise." <Gaus(0., value); digital_noise[i]=(xrdm>0?Int_t(xrdm+0.5):Int_t(xrdm-0.5)); } cout<<"MFadc::SetDigitalNoise ... done"<Integer((Int_t) fSlices_mFadc*999); // // Then the noise is introduced for each time slice // for ( Int_t is = 0 ; is < fFadcSlices; is++ ) { output[i][is] += digital_noise[startslice+is]; output_lowgain[i][is] += digital_noise[startslice+fFadcSlices+is]; } } } void MFadc::Scan() { for ( Int_t ip=0; ip 0. ) { printf (" %4.1f/", sig[ip][is] ) ; } else { printf ("----/" ) ; } } printf ("\n"); } } } void MFadc::Scan(Float_t time) { // // first of all we subtract from the time a offset (8 ns) // Float_t t ; (0 > time - TIME_BEFORE_TRIGGER)? t=fadc_time_offset: t=(time-TIME_BEFORE_TRIGGER+fadc_time_offset) ; // to show also the start of the pulse before the trigger time if ( t < 0. ) { cout << " WARNING!! FROM MFADC::SCAN(t) " << endl ; exit (776) ; } // // calculate the first slice to write out // Int_t iFirstSlice ; iFirstSlice = (Int_t) ( t * fFadcSlicesPerNanosec ) ; for ( Int_t ip=0; ipInteger((Int_t) fSlices_mFadc*999); for ( Int_t is=0; is < n_slices ; is++ ) { if (ishigh) fvalue = sig[pix][is]; else // If we deal with low gain, we have to scale the values in sig_LG[][] by // the gain ratio (high2low_gain), since "sig_LG" contains at this point the // noise produced before the receiver boards (for instance NSB noise). // fvalue = pedestal[pix]+(sig_LG[pix][is]-pedestal[pix]) / high2low_gain; fvalue += digital_noise[startslice+is]; // We add the noise intrinsic to FADC fvalue = fvalue < 0? fvalue-0.5 : fvalue+0.5; value = fvalue < 0.? (UChar_t) 0 : (fvalue > 255.? 255 : (UChar_t) fvalue); // Add up slices: sum += value - pedestal[pix]; } return sum; } //======================================================================= void MFadc::TriggeredFadc(Float_t time) { // // Here the slices to write out are calculated. Warning: the digitalization // is NOT done here (it is already done in MFadc::Fill). This procedure only // selects which FADC slices to write out, out of those contained in the sig[][] // and sig_LG[][] arrays. // // // calculate the first slice to write out, according to trigger time: // Int_t iFirstSlice ; Int_t i; // // We had 0.5 for the correct rounding: // iFirstSlice = (Int_t) ( 0.5 + time * fFadcSlicesPerNanosec ) ; for ( Int_t ip = 0; ip < numpix; ip++ ) { if ( used[ip] == kFALSE) // Pixels with no C-photons, in the case that camera is being run with // no noise (nor NSB neither electronic). We then set the mean pedestal as // signal, since when analyzing the camera output file, MARS will subtract // it anyway! { for ( Int_t i=0 ; i < fFadcSlices ; i++ ) { output[ip][i] = pedestal[ip]; output_lowgain[ip][i] = pedestal[ip]; } continue; } // First put the high gain in the output slices: i = 0; Int_t switch_i = 0; for ( Int_t is = iFirstSlice; is < (iFirstSlice+fFadcSlices); is++ ) { if (is < (Int_t)fSlices_mFadc) { output[ip][i] = sig[ip][is]; if (switch_i == 0) // Hi gain limit not yet surpassed before. { if (output[ip][i] > fGainSwitchAmp) switch_i = i + fShiftFromSwitch2LowGain; } } else // We are beyond the simulated signal history in sig[][]! Put just mean pedestal! output[ip][i] = pedestal[ip]; i++; } // Now put the low gain: i=0; for ( Int_t is = iFirstSlice; is < (iFirstSlice+fFadcSlices); is++ ) { if (is < (Int_t)fSlices_mFadc) { if (switch_i > 0 && (i+fFadcSlices) >= switch_i) output_lowgain[ip][i] = pedestal[ip] + (sig_LG[ip][is]-pedestal[ip])/high2low_gain; // Once the shift occurs, low gain is filled with the high // gain signal scaled down by the factor high2low_gain else output_lowgain[ip][i] = sig[ip][is+fFadcSlices]; // Write out high gain into low gain slices if there was no // switch, or before the switch occurs. } else // We are beyond the simulated signal history in sig[][]! Put just mean pedestal! { output_lowgain[ip][i] = pedestal[ip]; } i++; } } } void MFadc::ShowSignal (MMcEvt *McEvt, Float_t trigTime) { // ============================================================ // // This method is used to book the histogram to show the signal in // a special gui frame (class MGTriggerSignal). After the look onto the // signals for a better understanding of the things we will expect // the gui frame and all histogramms will be destroyed. // // // first of all create a list of the histograms to show // // take only that one with a entry TH1F *hist ; Char_t dumm[10]; Char_t name[256]; TObjArray *AList ; AList = new TObjArray(10) ; // the list of analog signal histograms // at the beginning we initalise 10 elements // but this array expand automatically if neccessay Int_t ic = 0 ; for ( Int_t i=0 ; i < numpix; i++ ) { if ( used [i] == TRUE ) { sprintf (dumm, "FADC_%d", i ) ; sprintf (name, "fadc signal %d", i ) ; hist = new TH1F(dumm, name, (Int_t)fSlices_mFadc, fadc_time_offset, TOTAL_TRIGGER_TIME+fadc_time_offset); // // fill the histogram // for (Int_t ibin = 1; ibin <= (Int_t)fSlices_mFadc; ibin++) hist->SetBinContent (ibin, sig[i][ibin-1]); // hist->SetMaximum( 5.); // hist->SetMinimum(-10.); hist->SetStats(kFALSE); // hist->SetAxisRange(0., 80. ) ; AList->Add(hist) ; ic++ ; } } // // create the Gui Tool // // new MGFadcSignal(McEvt, AList, trigTime, gClient->GetRoot(), gClient->GetRoot(), 400, 400 ) ; // // delete the List of histogramms // AList->Delete() ; delete AList ; } UChar_t MFadc::GetFadcSignal(Int_t pixel, Int_t slice){ // It returns the analog signal for a given pixel and a given FADC // time slice which would be read. // Since May 1 2004, we do the rounding and the truncation to the range // 0-255 counts here. (A. Moralejo) Float_t out = output[pixel][slice] > 0. ? output[pixel][slice]+0.5 : output[pixel][slice]-0.5; // (add or subtract 0.5 for correct rounding) return (out < 0.? (UChar_t) 0 : (out > 255.? (UChar_t) 255 : (UChar_t) out)); } UChar_t MFadc::GetFadcLowGainSignal(Int_t pixel, Int_t slice){ // It returns the analog signal for a given pixel and a given FADC // time slice which would be read. Same comment as above. Float_t outlow = output_lowgain[pixel][slice] > 0. ? output_lowgain[pixel][slice]+0.5 : output_lowgain[pixel][slice]-0.5; // (add or subtract 0.5 for correct rounding) return (outlow < 0.? (UChar_t) 0 : (outlow > 255.? (UChar_t) 255 : (UChar_t) outlow)); }