aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--host/docs/calibration.dox24
-rw-r--r--host/lib/include/uhdlib/usrp/common/apply_corrections.hpp47
-rw-r--r--host/lib/include/uhdlib/utils/paths.hpp2
-rw-r--r--host/lib/usrp/common/apply_corrections.cpp295
-rw-r--r--host/lib/utils/paths.cpp26
-rw-r--r--host/utils/usrp_cal_utils.hpp35
6 files changed, 229 insertions, 200 deletions
diff --git a/host/docs/calibration.dox b/host/docs/calibration.dox
index 4bf89a8bc..b9b82e5c7 100644
--- a/host/docs/calibration.dox
+++ b/host/docs/calibration.dox
@@ -8,7 +8,7 @@ UHD software comes with several self-calibration utilities for
minimizing IQ imbalance and DC offset. These utilities perform
calibration sweeps using transmit leakage into the receive path (special
equipment is not required). The results from a calibration are written
-to a CSV file in the user's home directory. UHD software will
+to a file in the user's home directory. UHD software will
automatically apply corrections at runtime when the user re-tunes the
daughterboard LO. Calibration results are specific to an individual RF
board.
@@ -34,6 +34,7 @@ utilities:
- SBX Series transceiver boards
- CBX Series transceiver boards
- UBX Series transceiver boards
+- USRP N320
\subsection calibration_self_utils Calibration Utilities
@@ -74,6 +75,20 @@ Calibration files can easily be moved from one machine to another by copying the
calibration file. The old calibration file will be renamed so it may be
recovered by the user.
+\subsection calibration_data_csv Converting UHD 3.x calibration data to UHD 4
+
+Older versions of UHD used a CSV-based format for storing calbration data for
+IQ imbalance and DC offset correction on some devices (e.g., X300, N200
+motherboards and WBX/SBX/CBX/UBX daughterboards).
+
+Going forward, all calibration data is stored as binary, to facilitate storing
+it on device's flash memory, among other reasons. Running the `uhd_cal_*`
+utilities will automatically generate the calibration data in the new format.
+
+To convert existing calbration data to the new format, use the convert_cal_data.py
+utility. By default, it will convert all existing data. Use `convert_cal_data.py --help`
+to get a full list of command line options.
+
\subsection ignore_cal_file Ignoring Calibration Files
@@ -82,15 +97,12 @@ adding "ignore-cal-file" to the arguments. With the UHD API, it can be done as
follows:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
- uhd::device_addr_t hint;
- hint["type"] = "usrp1";
- hint["ignore-cal-file"] = "";
- uhd::device_addrs_t dev_addrs = uhd::device::find(hint);
+ auto usrp = uhd::usrp::multi_usrp::make("type=x300,ignore-cal-file=1");
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Using tx_waveforms as an example, the user can apply this argument as follows:
- tx_waveforms --args="addr=192.168.10.2,ignore-cal-file" --freq=100e6 --rate=1e6
+ tx_waveforms --args="addr=192.168.10.2,ignore-cal-file=1" --freq=100e6 --rate=1e6
*/
// vim:ft=doxygen:
diff --git a/host/lib/include/uhdlib/usrp/common/apply_corrections.hpp b/host/lib/include/uhdlib/usrp/common/apply_corrections.hpp
index dffefffea..fb9aaa8f1 100644
--- a/host/lib/include/uhdlib/usrp/common/apply_corrections.hpp
+++ b/host/lib/include/uhdlib/usrp/common/apply_corrections.hpp
@@ -14,26 +14,67 @@
namespace uhd { namespace usrp {
+/*! Apply TX DC offset or IQ imbalance corrections (RFNoC version)
+ *
+ * \param sub_tree Property tree object
+ * \param db_serial Daughterboard serial
+ * \param tx_fe_corr_path This is the path relative to \p sub_tree where the
+ * coefficients are stored. The path should end in
+ * `iq_balance/value` or `dc_offset/value` and be a
+ * complex number.
+ * \param tx_lo_freq The current LO frequency. Used to look up coefficients in the cal
+ * data set.
+ */
void apply_tx_fe_corrections(property_tree::sptr sub_tree, // starts at mboards/x
const std::string& db_serial,
const fs_path tx_fe_corr_path,
const double tx_lo_freq // actual lo freq
);
+/*! Apply TX DC offset or IQ imbalance corrections (Gen-2 USRP version)
+ *
+ * \param sub_tree Property tree object. It's the motherboard subtree, i.e.,
+ * what comes after /mboards/X.
+ * \param slot Daughterboard slot ("A" or "B"), used to auto-detect the paths.
+ * \param tx_lo_freq The current LO frequency. Used to look up coefficients in the cal
+ * data set.
+ */
void apply_tx_fe_corrections(property_tree::sptr sub_tree, // starts at mboards/x
const std::string& slot, // name of dboard slot
const double tx_lo_freq // actual lo freq
);
+
+/*! Apply RX DC offset or IQ imbalance corrections (RFNoC version)
+ *
+ * \param sub_tree Property tree object
+ * \param db_serial Daughterboard serial
+ * \param tx_fe_corr_path This is the path relative to \p sub_tree where the
+ * coefficients are stored. The path should end in
+ * `iq_balance/value` or `dc_offset/value` and be a
+ * complex number.
+ * \param tx_lo_freq The current LO frequency. Used to look up coefficients in the cal
+ * data set.
+ */
void apply_rx_fe_corrections(property_tree::sptr sub_tree, // starts at mboards/x
- const std::string& slot, // name of dboard slot
+ const std::string& db_serial,
+ const fs_path rx_fe_corr_path,
const double rx_lo_freq // actual lo freq
);
+/*! Apply RX DC offset or IQ imbalance corrections (Gen-2 USRP version)
+ *
+ * \param sub_tree Property tree object. It's the motherboard subtree, i.e.,
+ * what comes after /mboards/X.
+ * \param slot Daughterboard slot ("A" or "B"), used to auto-detect the paths.
+ * \param rx_lo_freq The current LO frequency. Used to look up coefficients in the cal
+ * data set.
+ */
void apply_rx_fe_corrections(property_tree::sptr sub_tree, // starts at mboards/x
- const std::string& db_serial,
- const fs_path rx_fe_corr_path,
+ const std::string& slot, // name of dboard slot
const double rx_lo_freq // actual lo freq
);
+
+
}} // namespace uhd::usrp
#endif /* INCLUDED_LIBUHD_USRP_COMMON_APPLY_CORRECTIONS_HPP */
diff --git a/host/lib/include/uhdlib/utils/paths.hpp b/host/lib/include/uhdlib/utils/paths.hpp
index 7f0dc4046..7caac8a7d 100644
--- a/host/lib/include/uhdlib/utils/paths.hpp
+++ b/host/lib/include/uhdlib/utils/paths.hpp
@@ -18,6 +18,8 @@ namespace uhd {
*/
std::string path_expandvars(const std::string& path);
+std::string get_appdata_path(void);
+
} /* namespace uhd */
#endif /* INCLUDED_UHDLIB_UTILS_PATHS_HPP */
diff --git a/host/lib/usrp/common/apply_corrections.cpp b/host/lib/usrp/common/apply_corrections.cpp
index b75ab7d95..3cdf3d29f 100644
--- a/host/lib/usrp/common/apply_corrections.cpp
+++ b/host/lib/usrp/common/apply_corrections.cpp
@@ -5,237 +5,198 @@
// SPDX-License-Identifier: GPL-3.0-or-later
//
-#include <uhd/types/dict.hpp>
+#include <uhd/cal/container.hpp>
+#include <uhd/cal/database.hpp>
+#include <uhd/cal/iq_cal.hpp>
#include <uhd/usrp/dboard_eeprom.hpp>
#include <uhd/utils/csv.hpp>
#include <uhd/utils/log.hpp>
-#include <uhd/utils/paths.hpp>
#include <uhdlib/usrp/common/apply_corrections.hpp>
-#include <boost/filesystem.hpp>
-#include <boost/thread/mutex.hpp>
+#include <uhdlib/utils/paths.hpp>
+#include <unordered_map>
+#include <boost/filesystem.hpp> // For deprecated CSV reader only
#include <complex>
#include <cstdio>
#include <fstream>
+#include <mutex>
-namespace fs = boost::filesystem;
+using namespace uhd::usrp::cal;
-boost::mutex corrections_mutex;
-
-/***********************************************************************
- * Helper routines
- **********************************************************************/
-static double linear_interp(double x, double x0, double y0, double x1, double y1)
-{
- return y0 + (x - x0) * (y1 - y0) / (x1 - x0);
-}
+std::mutex corrections_mutex;
/***********************************************************************
* FE apply corrections implementation
**********************************************************************/
-struct fe_cal_t
-{
- double lo_freq;
- double iq_corr_real;
- double iq_corr_imag;
-};
-
-static bool fe_cal_comp(fe_cal_t a, fe_cal_t b)
-{
- return (a.lo_freq < b.lo_freq);
-}
+namespace {
-static uhd::dict<std::string, std::vector<fe_cal_t>> fe_cal_cache;
+// Cache the loaded data so we don't have to serialize on every tune
+std::unordered_map<std::string, iq_cal::sptr> fe_cal_cache;
-static bool is_same_freq(const double f1, const double f2)
+// Deprecated CSV file loader. Delete this function once we remove CSV support.
+// Then, also delete the uhd::csv module.
+bool load_legacy_fe_corrections(const std::string& cal_key,
+ const std::string& db_serial, const std::string& file_prefix)
{
- const double epsilon = 0.1;
- return ((f1 - epsilon) < f2 and (f1 + epsilon) > f2);
-}
+ namespace fs = boost::filesystem;
+ const std::string file_prefix_deprecated = file_prefix + "_cal_v0.2_";
+ // make the calibration file path
+ const fs::path cal_data_path = fs::path(uhd::get_appdata_path()) / ".uhd" / "cal"
+ / (file_prefix_deprecated + db_serial + ".csv");
+ UHD_LOG_TRACE(
+ "CAL", "Checking for deprecated CSV-based cal data at " << cal_data_path);
+ if (not fs::exists(cal_data_path)) {
+ return false;
+ }
-static std::complex<double> get_fe_correction(
- const std::string& key, const double lo_freq)
-{
- const std::vector<fe_cal_t>& datas = fe_cal_cache[key];
- if (datas.empty())
- throw uhd::runtime_error("empty calibration table " + key);
-
- // search for lo freq
- size_t lo_index = 0;
- size_t hi_index = datas.size() - 1;
- for (size_t i = 0; i < datas.size(); i++) {
- if (is_same_freq(datas[i].lo_freq, lo_freq)) {
- hi_index = i;
- lo_index = i;
- break;
+ // The serial/timestamp don't really matter, we never look them up once we
+ // generate the container here.
+ auto iq_cal_container = iq_cal::make(file_prefix, db_serial, 0);
+
+ // parse csv file
+ std::ifstream cal_data(cal_data_path.string().c_str());
+ const uhd::csv::rows_type rows = uhd::csv::to_rows(cal_data);
+ bool read_data = false, skip_next = false;
+ for (const uhd::csv::row_type& row : rows) {
+ if (not read_data and not row.empty() and row[0] == "DATA STARTS HERE") {
+ read_data = true;
+ skip_next = true;
+ continue;
}
- if (datas[i].lo_freq > lo_freq) {
- hi_index = i;
- break;
+ if (not read_data)
+ continue;
+ if (skip_next) {
+ skip_next = false;
+ continue;
}
- lo_index = i;
- }
- if (lo_index == 0)
- return std::complex<double>(
- datas[lo_index].iq_corr_real, datas[lo_index].iq_corr_imag);
- if (hi_index == lo_index)
- return std::complex<double>(
- datas[hi_index].iq_corr_real, datas[hi_index].iq_corr_imag);
-
- // interpolation time
- return std::complex<double>(linear_interp(lo_freq,
- datas[lo_index].lo_freq,
- datas[lo_index].iq_corr_real,
- datas[hi_index].lo_freq,
- datas[hi_index].iq_corr_real),
- linear_interp(lo_freq,
- datas[lo_index].lo_freq,
- datas[lo_index].iq_corr_imag,
- datas[hi_index].lo_freq,
- datas[hi_index].iq_corr_imag));
+ iq_cal_container->set_cal_coeff(
+ std::stod(row[0]), {std::stod(row[1]), std::stod(row[2])});
+ }
+ fe_cal_cache.insert({cal_key, iq_cal_container});
+ UHD_LOGGER_INFO("CAL") << "Calibration data loaded: " << cal_data_path.string();
+ return true;
}
-static void apply_fe_corrections(uhd::property_tree::sptr sub_tree,
+void apply_fe_corrections(uhd::property_tree::sptr sub_tree,
const std::string& db_serial,
const uhd::fs_path& fe_path,
const std::string& file_prefix,
const double lo_freq)
{
- // make the calibration file path
- const fs::path cal_data_path = fs::path(uhd::get_app_path()) / ".uhd" / "cal"
- / (file_prefix + db_serial + ".csv");
- if (not fs::exists(cal_data_path))
- return;
-
- // parse csv file or get from cache
- if (not fe_cal_cache.has_key(cal_data_path.string())) {
- std::ifstream cal_data(cal_data_path.string().c_str());
- const uhd::csv::rows_type rows = uhd::csv::to_rows(cal_data);
-
- bool read_data = false, skip_next = false;
- ;
- std::vector<fe_cal_t> datas;
- for (const uhd::csv::row_type& row : rows) {
- if (not read_data and not row.empty() and row[0] == "DATA STARTS HERE") {
- read_data = true;
- skip_next = true;
- continue;
+ const auto cal_key = file_prefix + ":" + db_serial;
+ // Check if we need to load cal data
+ if (!fe_cal_cache.count(cal_key)) {
+ if (database::has_cal_data(file_prefix, db_serial)) {
+ try {
+ const auto cal_data = database::read_cal_data(file_prefix, db_serial);
+ fe_cal_cache.insert({cal_key, container::make<iq_cal>(cal_data)});
+ UHD_LOG_DEBUG("CAL",
+ "Loaded calibration data for " << file_prefix
+ << " serial=" << db_serial);
+ } catch (const uhd::exception& ex) {
+ UHD_LOG_WARNING("CAL",
+ "Error occurred reading cal data: `" << ex.what()
+ << "'. Skipping future loads.");
+ fe_cal_cache.insert({cal_key, nullptr});
}
- if (not read_data)
- continue;
- if (skip_next) {
- skip_next = false;
- continue;
- }
- fe_cal_t data;
- std::sscanf(row[0].c_str(), "%lf", &data.lo_freq);
- std::sscanf(row[1].c_str(), "%lf", &data.iq_corr_real);
- std::sscanf(row[2].c_str(), "%lf", &data.iq_corr_imag);
- datas.push_back(data);
+ // Delete the following else clause once we remove CSV support
+ } else if (load_legacy_fe_corrections(cal_key, db_serial, file_prefix)) {
+ UHD_LOG_WARNING("CAL",
+ "Found deprecated (CSV-based) cal data format. This feature will go away "
+ "in the future, please convert your calibration data to the new binary "
+ "format, or re-run your self-cal routines. For more information, see "
+ "https://files.ettus.com/manual/page_calibration.html");
+ } else {
+ // If there is no cal data, store a nullptr so we can skip the check
+ // next time.
+ fe_cal_cache.insert({cal_key, nullptr});
+ UHD_LOG_TRACE("CAL",
+ "No calibration data found for " << file_prefix
+ << " serial=" << db_serial);
}
- std::sort(datas.begin(), datas.end(), fe_cal_comp);
- fe_cal_cache[cal_data_path.string()] = datas;
- UHD_LOGGER_INFO("CAL") << "Calibration data loaded: " << cal_data_path.string();
}
+ // Check if valid data even exists
+ if (fe_cal_cache.at(cal_key) == nullptr) {
+ return;
+ }
+
+ // OK we have cal data: Now apply it
sub_tree->access<std::complex<double>>(fe_path).set(
- get_fe_correction(cal_data_path.string(), lo_freq));
+ fe_cal_cache.at(cal_key)->get_cal_coeff(lo_freq));
}
-/***********************************************************************
- * Wrapper routines with nice try/catch + print
- **********************************************************************/
-void uhd::usrp::apply_tx_fe_corrections( // overloading to work according to rfnoc tree
- // struct
- property_tree::sptr sub_tree, // starts at mboards/x
+} // namespace
+
+/******************************************************************************
+ * Wrapper routines with nice try/catch + print, RFNoC device version
+ *****************************************************************************/
+void uhd::usrp::apply_tx_fe_corrections(property_tree::sptr sub_tree,
const std::string& db_serial,
const uhd::fs_path tx_fe_corr_path,
- const double lo_freq // actual lo freq
-)
+ const double lo_freq)
{
- boost::mutex::scoped_lock l(corrections_mutex);
+ std::lock_guard<std::mutex> l(corrections_mutex);
try {
- apply_fe_corrections(sub_tree,
- db_serial,
- tx_fe_corr_path + "/iq_balance/value",
- "tx_iq_cal_v0.2_",
- lo_freq);
- apply_fe_corrections(sub_tree,
- db_serial,
- tx_fe_corr_path + "/dc_offset/value",
- "tx_dc_cal_v0.2_",
- lo_freq);
+ apply_fe_corrections(
+ sub_tree, db_serial, tx_fe_corr_path + "/iq_balance/value", "tx_iq", lo_freq);
} catch (const std::exception& e) {
UHD_LOGGER_ERROR("CAL") << "Failure in apply_tx_fe_corrections: " << e.what();
}
-}
-
-void uhd::usrp::apply_tx_fe_corrections(
- property_tree::sptr sub_tree, // starts at mboards/x
- const std::string& slot, // name of dboard slot
- const double lo_freq // actual lo freq
-)
-{
- boost::mutex::scoped_lock l(corrections_mutex);
-
- // extract eeprom serial
- const uhd::fs_path db_path = "dboards/" + slot + "/tx_eeprom";
- const std::string db_serial =
- sub_tree->access<uhd::usrp::dboard_eeprom_t>(db_path).get().serial;
try {
- apply_fe_corrections(sub_tree,
- db_serial,
- "tx_frontends/" + slot + "/iq_balance/value",
- "tx_iq_cal_v0.2_",
- lo_freq);
- apply_fe_corrections(sub_tree,
- db_serial,
- "tx_frontends/" + slot + "/dc_offset/value",
- "tx_dc_cal_v0.2_",
- lo_freq);
+ apply_fe_corrections(
+ sub_tree, db_serial, tx_fe_corr_path + "/dc_offset/value", "tx_dc", lo_freq);
} catch (const std::exception& e) {
UHD_LOGGER_ERROR("CAL") << "Failure in apply_tx_fe_corrections: " << e.what();
}
}
-void uhd::usrp::apply_rx_fe_corrections( // overloading to work according to rfnoc tree
- // struct
- property_tree::sptr sub_tree, // starts at mboards/x
+void uhd::usrp::apply_rx_fe_corrections(property_tree::sptr sub_tree,
const std::string& db_serial,
const uhd::fs_path rx_fe_corr_path,
- const double lo_freq // actual lo freq
-)
+ const double lo_freq)
{
- boost::mutex::scoped_lock l(corrections_mutex);
+ std::lock_guard<std::mutex> l(corrections_mutex);
try {
- apply_fe_corrections(sub_tree,
- db_serial,
- rx_fe_corr_path + "/iq_balance/value",
- "rx_iq_cal_v0.2_",
- lo_freq);
+ apply_fe_corrections(
+ sub_tree, db_serial, rx_fe_corr_path + "/iq_balance/value", "rx_iq", lo_freq);
} catch (const std::exception& e) {
UHD_LOGGER_ERROR("CAL") << "Failure in apply_tx_fe_corrections: " << e.what();
}
}
+/******************************************************************************
+ * Gen-2 versions
+ *****************************************************************************/
+void uhd::usrp::apply_tx_fe_corrections(
+ property_tree::sptr sub_tree, // starts at mboards/x
+ const std::string& slot, // name of dboard slot
+ const double lo_freq // actual lo freq
+)
+{
+ std::lock_guard<std::mutex> l(corrections_mutex);
+
+ // extract eeprom serial
+ const uhd::fs_path db_path = "dboards/" + slot + "/tx_eeprom";
+ const std::string db_serial =
+ sub_tree->access<uhd::usrp::dboard_eeprom_t>(db_path).get().serial;
+ const uhd::fs_path corr_path("tx_frontends/" + slot);
+
+ apply_tx_fe_corrections(sub_tree, db_serial, corr_path, lo_freq);
+}
+
void uhd::usrp::apply_rx_fe_corrections(
property_tree::sptr sub_tree, // starts at mboards/x
const std::string& slot, // name of dboard slot
const double lo_freq // actual lo freq
)
{
- boost::mutex::scoped_lock l(corrections_mutex);
+ std::lock_guard<std::mutex> l(corrections_mutex);
const uhd::fs_path db_path = "dboards/" + slot + "/rx_eeprom";
const std::string db_serial =
sub_tree->access<uhd::usrp::dboard_eeprom_t>(db_path).get().serial;
- try {
- apply_fe_corrections(sub_tree,
- db_serial,
- "rx_frontends/" + slot + "/iq_balance/value",
- "rx_iq_cal_v0.2_",
- lo_freq);
- } catch (const std::exception& e) {
- UHD_LOGGER_ERROR("CAL") << "Failure in apply_rx_fe_corrections: " << e.what();
- }
+ const uhd::fs_path corr_path("rx_frontends/" + slot);
+
+ apply_rx_fe_corrections(sub_tree, db_serial, corr_path, lo_freq);
}
diff --git a/host/lib/utils/paths.cpp b/host/lib/utils/paths.cpp
index ccf52f257..3ecd5fe38 100644
--- a/host/lib/utils/paths.cpp
+++ b/host/lib/utils/paths.cpp
@@ -8,6 +8,7 @@
#include <uhd/config.hpp>
#include <uhd/exception.hpp>
#include <uhd/utils/paths.hpp>
+#include <uhd/utils/log.hpp>
#include <uhdlib/utils/paths.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/version.hpp>
@@ -189,6 +190,31 @@ std::string uhd::get_app_path(void)
return uhd::get_tmp_path();
}
+// Only used for deprecated CSV file loader. Delete this once CSV support is
+// removed.
+std::string uhd::get_appdata_path(void)
+{
+ const std::string uhdcalib_path = get_env_var("UHD_CONFIG_DIR");
+ if (not uhdcalib_path.empty()) {
+ UHD_LOG_WARNING("UHD",
+ "The environment variable UHD_CONFIG_DIR is deprecated. Refer to "
+ "https://files.ettus.com/manual/page_calibration.html for how to store "
+ "calibration data.");
+ return uhdcalib_path;
+ }
+
+ const std::string appdata_path = get_env_var("APPDATA");
+ if (not appdata_path.empty())
+ return appdata_path;
+
+ const std::string home_path = get_env_var("HOME");
+ if (not home_path.empty())
+ return home_path;
+
+ return uhd::get_tmp_path();
+}
+
+
#if BOOST_VERSION >= 106100
std::string uhd::get_pkg_path(void)
{
diff --git a/host/utils/usrp_cal_utils.hpp b/host/utils/usrp_cal_utils.hpp
index 61dd0fbdd..d43df7a1b 100644
--- a/host/utils/usrp_cal_utils.hpp
+++ b/host/utils/usrp_cal_utils.hpp
@@ -5,6 +5,8 @@
// SPDX-License-Identifier: GPL-3.0-or-later
//
+#include <uhd/cal/database.hpp>
+#include <uhd/cal/iq_cal.hpp>
#include <uhd/property_tree.hpp>
#include <uhd/usrp/dboard_eeprom.hpp>
#include <uhd/usrp/multi_usrp.hpp>
@@ -181,33 +183,18 @@ static void store_results(const std::vector<result_t>& results,
const std::string& what, // Type of test, e.g. "iq",
const std::string& serial)
{
- // make the calibration file path
- fs::path cal_data_path = fs::path(uhd::get_app_path()) / ".uhd";
- fs::create_directory(cal_data_path);
- cal_data_path = cal_data_path / "cal";
- fs::create_directory(cal_data_path);
- cal_data_path =
- cal_data_path / str(boost::format("%s_%s_cal_v0.2_%s.csv") % xx % what % serial);
- if (fs::exists(cal_data_path))
- fs::rename(cal_data_path,
- cal_data_path.string() + str(boost::format(".%d") % time(NULL)));
-
- // fill the calibration file
- std::ofstream cal_data(cal_data_path.string().c_str());
- cal_data << boost::format("name, %s Frontend Calibration\n") % XX;
- cal_data << boost::format("serial, %s\n") % serial;
- cal_data << boost::format("timestamp, %d\n") % time(NULL);
- cal_data << boost::format("version, 0, 1\n");
- cal_data << boost::format("DATA STARTS HERE\n");
- cal_data << "lo_frequency, correction_real, correction_imag, measured, delta\n";
-
+ using namespace uhd::usrp::cal;
+ // Note: We could also load existing data and update it.
+ auto cal_data = iq_cal::make(XX + " Frontend Calibration", serial, time(NULL));
for (size_t i = 0; i < results.size(); i++) {
- cal_data << results[i].freq << ", " << results[i].real_corr << ", "
- << results[i].imag_corr << ", " << results[i].best << ", "
- << results[i].delta << "\n";
+ cal_data->set_cal_coeff(results[i].freq,
+ {results[i].real_corr, results[i].imag_corr},
+ results[i].best,
+ results[i].delta);
}
- std::cout << "wrote cal data to " << cal_data_path << std::endl;
+ const std::string cal_key = xx + "_" + what;
+ database::write_cal_data(cal_key, serial, cal_data->serialize());
}
/***********************************************************************