#ifndef p_ADC #define p_ADC #include #include #include #include #include #include #include "pUtility.h" #include "pSignal.h" // Basic classes: // pSignal: samples storage and simple operations on samples, signal generation // (sinusoidal, preamp, PMT signals...) // pADC: A/D conversion simulation // pFT: contains a Fourier Tranform // pDSP: handles Fourier transforms, Z-Tranforms, Filters, various LTI system operations, convolution, recursive difference // equations.... #define DEBUG /*! \brief class modeling a sampling ADC with bipolar transfer function The model accepts the following parameters:
  • double Ts: sampling period in ns
  • double Fs: sampling frequency in GHz (always =1/Ts)
  • double range: peak-to-peak range, default is 2V, meaning input in +- 1V
  • int Nbits: physical resolution (number of quantization levels is 2^Nbits)
  • int fractional: set to 1 for fractional (i.e. abs(sample)<1) output
  • double sigma_in_noise: input referred (a.k.a. code transition) noise std. dev.
  • double ap_jitter: aperture jitter std. dev.
Fractional mode (fractional=1) means that the output will be in the (-1, 1) range, i.e. the output is produced normalized to Full Scale */ class pADC: public TObject{ public: // class constructors //! ADC constructor: //! e.g. to create a 14 bit, 100 MHz (0.1 GHz) ADC with 2V p-p range, do //! \code //! pADC adc(14, 0.1, 2) //! \endcode //! then you can set other ADC characteristics (input referred noise, aperture jitter,...) using //! setter functions //! e.g //! \code //! adc.SetInputNoise(1.5) //! adc.SetApertureJitter(0.01) //! \endcode pADC(int Nbits, double Fs, double range); virtual ~pADC(){} // signal generation //! samples ideally (i.e. no noise, no jitter, ideal ADC!) a continuous signal described by a function (function is ROOT class TF1) //! returns a pointer to a pSignal object which stores the samples pSignal *IdealSampleTF1(TF1 *f, int nsamples); //! samples realistically (i.e. with noise, jitter...real ADC!) a continuous signal described by a function (function is ROOT class TF1) //! noise and jitter must be set in advance, quantization is always performed //! returns a pointer to a pSignal object which stores the samples pSignal *SampleTF1(TF1 *f, int nsamples); //! samples realistically (i.e. with noise, jitter...real ADC!) a continuous signal described by a function (function is ROOT class TF1) //! noise and jitter can be passed to the function, quantization can be activated/deactivated using a flag (quantize = 1/0) //! returns a pointer to a pSignal object which stores the samples pSignal *SampleTF1(TF1 *f, int nsamples, double sigma_noise, double t_jitter, int quantize); //! samples realistically (i.e. with noise, jitter...real ADC!) a sine wave (you must pass amplitude and frequency) //! noise and jitter must be set in advance, quantization is always performed //! returns a pointer to a pSignal object which stores the samples pSignal *SampleSine(double amplitude, double freq, double toff, int nsamples); //! samples realistically (i.e. with noise, jitter...real ADC!) a sine wave (you must pass amplitude and frequency) //! noise and jitter can be passed to the function, quantization is always performed //! returns a pointer to a pSignal object which stores the samples pSignal *SampleSine(double amplitude, double freq, double toff, int nsamples, double sigma_noise, double t_jitter); //! samples realistically (i.e. with noise, jitter...real ADC!) a simulated charge preamp signal //! (NB: noise and jitter must be set in advance), quantization is always performed //! returns a pointer to a pSignal object which stores the samples /*!
    *
  • amplitude: step amplitude in Volts *
  • tzero: length of baseline before step in ns *
  • risetime: leading edge time constant in ns *
  • tau: decay time constant in ns *
  • baseline: DC value of signal in Volts *
  • nsamples: number of samples to be produced *
e.g. \code pADC adc(14, 0.1, 2) adc.SetInputNoise(1.5) adc.SetApertureJitter(0.01) pSignal *sig = adc.SamplePreamp(0.5,1000,20,10000,0.01,2000) sig->Draw("ALP") \endcode produces a signal like this one: \image html preamp_signal.png "Sampled charge preamp signal, simulated with pADC class" zooming in on the baseline, we can see the presence of sampling noise: \image html preamp_signal_noise.png "Sampling noise produced by pADC (rms 1.5 LSB)" */ pSignal *SamplePreamp(double amplitude, double tzero, double risetime, double tau, double baseline, int nsamples); //! samples realistically (i.e. with noise, jitter...real ADC!) a simulated charge preamp signal //! obtained from the integration on a preamp of a current signal with two time costants //! (NB: noise and jitter must be set in advance), quantization is always performed //! returns a pointer to a pSignal object which stores the samples /*!
    *
  • amplitude: step amplitude in Volts (if tau->infinity) *
  • tzero: length of baseline before step in ns *
  • trise_i: leading edge time constant (in ns) of the current signal *
  • tfall_i: falling edge time constant (in ns) of the current signal *
  • tau: decay time constant in ns *
  • baseline: DC value of signal in Volts *
  • nsamples: number of samples to be produced *
e.g. \code pADC adc(14, 0.1, 2) adc.SetInputNoise(1.5) adc.SetApertureJitter(0.01) pSignal *sig = adc.SampleChargeSignal(0.5,1000,20,20,10000,0.01,2000) sig->Draw("ALP") \endcode */ pSignal *SampleChargeSignal(double amplitude, double tzero, double trise_i,double tfall_i, double tau, double baseline, int nsamples); // getters //! get actual pADC range in volt double GetRange(){ return range;} //! get pADC resolution int GetNbits(){ return Nbits;} //! get value of fractional flag int GetFractional(){ return fractional;} //! get input referred noise std dev in LSB (bits!) double GetInputNoise(){ return sigma_in_noise;} //! get aperture jitter std dev in ns double GetApertureJitter(){ return ap_jitter;} //! get sampling period Ts in ns double GetTs(){ return Ts;} //! get sampling frequency Fs in GHz double GetFs(){ return Fs;} // setters //! set fractional (val=1) or integer (val=0) mode //! in fractional mode, the ADC produces values between -1 (-Full Scale) and 1 (+Full Scale) //! in integer mode, the ADC produces values between -2^(N-1) and 2^(N-1)-1 int SetFractional(int val){fractional=val; return fractional;} //! set pADC resolution (Nbits=number of physical bits) //! the ADC range will be divided into 2^Nbits intervals int SetNbits(int val){Nbits=val; return Nbits;} //! set pADC range in volts (range is maximum-minimum acceptable value) //! voltages between -range/2 and range/2 will be converted without over/underflow double SetRange(double val){range=val; return range;} //! set input referred noise std dev in LSB (bits!) //! gaussian amplitude fluctuations with standard deviation=sigma will be //! added in the sampling process, to simulate the Input Referred noise of the ADC //! (noise due to internal analog stages, buffers etc) double SetInputNoise(double sigma){sigma_in_noise=sigma; return sigma_in_noise;} //! set aperture jitter std dev in ns //! fluctuations of the time when a sample is actually taken //! (in a real ADC they are due to the internal track and hold electronics //! and to jitter of the sampling clock: //! there is a certain uncertainty on the sampling time) double SetApertureJitter(double sigma){ap_jitter=sigma; return ap_jitter;} //! set sampling period in ns (sampling frequency is updated automatically) double SetTs(double val){Ts = val; Fs=1./Ts*1.0e3; return Ts;} //! set Fs in GHz (sampling period is automatically updated) double SetFs(double val){Fs = val; Ts=1./Fs*1.0e3; return Fs;} protected: double Ts; //! sampling period in ns double Fs; //! sampling frequency in GHz double range; //! peak-to-peak range, default 2V=+- 1V int Nbits; //! number of bits for quantization (resolution) int fractional; //! set to 1 for fractional (i.e. abs(sample)<1) output double sigma_in_noise; //! input referred (a.k.a. code transition noise) std. dev. in bits double ap_jitter; //! aperture jitter std. dev. in ns ClassDef(pADC,2); }; #endif