diff options
author | Martin Braun <martin.braun@ettus.com> | 2020-05-15 15:25:21 -0700 |
---|---|---|
committer | Aaron Rossetto <aaron.rossetto@ni.com> | 2020-05-19 13:25:20 -0500 |
commit | a847aea736d5f20387b7a658abfb0bf360750351 (patch) | |
tree | 48ae75359fb462ebc801833a04bbb26cb3deb4e4 /host/lib | |
parent | 2d7676e8cf2cc4fb59e59185864c8804ca77e15b (diff) | |
download | uhd-a847aea736d5f20387b7a658abfb0bf360750351.tar.gz uhd-a847aea736d5f20387b7a658abfb0bf360750351.tar.bz2 uhd-a847aea736d5f20387b7a658abfb0bf360750351.zip |
lib: pwr_cal: Fix power indexing
The pwr_cal::get_gain() method previously held the incorrect assumption
that power values per frequency would be equidistant, i.e., be at the
same indices as the gain values. Due to the frequency-dependent nature
of the hardware, this is not a valid assumption (if that were the case,
frequency-dependent calibration would be unnecessary).
This changes get_gain() to not rely on that assumption. Note that it
requires doing some more rounding: The bilinear interpolation method
uses requires coordinates to be on a rectangular grid. This snaps the
power values onto a single coordinate.
Diffstat (limited to 'host/lib')
-rw-r--r-- | host/lib/cal/pwr_cal.cpp | 44 |
1 files changed, 28 insertions, 16 deletions
diff --git a/host/lib/cal/pwr_cal.cpp b/host/lib/cal/pwr_cal.cpp index 3ff199598..82af208df 100644 --- a/host/lib/cal/pwr_cal.cpp +++ b/host/lib/cal/pwr_cal.cpp @@ -178,32 +178,44 @@ public: const auto f_iters = get_bounding_iterators(table, freqi); const uint64_t f1i = f_iters.first->first; const uint64_t f2i = f_iters.second->first; - // Frequency is out of bounds if (f1i == f2i) { + // Frequency is out of bounds return at_lin_interp(table.at(f1i).p2g, power_coerced); } - const double f1 = static_cast<double>(f1i); - const double f2 = static_cast<double>(f2i); - const auto pwr_iters = get_bounding_iterators(table.at(f1).p2g, power_coerced); - const double pwr1 = pwr_iters.first->first; - const double pwr2 = pwr_iters.second->first; + + // NOTE: bilinear_interp() does not interpolate on an arbitrary tetragon, + // but requires the coordinates to be on a rectangular grid. Due to the + // frequency-dependent nature of power calibration, it is unlikely that + // the bounding power values for f1 and f2 (respectively) are identical. + // We therefore not only interpolate the final gain values, but we also + // nearest-neighbor-interpolate the grid coordinates for the power. + // This snap-to-grid adds another error, which can be counteracted by + // good choice of frequency and gain points on which to sample. + const auto f1pwr_iters = get_bounding_iterators(table.at(f1i).p2g, power_coerced); + const double f1pwr1 = f1pwr_iters.first->first; + const double f1pwr2 = f1pwr_iters.second->first; + const auto f2pwr_iters = get_bounding_iterators(table.at(f2i).p2g, power_coerced); + const double f2pwr1 = f2pwr_iters.first->first; + const double f2pwr2 = f2pwr_iters.second->first; + const double f1 = static_cast<double>(f1i); + const double f2 = static_cast<double>(f2i); + const double pwr1 = linear_interp(freq, f1, f1pwr1, f2, f2pwr1); + const double pwr2 = linear_interp(freq, f1, f1pwr2, f2, f2pwr2); // Power is out of bounds (this shouldn't happen after coercing, but this // is just another good sanity check on our data) if (pwr1 == pwr2) { return linear_interp(freq, f1, - table.at(f1i).p2g.at(pwr1), + at_nearest(table.at(f1i).p2g, pwr1), f2, - table.at(f2i).p2g.at(pwr1)); + at_nearest(table.at(f2i).p2g, pwr2)); } - - // Both gain and freq are within bounds: Bi-Linear interpolation - // Find power values - const auto gain11 = table.at(f1i).p2g.at(pwr1); - const auto gain12 = table.at(f1i).p2g.at(pwr2); - const auto gain21 = table.at(f2i).p2g.at(pwr1); - const auto gain22 = table.at(f2i).p2g.at(pwr2); - + // Both gain and freq are within bounds => Bi-Linear interpolation + // Find gain values: + const auto gain11 = table.at(f1i).p2g.at(f1pwr1); + const auto gain12 = table.at(f1i).p2g.at(f1pwr2); + const auto gain21 = table.at(f2i).p2g.at(f2pwr1); + const auto gain22 = table.at(f2i).p2g.at(f2pwr2); return bilinear_interp( freq, power_coerced, f1, pwr1, f2, pwr2, gain11, gain12, gain21, gain22); } |