Commit 1f602161 authored by dauncey's avatar dauncey

Test of new branch

parent c25b469e
......@@ -9,7 +9,6 @@ CXX = g++
PYTHON_EXE = /usr/include/python2.6
HEPMC_DIR = $(HEPMCSYS)
BOOST_DIR = $(BOOSTSYS)
RAWDATA_DIR = $(SIMRAWDATA)
####################
......@@ -21,6 +20,10 @@ MKFILE_PATH = $(abspath $(lastword $(MAKEFILE_LIST)))
TOP = $(patsubst %/,%,$(dir $(MKFILE_PATH)))
CURRENT = $(shell pwd)
# RawData directory
#RAWDATA_DIR = $(ANALSYS)/$(SIMRAWDATA)
RAWDATA_DIR = $(CURRENT)/$(SIMRAWDATA)
# python
PYTHON_CODE = $(TOP)/python
......@@ -64,8 +67,8 @@ ROOT_LIBS = $(shell root-config --libs)
ROOT_GLIBS = $(shell root-config --glibs)
# Boost
BOOST_FLAGS = -I$(BOOST_DIR)/include
BOOST_LIBS = -L$(BOOST_DIR)/lib -lboost_filesystem -lboost_system
if [ ! -d $(BOOSTSYS) ]; then BOOST_FLAGS = -I$(BOOST_DIR)/include
if [ ! -d $(BOOSTSYS) ]; then BOOST_LIBS = -L$(BOOST_DIR)/lib -lboost_filesystem -lboost_system
# HepMC flags
HEPMC_FLAGS = -I$(HEPMC_DIR)/include
......@@ -79,6 +82,7 @@ CXXFLAGS += $(HEPMC_FLAGS)
CXXFLAGS += -I$(NAVIGATION_DIR)
CXXFLAGS += -I$(INTERFACE_DIR)
CXXFLAGS += -I$(TOP)/src
CXXFLAGS += -I$(RAWDATA_DIR)
#CXXFLAGS += -I$(PYTHON_EXE)
# CXX LIBS
......@@ -111,6 +115,7 @@ echo:
echo $(TOP)
echo $(CURRENT)
echo $(BOOST_DIR)
echo $(BIN_DIR)
# echo $(INTERFACE_DIR)
# echo $(CXX) $(CXXFLAGS) -o bin/$@ $<
# echo $(EXES)
......
No preview for this file type
......@@ -13,7 +13,187 @@
\begin{document}
\centerline{\Large \bf Notes on TPG}
\bigskip
\centerline{\large May 2016}
\centerline{\large \today}
\section{Latency and drain-time limits on signal bandwidth overheads}
In addition to the pileup-generated rate of hits (both for DAQ and TPG),
there are also occasional signal events. Some of these can cause a large number
of hits in a small area, such as a motherboard. The bandwidth for data coming
from the motherboard must include some overhead above the value needed for the
pileup as otherwise these signal events will eventually cause buffer overflows.
There are two issues; latency (particularly important for the TPG) and the
``drain-time'' of the FE buffers. This latter is the time taken to flush out the
extra data from the signal event such that the buffers are back at the steady
state of handling the average pileup. A long drain-time would mean the buffers
are fuller than normal and so there is a risk that another signal event could
cause an overflow. The effect of latency is clear but it is
harder to put a firm requirement on the drain-time.
Let the maximum signal plus pileup data volume for a BX in a panel be $s$ bits
and the average pileup data volume per BX be $p$ bits, where clearly $s>p$.
The ``extra'' data due to the signal is obviously $s-p$ bits. A bandwidth $b$
is to be determined, where $b > p$. Clearly $b=s$ would allow any signal event
to be read out within one BX but would be more bandwidth that really required.
Hence, that the bandwidth is set to be that required for the pileup plus some
fraction $f$ of the extra data due to the signal, i.e.
\begin{equation}
b = p+f(s-p) = fs+(1-f)p
\end{equation}
For this bandwidth then the drain-time $d$ is given by the amount of
extra data, $s-p$, divided by the extra bandwidth above the pileup rate,
$f(s-p)$, i.e.
\begin{equation}
d = \frac{s-p}{f(s-p)} = \frac{1}{f}
\end{equation}
The latency $l$ is the time to read out the whole signal event given the total
bandwidth, so
\begin{equation}
l = \frac{s}{b} = \frac{s}{fs+(1-f)p} = \frac{1}{f[1-(p/s)]+(p/s)}
\end{equation}
Note that
\begin{equation}
\frac{l}{d} = \frac{1}{[1-(p/s)]+(p/fs)} = \frac{1}{1+(p/s)(1/f-1)}<1
\end{equation}
i.e. the latency is always shorter than the drain-time.
The value of the fraction is obviously limited to $0 < f < 1$ so the limits on
the latency are $(s/p) > l > 1$. The lower limit, which occurs for $f=1$, is
simply adding in enough bandwidth so $b=s$. The upper limit says that even with
zero overhead bandwidth, where $b=p$, the latency for reading out the signal
event is simply $s/b=s/p$.
If this upper latency limit is below the allowable latency, then the drain-time
is the only relevant limit. Otherwise, both limits need to be checked to set the
value of $f$. Take an example; with a latency limit of 10 BX, a drain-time
limit (semi-arbitrarily) of 40 BX (i.e. before the next L1 trigger on average),
and a ratio of $s/p = 20$, then the latency limit means the fraction must be
\begin{equation}
f \ge \frac{(1/l)-(p/s)}{1-(p/s)} = \frac{0.1-0.05}{1-0.1} = \frac{1}{19}
\end{equation}
which is stricter that the drain-time limit $f \ge 1/40$ and so sets the
required fraction. The two limits are equivalent for a particular value
of $p/s$ which is given by
\begin{equation}
f = \frac{(1/l)-(p/s)}{1-(p/s)} = \frac{1}{d}
\end{equation}
which gives
\begin{equation}
\frac{p}{s} = \frac{(d/l)-1}{d-1}
\end{equation}
and for the example here results in
\begin{equation}
\frac{p}{s} = \frac{4-1}{40-1} = \frac{3}{39} = \frac{1}{13}
\end{equation}
Hence, if $s/p \le 13$, then the drain-time limit is stricter.
\section{Hexagonal integer grid}
The centres of a regular array of hexagons can be considered to lie on an
effective Cartesian grid, with the $y$ axis unit equal to $3/2$ of the hexagon
side and the $x$ axis unit equal to $\sqrt{3}/2$ of the hexagonal side, i.e.
the ratio of $y/x$ units is $\sqrt{3}$. The centres of the hexagons then
lie on integer values of $x$ and $y$, $i_x$ and $i_y$, and
occupy a chessboard pattern, here assumed to have the sum of $i_x+i_y$ being
even. The centres are 2 units apart along the $x$ axis but are 1 unit apart
along the $y$ axis. E.g. the valid wafer along the $x$ axis are at $i_y=0$
and $i_x = \dots, -4, -2, 0, 2, 4, \dots$. The next row up is $i_y=1$
and $i_x = \dots, -3, -1, 1, 3, \dots$, while the next row down is $i_y=-1$
with the same values of $i_x$.
The valid wafer centres can also be described by plane polar coordinates,
$i_r$ and $i_\phi$, where $i_r \ge 0$ and
$i_\phi$ is limited to the range 0 to $6i_r-1$,
except the centre $i_x=0$ and $i_y=0$ has $i_r=0$ and $i_\phi=0$.
\bigskip
\begin{center}
\begin{tabular}{c|c}
\hline
$i_x, i_y$ & $i_r, i_\phi$ \cr\hline
$ 0, 0$ & $0, 0$ \cr\hline
$ 2, 0$ & $1, 0$ \cr
$ 1, 1$ & $1, 1$ \cr
$-1, 1$ & $1, 2$ \cr
$-2, 0$ & $1, 3$ \cr
$-1,-1$ & $1, 4$ \cr
$ 1,-1$ & $1, 5$ \cr\hline
$ 4, 0$ & $2, 0$ \cr
$ 3, 1$ & $2, 1$ \cr
$ 2, 2$ & $2, 2$ \cr
$ 0, 2$ & $2, 3$ \cr
$-2, 2$ & $2, 4$ \cr
$-3, 1$ & $2, 5$ \cr
$-4, 0$ & $2, 6$ \cr
$-3,-1$ & $2, 7$ \cr
$-2,-2$ & $2, 8$ \cr
$ 0,-2$ & $2, 9$ \cr
$ 2,-2$ & $2,10$ \cr
$ 3,-1$ & $2,11$ \cr
\hline
\end{tabular}
\end{center}
A rotation by $\Delta\phi = 60^\circ$ and $-60^\circ \equiv 300^\circ$
in Cartesian coordinates would be
\begin{equation}
\begin{pmatrix}
x^\prime \\ y^\prime
\end{pmatrix}
= \begin{pmatrix}
1/2 & \mp\sqrt{3}/2 \\ \pm\sqrt{3}/2 & 1/2
\end{pmatrix}
\begin{pmatrix}
x \\ y
\end{pmatrix}
\end{equation}
But the units mean $x^{(\prime)} \propto i_x^{(\prime)}$ while
$y^{(\prime)} \propto \sqrt{3}i_y^{(\prime)}$ so
\begin{equation}
\begin{pmatrix}
i_x^\prime \\ \sqrt{3}i_y^\prime
\end{pmatrix}
= \begin{pmatrix}
1/2 & \mp\sqrt{3}/2 \\ \pm\sqrt{3}/2 & 1/2
\end{pmatrix}
\begin{pmatrix}
i_x \\ \sqrt{3}i_y
\end{pmatrix}
\qquad{\rm so}\qquad
\begin{pmatrix}
i_x^\prime \\ i_y^\prime
\end{pmatrix}
= \begin{pmatrix}
1/2 & \mp 3/2 \\ \pm 1/2 & 1/2
\end{pmatrix}
\begin{pmatrix}
i_x \\ i_y
\end{pmatrix}
\end{equation}
A rotation of $120^\circ$ and $-120^\circ \equiv 240^\circ$ is therefore
\begin{equation}
\begin{pmatrix}
i_x^\prime \\ i_y^\prime
\end{pmatrix}
= \begin{pmatrix}
-1/2 & \mp 3/2 \\ \pm 1/2 & -1/2
\end{pmatrix}
\begin{pmatrix}
i_x \\ i_y
\end{pmatrix}
\end{equation}
while a rotation of $180^\circ$ is simply
\begin{equation}
\begin{pmatrix}
i_x^\prime \\ i_y^\prime
\end{pmatrix}
= \begin{pmatrix}
-1 & 0 \\ 0 & -1
\end{pmatrix}
\begin{pmatrix}
i_x \\ i_y
\end{pmatrix}
\end{equation}
\section{Optimisation of layer weights}
Each event $e$ gives some values $d_{e,i}$ of the deposited energy in
......
// The architecture setting defines how the charge is digitised
//
// The method setting defines how the digitised values are combined
// for the trigger
#ifndef AdcReading_HH
#define AdcReading_HH
......@@ -10,17 +15,40 @@
class AdcReading {
public:
AdcReading() : fLoData(0), fHiData(0) {
AdcReading() : fLoData(0), fHiData(0),
fLoPedestal(0.5), fHiPedestal(0.5),
fLoGain(0.0), fHiGain(0.0) {
initialise();
}
~AdcReading() {
}
void initialise() {
assert(fLoGain==0.0 && fHiGain==0.0);
fLoPedestal=Random::random().Uniform()-0.5;
fHiPedestal=Random::random().Uniform()-0.5;
fLoGain=Random::random().Gaus();
fHiGain=Random::random().Uniform()-0.5;
}
double loPedestal() const {
return fLoPedestal;
}
double hiPedestal() const {
return fHiPedestal;
}
double loGain() const {
return fLoGain;
}
double hiGain() const {
return fHiGain;
}
uint16_t loData() const {
return fLoData;
}
......@@ -35,88 +63,112 @@ public:
}
void reading(double q) {
if(q<0.0) {
fLoData=0;
fHiData=0;
double loAdcLsb(fLoAdcLsb*(1.0+fLoGainWidth*fLoGain));
double loAdc(fLoPedestal+(q/loAdcLsb));
} else {
double loAdcLsb(fLoAdcLsb*(1.0+fLoGainWidth*fLoGain));
double hiAdcLsb(fHiAdcLsb*(1.0+fHiGainWidth*fHiGain));
// Allow for non-linear TOT
if(fArchitecture==0) {
if(q>150.0) q-=150.0*(150.0-140.0)/(q-140.0);
else q=0.0;
}
// TP = baseline
if(fArchitecture==0) {
double hiAdcLsb(fHiAdcLsb*(1.0+fHiGainWidth*fHiGain));
double hiAdc(fHiPedestal+(q/hiAdcLsb));
// Baseline and ~ideal baseline
if(fArchitecture==0 ||fArchitecture==1) {
// Low range
fLoData=1023;
if(q<1023.0*loAdcLsb) fLoData=uint16_t(q/loAdcLsb);
// High range
if(q>100.0) q-=100.0*(100.0-90.0)/(q-90.0);
else q=0.0;
fHiData=4095;
if(q<4095.0*fHiAdcLsb) fHiData=uint16_t(q/fHiAdcLsb);
// Low range
if(loAdc<0.0) {
fLoData=0;
} else {
if(loAdc<fLoSaturation) fLoData=uint16_t(loAdc+0.5);
else fLoData=fLoSaturation;
}
// Bi-gain with TOT which is never used in the trigger
if(fArchitecture==1) {
// Low range
fLoData=1023;
if(q<1023.0*loAdcLsb) fLoData=uint16_t(q/loAdcLsb);
// High range
fHiData=16383;
if(q<16383.0*fHiAdcLsb) fHiData=uint16_t(q/fHiAdcLsb);
//std::cout << "q = " << q << " lo,hi = " << fLoData << ", " << fHiData << std::endl;
// High range
if(hiAdc<0.0) {
fHiData=0;
} else {
if(hiAdc<fHiSaturation) fHiData=uint16_t(hiAdc+0.5);
else fHiData=fHiSaturation;
}
}
// Bi-gain with TOT which is never used in the trigger
if(fArchitecture==2) {
// Bi-gain with no TOT
if(fArchitecture==2) {
// Low range
fLoData=255;
if(q< 255.0*loAdcLsb) fLoData=uint16_t(q/loAdcLsb);
// High range
fHiData=4095;
if(q<4095.0*fHiAdcLsb) fHiData=uint16_t(q/fHiAdcLsb);
// Low range
if(loAdc<0.0) {
fLoData=0;
} else {
if(loAdc<fLoSaturation) fLoData=uint16_t(loAdc+0.5);
else fLoData=fLoSaturation;
}
// Single gain ~ideal
if(fArchitecture==3) {
// Low and high ranges combined to store more than 16 bits
uint32_t total(524287);
if(q<524287.0*loAdcLsb) total=uint32_t(q/loAdcLsb);
fLoData=(total&0xffff);
fHiData=(total>>16);
if(fHiData>7) {
std::cout << "AdcReading::reading() Arch 3, q = " << q
<< ", loAdcLsb = " << loAdcLsb
<< ", fLoData = " << fLoData
<< ", fHiData = " << fHiData
<< ", total = " << total << std::endl;
}
// High range
if(hiAdc<0.0) {
fHiData=0;
} else {
if(hiAdc<16383.0) fHiData=uint16_t(hiAdc+0.5);
else fHiData=16383;
}
}
// Bi-gain ~ideal
if(fArchitecture==4) {
// Bi-gain with no TOT
if(fArchitecture==3) {
// Low range
if(loAdc<0.0) {
fLoData=0;
} else {
if(loAdc<255.0) fLoData=uint16_t(loAdc+0.5);
else fLoData=255;
}
// Low range
fLoData=1023;
if(q<1023.0*loAdcLsb) fLoData=uint16_t(q/loAdcLsb);
// High range
fHiData=4095;
if(q<4095.0*hiAdcLsb) fHiData=uint16_t(q/hiAdcLsb);
// High range
if(hiAdc<0.0) {
fHiData=0;
} else {
if(hiAdc<fHiSaturation) fHiData=uint16_t(hiAdc+0.5);
else fHiData=fHiSaturation;
}
}
// Single gain ~ideal
if(fArchitecture==4) {
// Low and high ranges combined to store more than 16 bits
uint32_t total;
if(loAdc<0.0) {
total=0;
} else {
if(loAdc<524287.0) total=uint32_t(loAdc+0.5);
else total=524287;
}
fLoData=(total&0xffff);
fHiData=(total>>16);
if(fHiData>7) {
std::cout << "AdcReading::reading() Arch 3, q = " << q
<< ", loAdcLsb = " << loAdcLsb
<< ", fLoData = " << fLoData
<< ", fHiData = " << fHiData
<< ", total = " << total << std::endl;
}
}
}
// Assume this is used for merging the two ranges for
// the TPG path only, not for the DAQ and TPG selection
uint32_t result() const {
return trgResult();
}
uint32_t trgResult() const {
assert(fMethod<numberOfMethods());
if(fArchitecture==0) {
......@@ -198,13 +250,29 @@ public:
return 25*fHiData+12;
}
// IMPLEMENT THIS SOMEWHERE HERE!!!
/*
unsigned r(result());
if(fTruncateBits>0) {
r>>=fTruncateBits;
r<<=fTruncateBits;
}
*/
assert(false);
return 0xffffffff;
}
// Assume this is only used for DAQ and TPG path selection
// in DigHit, not for TPG merging of two ranges
double chargeResult() const {
return daqResult();
}
double daqResult() const {
/*
if(fArchitecture==0) return fAdcLsb*(result()+0.5);
if(fArchitecture==1) return fAdcLsb*(result()+0.5);
......@@ -218,12 +286,31 @@ public:
assert(false);
return 999999.0;
*/
/*
unsigned r(result());
if(fTruncateBits>0) {
r>>=fTruncateBits;
r<<=fTruncateBits;
}
return fAdcLsb*(r+0.5);
*/
//return fAdcLsb*(r+0.5);
if(fLoData<fLoSaturation) {
double loAdcLsb(fLoAdcLsb*(1.0+fLoGainWidth*fLoGain));
return loAdcLsb*(fLoData-fLoPedestal);
}
double hiAdcLsb(fHiAdcLsb*(1.0+fHiGainWidth*fHiGain));
double q(hiAdcLsb*(fHiData-fHiPedestal));
if(fArchitecture==0) {
if(q>0.0) q=0.5*(140.0+q+sqrt((140.0-q)*(140.0-q)+600*(150.0-140.0)));
else q=0.0;
}
return q;
}
bool read(std::istream &fin) {
......@@ -239,73 +326,105 @@ public:
}
void print() const {
std::cout << "AdcReading " << fLoData << ", " << fHiData;
std::cout << "AdcReading ADC values " << fLoData << ", " << fHiData;
}
static void setArchitecture(unsigned a) {
assert(a<fNumberOfArchitectures);
fArchitecture=a;
resetMethod();
void printConstants() const {
std::cout << "AdcReading Low pedestal, gain " << fLoPedestal << ", " << fLoGain
<< ", High pedestal, gain " << fHiPedestal << ", " << fHiGain << std::endl
<< std::endl;
}
static void resetArchitecture() {
setArchitecture(0);
static void printStatics() {
std::cout << "AdcReading parameters: architecture " << fArchitecture
<< ", method " << fMethod << std::endl
<< " ADC: LSB " << fLoAdcLsb
<< ", saturation " << fLoSaturation << ", gain width " << fLoGainWidth << std::endl
<< " TDC: LSB " << fHiAdcLsb
<< ", saturation " << fHiSaturation << ", gain width " << fHiGainWidth << std::endl
<< " Range ratio " << fRatio << std::endl
<< " Truncation bits " << fTruncateBits << std::endl
<< std::endl;
}
static unsigned numberOfMethods() {
if(fArchitecture==0) return 5;
if(fArchitecture==1) return 8;
if(fArchitecture==2) return 5;
if(fArchitecture==3) return 1;
if(fArchitecture==4) return 1;
return 0;
static double loAdcLsb() {
return fLoAdcLsb;
}
static void setMethod(unsigned m) {
assert(m<numberOfMethods());
fMethod=m;
static double hiAdcLsb() {
return fLoAdcLsb;
}
if(fArchitecture==2 && fMethod==1) {
}
static double hiAdcToFc(double a) {
return a*fLoAdcLsb;
}
static void resetMethod() {
static double fcToLoAdc(double q) {
return q/fLoAdcLsb;
}
if(fArchitecture==0) {
fMethod=2;
static void setArchitecture(unsigned a) {
assert(a<fNumberOfArchitectures);
fArchitecture=a;
if(fArchitecture==0 || fArchitecture==1) {
fLoAdcLsb=fAdcLsb;
fRatio=24.9;
fRatio=30.0;
fHiAdcLsb=fRatio*fAdcLsb;
//fLoSaturation=(1<<11)-1;
fLoSaturation=1600; // Force earlier saturation than 11 bits = 2047
fHiSaturation=(1<<13)-1;
}
if(fArchitecture==1) {
fMethod=0;