|
@@ -825,16 +825,69 @@ class DataqSdkChannelConfWidget : public BasicDeviceConfigurationWidget
|
825
|
825
|
void startCalibration();
|
826
|
826
|
void stopCalibration();
|
827
|
827
|
void resetCalibration();
|
|
828
|
+ void updateInput(Measurement measure);
|
|
829
|
+ void updateOutput(Measurement measure);
|
|
830
|
+ private:
|
|
831
|
+ QPushButton *startButton;
|
|
832
|
+ QPushButton *resetButton;
|
|
833
|
+ QPushButton *stopButton;
|
|
834
|
+ @<DATAQ SDK device settings@>@;
|
|
835
|
+ DataqSdkDevice *calibrationDevice;
|
|
836
|
+ LinearCalibrator *calibrator;
|
|
837
|
+ QLineEdit *currentMeasurement;
|
|
838
|
+ QLineEdit *minimumMeasurement;
|
|
839
|
+ QLineEdit *maximumMeasurement;
|
|
840
|
+ QLineEdit *averageMeasurement;
|
|
841
|
+ QLineEdit *currentMapped;
|
|
842
|
+ QLineEdit *minimumMapped;
|
|
843
|
+ QLineEdit *maximumMapped;
|
|
844
|
+ QLineEdit *averageMapped;
|
|
845
|
+ int rmCount;
|
|
846
|
+ int cmCount;
|
|
847
|
+ double rmin;
|
|
848
|
+ double rmax;
|
|
849
|
+ double rmean;
|
|
850
|
+ double cmin;
|
|
851
|
+ double cmax;
|
|
852
|
+ double cmean;
|
828
|
853
|
};
|
829
|
854
|
|
|
855
|
+@ Private members that hold minimum and maximum aggregate data for channel
|
|
856
|
+calibration will be initialized to the maximum and minimum values available for
|
|
857
|
+the |double| type respectively. This guarantees that the first measurement will
|
|
858
|
+overwrite these values. This is done with |std::numeric_limits| so we require a
|
|
859
|
+header to be included to gain access to this.
|
|
860
|
+
|
|
861
|
+@<Header files to include@>=
|
|
862
|
+#include <limits>
|
|
863
|
+
|
830
|
864
|
@ The constructor sets up the interface. Calibration settings line edits need
|
831
|
865
|
to have numeric validators added.
|
832
|
866
|
|
833
|
867
|
@<DataqSdkDeviceConfWidget implementation@>=
|
834
|
868
|
DataqSdkChannelConfWidget::DataqSdkChannelConfWidget(DeviceTreeModel *model,
|
835
|
869
|
const QModelIndex &index)
|
836
|
|
- : BasicDeviceConfigurationWidget(model, index)
|
|
870
|
+ : BasicDeviceConfigurationWidget(model, index),
|
|
871
|
+ startButton(new QPushButton(tr("Start"))),
|
|
872
|
+ resetButton(new QPushButton(tr("Reset"))),
|
|
873
|
+ stopButton(new QPushButton(tr("Stop"))),
|
|
874
|
+ calibrator(new LinearCalibrator),
|
|
875
|
+ currentMeasurement(new QLineEdit), minimumMeasurement(new QLineEdit),
|
|
876
|
+ maximumMeasurement(new QLineEdit), averageMeasurement(new QLineEdit),
|
|
877
|
+ currentMapped(new QLineEdit), minimumMapped(new QLineEdit),
|
|
878
|
+ maximumMapped(new QLineEdit), averageMapped(new QLineEdit),
|
|
879
|
+ rmCount(0), cmCount(0),
|
|
880
|
+ rmin(std::numeric_limits<double>::max()),
|
|
881
|
+ rmax(std::numeric_limits<double>::min()), rmean(0),
|
|
882
|
+ cmin(std::numeric_limits<double>::max()),
|
|
883
|
+ cmax(std::numeric_limits<double>::min()), cmean(0)
|
837
|
884
|
{
|
|
885
|
+ @<Find DATAQ SDK device settings from parent node@>@;
|
|
886
|
+ resetButton->setEnabled(false);
|
|
887
|
+ stopButton->setEnabled(false);
|
|
888
|
+ connect(startButton, SIGNAL(clicked()), this, SLOT(startCalibration()));
|
|
889
|
+ connect(resetButton, SIGNAL(clicked()), this, SLOT(resetCalibration()));
|
|
890
|
+ connect(stopButton, SIGNAL(clicked()), this, SLOT(stopCalibration()));
|
838
|
891
|
QVBoxLayout *layout = new QVBoxLayout;
|
839
|
892
|
QFormLayout *topLayout = new QFormLayout;
|
840
|
893
|
QLineEdit *columnEdit = new QLineEdit;
|
|
@@ -848,6 +901,7 @@ DataqSdkChannelConfWidget::DataqSdkChannelConfWidget(DeviceTreeModel *model,
|
848
|
901
|
layout->addLayout(topLayout);
|
849
|
902
|
QLabel *calibrationLabel = new QLabel(tr("Calibration settings"));
|
850
|
903
|
layout->addWidget(calibrationLabel);
|
|
904
|
+ QHBoxLayout *calibrationLayout = new QHBoxLayout;
|
851
|
905
|
QFormLayout *calibrationControlsLayout = new QFormLayout;
|
852
|
906
|
QLineEdit *measuredLowerEdit = new QLineEdit;
|
853
|
907
|
measuredLowerEdit->setText("0");
|
|
@@ -866,10 +920,35 @@ DataqSdkChannelConfWidget::DataqSdkChannelConfWidget(DeviceTreeModel *model,
|
866
|
920
|
QLineEdit *sensitivityEdit = new QLineEdit;
|
867
|
921
|
sensitivityEdit->setText("0");
|
868
|
922
|
calibrationControlsLayout->addRow(tr("Discrete interval skip"), sensitivityEdit);
|
869
|
|
- layout->addLayout(calibrationControlsLayout);
|
870
|
|
-
|
871
|
|
- // Insert another panel to assist in determining proper calibration values.
|
872
|
|
-
|
|
923
|
+ QVBoxLayout *calibrationTestLayout = new QVBoxLayout;
|
|
924
|
+ QHBoxLayout *deviceControlLayout = new QHBoxLayout;
|
|
925
|
+ deviceControlLayout->addWidget(startButton);
|
|
926
|
+ deviceControlLayout->addWidget(resetButton);
|
|
927
|
+ deviceControlLayout->addWidget(stopButton);
|
|
928
|
+ QFormLayout *indicatorLayout = new QFormLayout;
|
|
929
|
+ currentMeasurement->setReadOnly(true);
|
|
930
|
+ minimumMeasurement->setReadOnly(true);
|
|
931
|
+ maximumMeasurement->setReadOnly(true);
|
|
932
|
+ averageMeasurement->setReadOnly(true);
|
|
933
|
+ currentMapped->setReadOnly(true);
|
|
934
|
+ minimumMapped->setReadOnly(true);
|
|
935
|
+ maximumMapped->setReadOnly(true);
|
|
936
|
+ averageMapped->setReadOnly(true);
|
|
937
|
+ indicatorLayout->addRow(tr("Measured Values"), new QWidget);
|
|
938
|
+ indicatorLayout->addRow(tr("Current"), currentMeasurement);
|
|
939
|
+ indicatorLayout->addRow(tr("Minimum"), minimumMeasurement);
|
|
940
|
+ indicatorLayout->addRow(tr("Maximum"), maximumMeasurement);
|
|
941
|
+ indicatorLayout->addRow(tr("Mean"), averageMeasurement);
|
|
942
|
+ indicatorLayout->addRow(tr("Mapped Values"), new QWidget);
|
|
943
|
+ indicatorLayout->addRow(tr("Current Mapped"), currentMapped);
|
|
944
|
+ indicatorLayout->addRow(tr("Minimum Mapped"), minimumMapped);
|
|
945
|
+ indicatorLayout->addRow(tr("Maximum Mapped"), maximumMapped);
|
|
946
|
+ indicatorLayout->addRow(tr("Mean Mapped"), averageMapped);
|
|
947
|
+ calibrationTestLayout->addLayout(deviceControlLayout);
|
|
948
|
+ calibrationTestLayout->addLayout(indicatorLayout);
|
|
949
|
+ calibrationLayout->addLayout(calibrationControlsLayout);
|
|
950
|
+ calibrationLayout->addLayout(calibrationTestLayout);
|
|
951
|
+ layout->addLayout(calibrationLayout);
|
873
|
952
|
@<Get device configuration data for current node@>@;
|
874
|
953
|
for(int i = 0; i < configData.size(); i++)
|
875
|
954
|
{
|
|
@@ -960,26 +1039,31 @@ the |LinearCalibrator| used for calibration assistance.
|
960
|
1039
|
void DataqSdkChannelConfWidget::updateMeasuredLower(const QString &value)
|
961
|
1040
|
{
|
962
|
1041
|
updateAttribute("calibrationMeasuredLower", value);
|
|
1042
|
+ calibrator->setMeasuredLower(value.toDouble());
|
963
|
1043
|
}
|
964
|
1044
|
|
965
|
1045
|
void DataqSdkChannelConfWidget::updateMeasuredUpper(const QString &value)
|
966
|
1046
|
{
|
967
|
1047
|
updateAttribute("calibrationMeasuredUpper", value);
|
|
1048
|
+ calibrator->setMeasuredUpper(value.toDouble());
|
968
|
1049
|
}
|
969
|
1050
|
|
970
|
1051
|
void DataqSdkChannelConfWidget::updateMappedLower(const QString &value)
|
971
|
1052
|
{
|
972
|
1053
|
updateAttribute("calibrationMappedLower", value);
|
|
1054
|
+ calibrator->setMappedLower(value.toDouble());
|
973
|
1055
|
}
|
974
|
1056
|
|
975
|
1057
|
void DataqSdkChannelConfWidget::updateMappedUpper(const QString &value)
|
976
|
1058
|
{
|
977
|
1059
|
updateAttribute("calibrationMappedUpper", value);
|
|
1060
|
+ calibrator->setMappedUpper(value.toDouble());
|
978
|
1061
|
}
|
979
|
1062
|
|
980
|
1063
|
void DataqSdkChannelConfWidget::updateClosedInterval(bool closed)
|
981
|
1064
|
{
|
982
|
1065
|
updateAttribute("calibrationClosedInterval", closed ? "true" : "false");
|
|
1066
|
+ calibrator->setClosedRange(closed);
|
983
|
1067
|
}
|
984
|
1068
|
|
985
|
1069
|
void DataqSdkChannelConfWidget::updateSmoothingEnabled(bool enabled)
|
|
@@ -990,7 +1074,46 @@ void DataqSdkChannelConfWidget::updateSmoothingEnabled(bool enabled)
|
990
|
1074
|
void DataqSdkChannelConfWidget::updateSensitivity(const QString &value)
|
991
|
1075
|
{
|
992
|
1076
|
updateAttribute("calibrationSensitivity", value);
|
|
1077
|
+ calibrator->setSensitivity(value.toDouble());
|
|
1078
|
+}
|
|
1079
|
+
|
|
1080
|
+@ When calibrating a device, we must know certain information to open a
|
|
1081
|
+connection to the appropriate hardware and know which channel we are interested
|
|
1082
|
+in.
|
|
1083
|
+
|
|
1084
|
+@<DATAQ SDK device settings@>=
|
|
1085
|
+bool autoSelect;
|
|
1086
|
+QString deviceID;
|
|
1087
|
+int channelOfInterest;
|
|
1088
|
+
|
|
1089
|
+@ This information is accessed through the reference element associated with
|
|
1090
|
+the parent node of the current configuration and from the row number of the
|
|
1091
|
+current node.
|
|
1092
|
+
|
|
1093
|
+@<Find DATAQ SDK device settings from parent node@>=
|
|
1094
|
+QDomElement parentReference = model->referenceElement(model->data(index.parent(), Qt::UserRole).toString());
|
|
1095
|
+QDomNodeList deviceConfigData = parentReference.elementsByTagName("attribute");
|
|
1096
|
+QDomElement deviceNode;
|
|
1097
|
+QString configPort;
|
|
1098
|
+QString configAuto;
|
|
1099
|
+for(int i = 0; i < deviceConfigData.size(); i++)
|
|
1100
|
+{
|
|
1101
|
+ deviceNode = deviceConfigData.at(i).toElement();
|
|
1102
|
+ if(deviceNode.attribute("name") == "autoSelect")
|
|
1103
|
+ {
|
|
1104
|
+ autoSelect = (deviceNode.attribute("value") == "true");
|
|
1105
|
+ }
|
|
1106
|
+ else if(deviceNode.attribute("name") == "deviceNumber")
|
|
1107
|
+ {
|
|
1108
|
+ configAuto = deviceNode.attribute("value");
|
|
1109
|
+ }
|
|
1110
|
+ else if(deviceNode.attribute("name") == "port")
|
|
1111
|
+ {
|
|
1112
|
+ configPort = deviceNode.attribute("value");
|
|
1113
|
+ }
|
993
|
1114
|
}
|
|
1115
|
+deviceID = autoSelect ? configAuto : configPort;
|
|
1116
|
+channelOfInterest = index.row();
|
994
|
1117
|
|
995
|
1118
|
@ It must be possible to perform calibration operations with the hardware not
|
996
|
1119
|
connected. As such, the device should only be opened on request. Methods for
|
|
@@ -999,12 +1122,29 @@ opening and closing these connections to the hardware are provided.
|
999
|
1122
|
@<DataqSdkDeviceConfWidget implementation@>=
|
1000
|
1123
|
void DataqSdkChannelConfWidget::startCalibration()
|
1001
|
1124
|
{
|
1002
|
|
-
|
|
1125
|
+ startButton->setEnabled(false);
|
|
1126
|
+ stopButton->setEnabled(true);
|
|
1127
|
+ resetButton->setEnabled(true);
|
|
1128
|
+ calibrationDevice = new DataqSdkDevice(deviceID);
|
|
1129
|
+ Channel *channel;
|
|
1130
|
+ for(int i = 0; i <= channelOfInterest; i++)
|
|
1131
|
+ {
|
|
1132
|
+ channel = calibrationDevice->newChannel(Units::Unitless);
|
|
1133
|
+ }
|
|
1134
|
+ connect(channel, SIGNAL(newData(Measurement)), this, SLOT(updateInput(Measurement)));
|
|
1135
|
+ connect(channel, SIGNAL(newData(Measurement)), calibrator, SLOT(newMeasurement(Measurement)));
|
|
1136
|
+ connect(calibrator, SIGNAL(newData(Measurement)), this, SLOT(updateOutput(Measurement)));
|
|
1137
|
+ calibrationDevice->setClockRate(6.0 / (1.0 + channelOfInterest));
|
|
1138
|
+ calibrationDevice->start();
|
1003
|
1139
|
}
|
1004
|
1140
|
|
1005
|
1141
|
void DataqSdkChannelConfWidget::stopCalibration()
|
1006
|
1142
|
{
|
1007
|
|
-
|
|
1143
|
+ startButton->setEnabled(true);
|
|
1144
|
+ stopButton->setEnabled(false);
|
|
1145
|
+ resetButton->setEnabled(false);
|
|
1146
|
+ calibrationDevice->deleteLater();
|
|
1147
|
+ @<Reset DATAQ SDK channel calibration aggregates@>@;
|
1008
|
1148
|
}
|
1009
|
1149
|
|
1010
|
1150
|
@ When collecting calibration data it is useful to have a few types of
|
|
@@ -1018,7 +1158,51 @@ convenient testing in multiple parts of the range.
|
1018
|
1158
|
@<DataqSdkDeviceConfWidget implementation@>=
|
1019
|
1159
|
void DataqSdkChannelConfWidget::resetCalibration()
|
1020
|
1160
|
{
|
|
1161
|
+ @<Reset DATAQ SDK channel calibration aggregates@>@;
|
|
1162
|
+}
|
|
1163
|
+
|
|
1164
|
+@ When calibration is stopped or reset, aggregate statistics are set to
|
|
1165
|
+their initial values;
|
|
1166
|
+
|
|
1167
|
+@<Reset DATAQ SDK channel calibration aggregates@>=
|
|
1168
|
+rmCount = 0;
|
|
1169
|
+cmCount = 0;
|
|
1170
|
+rmin = std::numeric_limits<double>::max();
|
|
1171
|
+rmax = std::numeric_limits<double>::min();
|
|
1172
|
+rmean = 0;
|
|
1173
|
+cmin = std::numeric_limits<double>::max();
|
|
1174
|
+cmax = std::numeric_limits<double>::min();
|
|
1175
|
+cmean = 0;
|
1021
|
1176
|
|
|
1177
|
+@ Two methods are responsible for updating line edits with current and
|
|
1178
|
+aggregate data when calibrating a channel. One handles raw measurements from
|
|
1179
|
+the channel and the other handles output from the |LinearCalibrator|.
|
|
1180
|
+
|
|
1181
|
+@<DataqSdkDeviceConfWidget implementation@>=
|
|
1182
|
+void DataqSdkChannelConfWidget::updateInput(Measurement measure)
|
|
1183
|
+{
|
|
1184
|
+ double nv = measure.temperature();
|
|
1185
|
+ currentMeasurement->setText(QString("%1").arg(nv));
|
|
1186
|
+ rmin = qMin(nv, rmin);
|
|
1187
|
+ minimumMeasurement->setText(QString("%1").arg(rmin));
|
|
1188
|
+ rmax = qMax(nv, rmax);
|
|
1189
|
+ maximumMeasurement->setText(QString("%1").arg(rmax));
|
|
1190
|
+ rmean = ((rmean * rmCount) + nv) / (rmCount + 1);
|
|
1191
|
+ rmCount++;
|
|
1192
|
+ averageMeasurement->setText(QString("%1").arg(rmean));
|
|
1193
|
+}
|
|
1194
|
+
|
|
1195
|
+void DataqSdkChannelConfWidget::updateOutput(Measurement measure)
|
|
1196
|
+{
|
|
1197
|
+ double nv = measure.temperature();
|
|
1198
|
+ currentMapped->setText(QString("%1").arg(nv));
|
|
1199
|
+ cmin = qMin(nv, cmin);
|
|
1200
|
+ minimumMapped->setText(QString("%1").arg(cmin));
|
|
1201
|
+ cmax = qMax(nv, cmax);
|
|
1202
|
+ maximumMapped->setText(QString("%1").arg(cmax));
|
|
1203
|
+ cmean = ((cmean * cmCount) + nv) / (cmCount + 1);
|
|
1204
|
+ cmCount++;
|
|
1205
|
+ averageMapped->setText(QString("%1").arg(cmean));
|
1022
|
1206
|
}
|
1023
|
1207
|
|
1024
|
1208
|
@ Column name is handled as usual.
|