Skip to content
Snippets Groups Projects
Commit cb41d693 authored by Daniel Joseph Antrim's avatar Daniel Joseph Antrim
Browse files

Merge remote-tracking branch 'origin/dantrim_add_daq970a_meter' into dantrim_ads1015_and_daq970a

parents b3ca37de 8586f3bc
No related tags found
No related merge requests found
......@@ -171,8 +171,26 @@ void KeysightDAQ970A::configCAP(std::string channelListString) {
send("CONF:CAP AUTO," + channelListString);
}
bool KeysightDAQ970A::channelsAreIncreasingOrder(
const std::vector<unsigned>& channels) {
// c.f.
// https://stackoverflow.com/questions/43219003/c-is-there-stl-algorithm-to-check-if-the-range-is-strictly-sorted
auto iter = std::adjacent_find(channels.begin(), channels.end(),
std::greater_equal<unsigned>());
return iter == channels.end();
}
void KeysightDAQ970A::validateChannels(std::vector<unsigned> channels,
KeysightDAQ970A::Function func) {
// enforce that channels are monotonically increasing since this
// is the order that the hardware returns the measurements in
if (!channelsAreIncreasingOrder(channels)) {
throw std::runtime_error(
"KeysightDAQ970A::measure Provided channels must be given in "
"monotonically increasing order");
}
// check measurement type specific things
switch (func) {
case KeysightDAQ970A::Function::VoltageDC:
case KeysightDAQ970A::Function::Resistance:
......@@ -346,6 +364,8 @@ std::vector<double> KeysightDAQ970A::measure(std::vector<unsigned> channels,
case Statistic::Minimum:
m_min_last = results;
break;
default:
break;
}
} catch (std::exception& e) {
logger(logERROR) << __PRETTY_FUNCTION__ << " Exception caught during "
......
......
......@@ -8,6 +8,92 @@
#include "IMeter.h"
class ICom;
// clang-format off
/** \brief Implementation for benchtop Keysight DAQ970A, with DAQM901A modules
*
* The `KeysightDAQ970A` `IMeter` implementation adds support for the Keysight DAQ970A
* benchtop DAQ with DAQM901A general purpose plug-in multiplexer modules.
* General information about the Keysight DAQ970A can be found [here]
* (https://www.keysight.com/us/en/assets/7018-06259/technical-overviews/5992-3168.pdf),
* and specific programming information can be found [here]
* (https://www.keysight.com/us/en/assets/9018-04756/programming-guides/9018-04756.pdf).
*
* Each DAQM901A multiplexer module offers 20 channels capable of measuring
* AC/DC voltage, resistance, and capacitance. There are an additional two channels
* capable of measuring AC/DC currents (channels 21 and 22).
* The Keysight DAQ970A has 3 plug-in ports: port 100, port 200, and port 300.
* DAQM901A modules plugged into port 100 have channel numbers 101-122.
* DAQM901A modules plugged into port 200 have channel numbers 201-222.
* DAQM901A modules plugged into port 300 have channel numbers 301-322.
*
* Support for single measurements is provided by following the standard `IMeter`
* use, offering implementation for `measureDCV`, `measureDCI`, `measureRES`,
* and `measureCAP`. An example for measuring DC voltages is as follows:
*
* std::shared_ptr<KeysightDAQ970A> meter = ...; // get instance of KeysightDAQ970A
*
* // read a single channel
* unsigned channel{101};
* double value = meter->measureDCV(channel);
*
* // configure the Keysight DAQ970A to measure from multiple channels at once
* std::vector<unsigned> channels{101, 102, 103, 104};
* std::vector<double> values = meter->measureDCV(channels);
*
* When reading from multiple channels, as in the above, the input channels list
* should be monotonically increasing since the Keysight DAQ970A hardware
* scans through channels in this order and orders the returned data in this order,
* regardless of the order of channels provided to it.
*
* Support for measurement of several sample statistics is offered: average,
* standard deviation, maximum, minimum, and peak-to-peak. Measurement
* of sample statistics is supported by enabling the statistics measurement
* and configuring the Keysight DAQ970A trigger count to be greater than 1 (the
* default trigger count). This is done as follows:
*
* std::shared_ptr<KeysightDAQ970A> meter = ...; // get instance of KeysightDAQ970A
* meter->setDoStat(true);
* meter->setTrigCount(10); // compute sample statistics across 10 measurements per channel
*
* // compute sample statistics across a single channel
* unsigned channel{101};
* double average_val = meter->measureDCV(channel).at(0);
* double std_dev_val = meter->getStdDeviation().at(0);
* double min_val = meter->getMinimum().at(0);
* double max_val = meter->getMaximum().at(0);
*
* // compute the sample statistics across multiple channels
* std::vector<unsigned> channels{101,102,103,104};
* std::vector<double> average_values = meter->measureDCV(channels);
* std::vector<double> std_dev_values = meter->getStdDeviation();
* std::vector<double> min_values = meter->getMinimum();
* std::vector<double> max_values = meter->getMaximum();
*
* As seen in the above snippet, when the sample statistics computation have been
* enabled (via `KeysightDAQ970A::setDoStat(true)`), the methods `measureDCV`,
* `measureDCI`, `measureRES`, and `measureCAP` will return the computed
* averages. The other sample statistics computed from the call to `measureX`,
* are available via subsequent calls to `KeysightDAQ970A::getStdDeviation()`,
* `KeysightDAQ970A::getMaximum()`, and `KeysightDAQ970A::getMinimum()`.
* These `get` methods for the sample statistics always hold the values from the
* most recent call to `measureX`.
* Also note that the sample statistic `get` methods (e.g. `KeysightDAQ970A::getStdDeviation()`)
* always return a `std::vector<double>` even when the corresponding
* measurement was only done across a single channel (in which case, the size
* of the `std::vector` will be 1).
*
* The sample statistics computation (enabled via `KeysightDAQ970A::setDoStat(true)`)
* are computed within each channel, not across channels.
* That is, if you configure for 10 triggers and measure channel 101 and 102
* and channel 101 always measures a value of 0 and channel 102 always measures a value of
* 5, the `std::vector<double>` returned by,
* std::vector<double> average_values = meter->measureDCV({101, 102});
* will have a value of 0 at element 0 and a value of 5 at element 1
* (likewise for the other sample statistics).
*
*/
// clang-format on
class KeysightDAQ970A : public IMeter {
public:
KeysightDAQ970A(const std::string& name);
......@@ -45,6 +131,7 @@ class KeysightDAQ970A : public IMeter {
PeakToPeak
};
// clang-format off
//! \brief Set the number of triggers for statistics measurementts
/**
When performing a statistics measurement (enabled by calling
......@@ -56,8 +143,10 @@ class KeysightDAQ970A : public IMeter {
\param trig_count The number of triggers to acquire from each channel
when a statistics measurement is performed
*/
// clang-format on
void setTrigCount(unsigned trig_count = 1) { m_trig_count = trig_count; }
// clang-format off
//! \brief Set whether or not to perform a statistics measurement
/**
* Enables or disables the measurement of statistics when calling any of
......@@ -103,30 +192,28 @@ class KeysightDAQ970A : public IMeter {
* set to measure all statistics as if `KeysightDAQ970A::setMeasurementStat`
* has been called with `Statistic::All`.
*
* Note that if `KeysightDAQ970A::setMeasurementStat` is called and
* disables the measurement of the statistics information, then only a
* single shot measurement is performed for each of the configured channels.
* That is, the trigger count set by `setTrigCount` is ignored unless the
* The trigger count set by `setTrigCount` is ignored unless the
* statistics measurements are enabled.
*
* \param do_stat Whether or not to enable the statistics measurements.
*/
// clang-format on
void setDoStat(bool do_stat) { m_do_stat = do_stat; }
// clang-format off
//! \brief Set which measurement statistic to measure
/*
Specify a specific set of statistics to measure when computing the
measurement
* statistics (enabled with `KeysightDAQ970A::setDoStat(true)`.
* Specify a specific set of statistics to measure when computing the
* measurement statistics (enabled with `KeysightDAQ970A::setDoStat(true)`.
*
* By default, an instance of `KeysightDAQ970A` will compute all statistics
* possible (average, standard deviation, maximum, and minimum), but this
method
* can be used to specify a single statistic to be computed (unless one
passes
* possible (average, standard deviation, maximum, and minimum), but this method
* can be used to specify a single statistic to be computed (unless one passes
* `Statistic::All`, which will revert back to the default behavior).
*
* \param stat A value of the `KeysightDAQ970A::Statistic` enum.
*/
// clang-format on
void setMeasurementStat(Statistic stat) { m_measurement_stat = stat; }
//! \brief Get the average value statistic for all the previous channel
......@@ -182,6 +269,7 @@ class KeysightDAQ970A : public IMeter {
// helpers
std::vector<double> samplesFromResponse(const std::string& response,
unsigned n_expected);
bool channelsAreIncreasingOrder(const std::vector<unsigned>& channels);
std::string generateChannelListString(std::vector<unsigned> channels);
void validateChannels(std::vector<unsigned> channels, Function func);
static const std::vector<unsigned> validChannelsDCI;
......
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment