improve Histogram1D and trace View

This commit is contained in:
splitPoleDAQ 2023-06-01 17:51:00 -04:00
parent 69d25facb8
commit d241fec8b5
7 changed files with 272 additions and 102 deletions

View File

@ -12,6 +12,8 @@ Canvas::Canvas(Digitizer ** digi, unsigned int nDigi, QMainWindow * parent) : QM
this->digi = digi;
this->nDigi = nDigi;
enableSignalSlot = false;
setWindowTitle("Canvas");
setGeometry(0, 0, 1000, 800);
//setWindowFlags( this->windowFlags() & ~Qt::WindowCloseButtonHint );
@ -21,56 +23,134 @@ Canvas::Canvas(Digitizer ** digi, unsigned int nDigi, QMainWindow * parent) : QM
QVBoxLayout * layout = new QVBoxLayout(layoutWidget);
layoutWidget->setLayout(layout);
//========================
QGroupBox * controlBox = new QGroupBox("Control", this);
layout->addWidget(controlBox);
QGridLayout * ctrlLayout = new QGridLayout(controlBox);
controlBox->setLayout(ctrlLayout);
{//^========================
QGroupBox * controlBox = new QGroupBox("Control", this);
layout->addWidget(controlBox);
QGridLayout * ctrlLayout = new QGridLayout(controlBox);
controlBox->setLayout(ctrlLayout);
QPushButton * bnClearHist = new QPushButton("Clear Hist.", this);
ctrlLayout->addWidget(bnClearHist, 0, 0);
connect(bnClearHist, &QPushButton::clicked, this, [=](){
for( int i = 0; i < MaxNDigitizer; i++){
for( int j = 0; j < MaxNChannels; j++){
if( hist[i][j] ) hist[i][j]->Clear();
cbDigi = new RComboBox(this);
for( unsigned int i = 0; i < nDigi; i++) cbDigi->addItem("Digi-" + QString::number( digi[i]->GetSerialNumber() ), i);
ctrlLayout->addWidget(cbDigi, 0, 0, 1, 2);
connect( cbDigi, &RComboBox::currentIndexChanged, this, &Canvas::ChangeHistView);
cbCh = new RComboBox(this);
for( int i = 0; i < MaxNChannels; i++) cbCh->addItem("ch-" + QString::number( i ), i);
ctrlLayout->addWidget(cbCh, 0, 2, 1, 2);
connect( cbCh, &RComboBox::currentIndexChanged, this, &Canvas::ChangeHistView);
QPushButton * bnClearHist = new QPushButton("Clear Hist.", this);
ctrlLayout->addWidget(bnClearHist, 0, 4, 1, 2);
connect(bnClearHist, &QPushButton::clicked, this, [=](){
for( unsigned int i = 0; i < nDigi; i++){
for( int j = 0; j < MaxNChannels; j++){
if( hist[i][j] ) hist[i][j]->Clear();
}
}
}
});
});
cbDigi = new RComboBox(this);
for( unsigned int i = 0; i < nDigi; i++) cbDigi->addItem("Digi-" + QString::number( digi[i]->GetSerialNumber() ), i);
ctrlLayout->addWidget(cbDigi, 1, 0);
connect( cbDigi, &RComboBox::currentIndexChanged, this, &Canvas::ChangeHistView);
QLabel * lbNBin = new QLabel("#Bin:", this);
lbNBin->setAlignment(Qt::AlignRight | Qt::AlignCenter );
ctrlLayout->addWidget(lbNBin, 1, 0);
sbNBin = new RSpinBox(this);
sbNBin->setMinimum(0);
sbNBin->setMaximum(500);
ctrlLayout->addWidget(sbNBin, 1, 1);
connect(sbNBin, &RSpinBox::valueChanged, this, [=](){
if( !enableSignalSlot ) return;
sbNBin->setStyleSheet("color : blue;");
bnReBin->setEnabled(true);
});
cbCh = new RComboBox(this);
for( int i = 0; i < MaxNChannels; i++) cbCh->addItem("ch-" + QString::number( i ), i);
ctrlLayout->addWidget(cbCh, 1, 1);
connect( cbCh, &RComboBox::currentIndexChanged, this, &Canvas::ChangeHistView);
QLabel * lbXMin = new QLabel("X-Min:", this);
lbXMin->setAlignment(Qt::AlignRight | Qt::AlignCenter );
ctrlLayout->addWidget(lbXMin, 1, 2);
sbXMin = new RSpinBox(this);
sbXMin->setMinimum(-0x3FFF);
sbXMin->setMaximum(0x3FFF);
ctrlLayout->addWidget(sbXMin, 1, 3);
connect(sbXMin, &RSpinBox::valueChanged, this, [=](){
if( !enableSignalSlot ) return;
sbXMin->setStyleSheet("color : blue;");
bnReBin->setEnabled(true);
});
//========================
histBox = new QGroupBox("Histgrams", this);
layout->addWidget(histBox);
histLayout = new QGridLayout(histBox);
histBox->setLayout(histLayout);
QLabel * lbXMax = new QLabel("X-Max:", this);
lbXMax->setAlignment(Qt::AlignRight | Qt::AlignCenter );
ctrlLayout->addWidget(lbXMax, 1, 4);
sbXMax = new RSpinBox(this);
sbXMax->setMinimum(-0x3FFF);
sbXMax->setMaximum(0x3FFF);
ctrlLayout->addWidget(sbXMax, 1, 5);
connect(sbXMin, &RSpinBox::valueChanged, this, [=](){
if( !enableSignalSlot ) return;
sbXMin->setStyleSheet("color : blue;");
bnReBin->setEnabled(true);
});
double xMax = 4000;
double xMin = 0;
double nBin = 100;
bnReBin = new QPushButton("Rebin and Clear Histogram", this);
ctrlLayout->addWidget(bnReBin, 1, 6);
bnReBin->setEnabled(false);
connect(bnReBin, &QPushButton::clicked, this, [=](){
if( !enableSignalSlot ) return;
int bd = cbDigi->currentIndex();
int ch = cbCh->currentIndex();
hist[bd][ch]->Rebin( sbNBin->value(), sbXMin->value(), sbXMax->value());
sbNBin->setStyleSheet("");
sbXMin->setStyleSheet("");
sbXMax->setStyleSheet("");
bnReBin->setEnabled(false);
hist[bd][ch]->UpdatePlot();
});
for( unsigned int i = 0; i < MaxNDigitizer; i++){
for( int j = 0; j < digi[i]->GetNChannels(); j++){
if( i < nDigi ) {
hist[i][j] = new Histogram1D("Digi-" + QString::number(digi[i]->GetSerialNumber()) +", Ch-" + QString::number(j), "Raw Energy [ch]", nBin, xMin, xMax);
}else{
hist[i][j] = nullptr;
}
}
}
histLayout->addWidget(hist[0][0], 0, 0);
{//^========================
histBox = new QGroupBox("Histgrams", this);
layout->addWidget(histBox);
histLayout = new QGridLayout(histBox);
histBox->setLayout(histLayout);
double xMax = 4000;
double xMin = 0;
double nBin = 100;
for( unsigned int i = 0; i < MaxNDigitizer; i++){
if( i >= nDigi ) continue;
for( int j = 0; j < digi[i]->GetNChannels(); j++){
if( i < nDigi ) {
hist[i][j] = new Histogram1D("Digi-" + QString::number(digi[i]->GetSerialNumber()) +", Ch-" + QString::number(j), "Raw Energy [ch]", nBin, xMin, xMax);
}else{
hist[i][j] = nullptr;
}
}
}
histLayout->addWidget(hist[0][0], 0, 0);
sbNBin->setValue(nBin);
sbXMin->setValue(xMin);
sbXMax->setValue(xMax);
}
layout->setStretch(0, 1);
layout->setStretch(1, 6);
for( unsigned int i = 0; i < nDigi; i++){
for( int ch = 0; ch < MaxNChannels ; ch++) {
lastFilledIndex[i][ch] = -1;
loopFilledIndex[i][ch] = 0;
}
}
oldBd = -1;
oldCh = -1;
enableSignalSlot = true;
}
Canvas::~Canvas(){
@ -92,6 +172,18 @@ void Canvas::ChangeHistView(){
histLayout->addWidget(hist[bd][ch], 0, 0);
if( enableSignalSlot ){
sbNBin->setValue(hist[bd][ch]->GetNBin());
sbXMin->setValue(hist[bd][ch]->GetXMin());
sbXMax->setValue(hist[bd][ch]->GetXMax());
sbNBin->setStyleSheet("");
sbXMin->setStyleSheet("");
sbXMax->setStyleSheet("");
}
bnReBin->setEnabled(false);
oldBd = bd;
oldCh = ch;
}
@ -103,16 +195,25 @@ void Canvas::UpdateCanvas(){
digiMTX[i].lock();
for( int ch = 0; ch < digi[i]->GetNChannels(); ch ++ ){
int lastIndex = digi[i]->GetData()->DataIndex[ch];
int nDecoded = digi[i]->GetData()->NumEventsDecoded[ch];
if( nDecoded == 0 ) continue;
int loopIndex = digi[i]->GetData()->LoopIndex[ch];
for( int j = lastIndex - nDecoded + 1; j <= lastIndex; j ++){
hist[i][ch]->Fill( digi[i]->GetData()->Energy[ch][j]);
int temp1 = lastIndex + loopIndex*MaxNData;
int temp2 = lastFilledIndex[i][ch] + loopFilledIndex[i][ch]*MaxNData;
//printf("%d |%d %d \n", ch, temp2, temp1);
if( lastIndex < 0 ) continue;
if( temp1 <= temp2 ) continue;
for( int j = 0 ; j <= temp1 - temp2; j ++){
lastFilledIndex[i][ch] ++;
if( lastFilledIndex[i][ch] > MaxNData ) {
lastFilledIndex[i][ch] = 0;
loopFilledIndex[i][ch] ++;
}
hist[i][ch]->Fill( digi[i]->GetData()->Energy[ch][lastFilledIndex[i][ch]]);
}
hist[i][ch]->UpdatePlot();
}
digiMTX[i].unlock();

View File

@ -42,10 +42,20 @@ private:
RComboBox * cbDigi;
RComboBox * cbCh;
bool enableSignalSlot;
RSpinBox * sbNBin;
RSpinBox * sbXMin;
RSpinBox * sbXMax;
QPushButton * bnReBin;
QGroupBox * histBox;
QGridLayout * histLayout;
int oldBd, oldCh;
int lastFilledIndex[MaxNDigitizer][MaxNChannels];
int loopFilledIndex[MaxNDigitizer][MaxNChannels];
};
#endif

View File

@ -7,8 +7,8 @@
//^==============================================
class Histogram1D : public QCustomPlot{
public:
Histogram1D(QString title, QString xLabel, int xBin, double xMin, double xMax, QWidget * parent = nullptr) : QCustomPlot(parent){
Rebin(xBin, xMin, xMax);
Histogram1D(QString title, QString xLabel, int xbin, double xmin, double xmax, QWidget * parent = nullptr) : QCustomPlot(parent){
Rebin(xbin, xmin, xmax);
xAxis->setLabel(xLabel);
@ -31,7 +31,7 @@ public:
graph(0)->setData(xList, yList);
//setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables);
setInteractions( QCP::iRangeZoom );
setInteractions( QCP::iRangeDrag | QCP::iRangeZoom );
rescaleAxes();
yAxis->setRangeLower(0);
@ -39,10 +39,10 @@ public:
connect(this, &QCustomPlot::mouseMove, this, [=](QMouseEvent *event){
double x = this->xAxis->pixelToCoord(event->pos().x());
int bin = (x - xMin)/dX;
double bin = (x - xMin)/dX;
double z = yList[2*qFloor(bin) + 1];
QString coordinates = QString("Bin: %1, Value: %2").arg(bin).arg(z);
QString coordinates = QString("Bin: %1, Value: %2").arg(qFloor(bin)).arg(z);
QToolTip::showText(event->globalPosition().toPoint(), coordinates, this);
});
@ -52,24 +52,28 @@ public:
menu->setAttribute(Qt::WA_DeleteOnClose);
QAction * a1 = menu->addAction("UnZoom");
//TODO QAction * a2 = menu->addAction("Fit Guass");
QAction *selectedAction = menu->exec(event->globalPosition().toPoint());
if( selectedAction == a1 ){
xAxis->setRangeLower(0);
xAxis->setRangeLower(xMin);
xAxis->setRangeUpper(xMax);
yAxis->setRangeLower(0);
yAxis->setRangeUpper(yMax * 1.2);
yAxis->setRangeUpper(yMax * 1.2 > 10 ? yMax * 1.2 : 10);
replot();
}
}
});
}
int GetNBin() const {return xBin;}
double GetXMin() const {return xMin;}
double GetXMax() const {return xMax;}
void UpdatePlot(){
graph(0)->setData(xList, yList);
xAxis->setRangeLower(0);
xAxis->setRangeLower(xMin);
xAxis->setRangeUpper(xMax);
yAxis->setRangeLower(0);
yAxis->setRangeUpper(yMax * 1.2 > 10 ? yMax * 1.2 : 10);
@ -77,14 +81,15 @@ public:
}
void Clear(){
for( int i = 0; i <= xBin; i++) yList[i] = 0;
graph(0)->setData(xList, yList);
for( int i = 0; i <= yList.count(); i++) yList[i] = 0;
yMax = 0;
UpdatePlot();
}
void Rebin(int xBin, double xMin, double xMax){
this->xMin = xMin;
this->xMax = xMax;
this->xBin = xBin;
void Rebin(int xbin, double xmin, double xmax){
xMin = xmin;
xMax = xmax;
xBin = xbin;
dX = (xMax - xMin)/(xBin);
@ -92,8 +97,8 @@ public:
yList.clear();
for( int i = 0; i <= xBin; i ++ ){
xList.append(i*dX-(dX)*0.000001);
xList.append(i*dX);
xList.append(xMin + i*dX-(dX)*0.000001);
xList.append(xMin + i*dX);
yList.append(0);
yList.append(0);
}
@ -107,7 +112,6 @@ public:
}
void Fill(double value){
totalEntry ++;
if( value < xMin ) underFlow ++;
if( value > xMax ) overFlow ++;
@ -115,6 +119,7 @@ public:
double bin = (value - xMin)/dX;
int index1 = 2*qFloor(bin) + 1;
int index2 = index1 + 1;
if( 0 <= index1 && index1 <= 2*xBin) yList[index1] += 1;
if( 0 <= index1 && index2 <= 2*xBin) yList[index2] += 1;
@ -145,19 +150,19 @@ private:
//^==============================================
class Histogram2D : public QCustomPlot{
public:
Histogram2D(QString title, QString xLabel, QString yLabel, int xBin, double xMin, double xMax, int yBin, double yMin, double yMax, QWidget * parent = nullptr) : QCustomPlot(parent){
this->xMin = xMin;
this->xMax = xMax;
this->yMin = yMin;
this->yMax = yMax;
this->xBin = xBin;
this->yBin = yBin;
Histogram2D(QString title, QString xLabel, QString yLabel, int xbin, double xmin, double xmax, int ybin, double ymin, double ymax, QWidget * parent = nullptr) : QCustomPlot(parent){
xMin = xmin;
xMax = xmax;
yMin = ymin;
yMax = ymax;
xBin = xbin;
yBin = ybin;
axisRect()->setupFullAxesBox(true);
xAxis->setLabel(xLabel);
yAxis->setLabel(yLabel);
colorMap = new QCPColorMap(this->xAxis, this->yAxis);
colorMap = new QCPColorMap(xAxis, yAxis);
colorMap->data()->setSize(xBin, yBin);
colorMap->data()->setRange(QCPRange(xMin, xMax), QCPRange(yMin, yMax));
colorMap->setInterpolate(false);
@ -180,8 +185,8 @@ public:
rescaleAxes();
connect(this, &QCustomPlot::mouseMove, this, [=](QMouseEvent *event){
double x = this->xAxis->pixelToCoord(event->pos().x());
double y = this->yAxis->pixelToCoord(event->pos().y());
double x = xAxis->pixelToCoord(event->pos().x());
double y = yAxis->pixelToCoord(event->pos().y());
int xI, yI;
colorMap->data()->coordToCell(x, y, &xI, &yI);
double z = colorMap->data()->cell(xI, yI);
@ -190,6 +195,26 @@ public:
QToolTip::showText(event->globalPosition().toPoint(), coordinates, this);
});
connect(this, &QCustomPlot::mousePress, this, [=](QMouseEvent * event){
if (event->button() == Qt::RightButton) {
QMenu *menu = new QMenu(this);
menu->setAttribute(Qt::WA_DeleteOnClose);
QAction * a1 = menu->addAction("UnZoom");
QAction *selectedAction = menu->exec(event->globalPosition().toPoint());
if( selectedAction == a1 ){
xAxis->setRangeLower(xMin);
xAxis->setRangeUpper(xMax);
yAxis->setRangeLower(yMin);
yAxis->setRangeUpper(yMax);
replot();
}
}
});
}
void UpdatePlot(){

View File

@ -16,6 +16,7 @@
#include <QLineSeries>
#include <QAreaSeries>
#include <QValueAxis>
#include <QMenu>
//^====================================================
class RSpinBox : public QDoubleSpinBox{
@ -108,20 +109,6 @@ public:
setRenderHints(QPainter::Antialiasing);
vRangeMin = -(0x1FFF);
vRangeMax = 0x1FFF;
hRangeMin = 0;
hRangeMax = 0;
}
void SetHRange(int min, int max) {
this->hRangeMin = min;
this->hRangeMax = max;
}
void SetVRange(int min, int max) {
this->vRangeMin = min;
this->vRangeMax = max;
}
protected:
bool viewportEvent(QEvent *event) override{
@ -134,7 +121,23 @@ protected:
void mousePressEvent(QMouseEvent *event) override{
if (m_isTouching) return;
QChartView::mousePressEvent(event);
if (event->button() == Qt::RightButton) {
QMenu *menu = new QMenu(this);
menu->setAttribute(Qt::WA_DeleteOnClose);
QAction * a1 = menu->addAction("UnZoom");
QAction *selectedAction = menu->exec(event->globalPosition().toPoint());
if( selectedAction == a1 ) chart()->zoomReset();
}
}
void wheelEvent(QWheelEvent * event) override{
qreal zoomFactor = event->angleDelta().y() > 0 ? 0.9 : 1.1;
chart()->zoom(zoomFactor);
}
void mouseMoveEvent(QMouseEvent *event) override{
QPointF chartPoint = this->chart()->mapToValue(event->pos());
QString coordinateText = QString("x: %1, y: %2").arg(QString::number(chartPoint.x(), 'f', 0)).arg(QString::number(chartPoint.y(), 'f', 0));
@ -162,9 +165,9 @@ protected:
case Qt::Key_Up: chart()->scroll(0, 10); break;
case Qt::Key_Down: chart()->scroll(0, -10); break;
case Qt::Key_R :
chart()->zoomReset();
//chart()->axes(Qt::Vertical).first()->setRange(-(0x1FFF), 0x1FFF);
chart()->axes(Qt::Vertical).first()->setRange(vRangeMin, vRangeMax);
if( hRangeMax != hRangeMin ) chart()->axes(Qt::Horizontal).first()->setRange(hRangeMin, hRangeMax);
//chart()->axes(Qt::Vertical).first()->setRange(vRangeMin, vRangeMax);
break;
default: QGraphicsView::keyPressEvent(event); break;
}
@ -172,10 +175,6 @@ protected:
private:
bool m_isTouching;
int hRangeMin;
int hRangeMax;
int vRangeMin;
int vRangeMax;
QLabel * m_coordinateLabel;
};

View File

@ -283,12 +283,12 @@ MainWindow::~MainWindow(){
if( scope ) delete scope;
if( digiSettings ) delete digiSettings;
if( canvas ) delete canvas;
if( onlineAnalyzer ) delete onlineAnalyzer;
if( digiSettings ) delete digiSettings;
if( scalar ) {
CleanUpScalar();
scalarThread->Stop();
@ -551,7 +551,10 @@ void MainWindow::OpenDigitizers(){
WaitForDigitizersOpen(false);
bnStopACQ->setEnabled(false);
if( rawDataPath == "" ) bnStartACQ->setEnabled(false);
if( rawDataPath == "" ) {
chkSaveData->setChecked(false);
chkSaveData->setEnabled(false);
}
SetupScalar();
@ -569,6 +572,12 @@ void MainWindow::CloseDigitizers(){
scope = nullptr;
}
if( canvas ){
canvas->close();
delete canvas;
canvas = nullptr;
}
if( digiSettings ){
digiSettings->close();
delete digiSettings;
@ -774,7 +783,6 @@ void MainWindow::UpdateScalar(){
if( influx ){
influx->AddDataPoint("Rate,Bd="+std::to_string(digi[iDigi]->GetSerialNumber()) + ",Ch=" + QString::number(i).rightJustified(2, '0').toStdString() + " value=" + QString::number(digi[iDigi]->GetData()->TriggerRate[i], 'f', 2).toStdString());
}
}
}
digiMTX[iDigi].unlock();
@ -802,10 +810,12 @@ void MainWindow::StartACQ(){
if( chkSaveData->isChecked() ) {
LogMsg("<font style=\"color: orange;\">===================== <b>Start a new Run-" + QString::number(runID) + "</b></font>");
WriteRunTimestamp(true);
}else{
LogMsg("<font style=\"color: orange;\">===================== <b>Start a non-save Run</b></font>");
}
for( unsigned int i = 0; i < nDigi ; i++){
if( chkSaveData->isChecked() ) {
if( digi[i]->GetData()->OpenSaveFile((rawDataPath + "/" + prefix + "_" + QString::number(runID).rightJustified(3, '0')).toStdString()) == false ) {
@ -866,6 +876,7 @@ void MainWindow::StopACQ(){
if( chkSaveData->isChecked() ) {
LogMsg("===================== Stop Run-" + QString::number(runID));
WriteRunTimestamp(false);
}else{
LogMsg("===================== Stop a non-save Run");
}

View File

@ -6,6 +6,21 @@ It has scope (updated every half-sec), allow full control of the digitizer (exce
It can be connected to InfluxDB v1.8 and Elog.
# Operation
When programSettings.txt is presented in the same folder as the FSUDAQ_Qt, the program will load it can config the following
- (line 1) raw data path, where the data will be stored.
- (line 2) the influxDB v1.8 IP
- (line 3) the database name
- (line 4) the elog IP
- (line 5) the elog logbook name
- (line 6) elog user name
- (line 7) elog user password
If no programSettings.txt is found. The program can still search for all digitizers that connected using optical cable.
Missing the raw data path will disable save data run, but still can start the ACQ. Missing InfluxDB (elog) variables will disable influxDB (elog).
# Undergoing
the following additional functions are planned and I am working on them
@ -19,10 +34,10 @@ the following additional functions are planned and I am working on them
Ubuntu 22.04
- CAENVMELib_v3.3
- CAENCOmm_v1.5.3
- CAENDigitizer_v2.17.1
- CAEN A3818 Driver
- CAENVMELib v3.3
- CAENCOmm v1.5.3
- CAENDigitizer v2.17.1
- CAEN A3818 Driver v1.6.8
- qt6-base-dev
- libqt6charts6-dec

View File

@ -206,6 +206,15 @@ Scope::Scope(Digitizer ** digi, unsigned int nDigi, ReadDataThread ** readDataTh
UpdatePanelFromMomeory();
if( digi[ID]->GetDPPType() == V1730_DPP_PHA_CODE ) {
QValueAxis * yaxis = qobject_cast<QValueAxis*> (plot->axes(Qt::Vertical).first());
yaxis->setRange(-(0x1FFF), 0x1FFF);
}
if( digi[ID]->GetDPPType() == V1730_DPP_PSD_CODE ) {
QValueAxis * yaxis = qobject_cast<QValueAxis*> (plot->axes(Qt::Vertical).first());
yaxis->setRange(0, 0x3FFF);
}
enableSignalSlot = true;
}