Skip to content

Commit 2d4dc09

Browse files
author
Dan Smith
committed
cache the magnitudes w/o an AmplitudeTable
1 parent ebc4a8a commit 2d4dc09

1 file changed

Lines changed: 43 additions & 23 deletions

File tree

six/modules/c++/six.sicd/source/ComplexToAMP8IPHS8I.cpp

Lines changed: 43 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -44,33 +44,52 @@ inline double GetPhase(const std::complex<double>& v)
4444
return phase;
4545
}
4646

47-
ComplexToAMP8IPHS8I::ComplexToAMP8IPHS8I(const six::AmplitudeTable *pAmplitudeTable)
47+
static std::array<long double, UINT8_MAX + 1> make_magnitudes(const six::AmplitudeTable* pAmplitudeTable)
4848
{
49-
// Be careful with indexing so that we don't wrap-around in the loops.
50-
for (uint16_t i = 0; i <= UINT8_MAX; i++)
49+
std::array<long double, UINT8_MAX + 1> retval{};
50+
for (uint16_t i = 0; i <= UINT8_MAX; i++) // Be careful with indexing so that we don't wrap-around in the loops.
5151
{
5252
// AmpPhase -> Complex
5353
ImageData::AMP8I_PHS8I_t v;
54-
v.first = gsl::narrow<uint8_t>(i);
55-
v.second = v.first;
54+
v.first = v.second = gsl::narrow<uint8_t>(i);
5655
const auto complex = Utilities::from_AMP8I_PHS8I(v.first, v.second, pAmplitudeTable);
57-
magnitudes[i] = {
58-
std::abs(complex)
59-
};
56+
retval[i] = std::abs(complex);
57+
}
58+
return retval;
59+
}
60+
61+
static std::array<long double, UINT8_MAX + 1> get_magnitudes(const six::AmplitudeTable* pAmplitudeTable)
62+
{
63+
std::array<long double, UINT8_MAX + 1> retval{};
64+
if (pAmplitudeTable == nullptr)
65+
{
66+
static auto magnitudes = make_magnitudes(nullptr); // OK to cache, won't change
67+
retval = magnitudes;
68+
}
69+
else
70+
{
71+
retval = make_magnitudes(pAmplitudeTable);
6072
}
6173

6274
// I don't know if we can guarantee that the amplitude table is non-decreasing.
6375
// Check to verify property at runtime.
64-
if (!std::is_sorted(magnitudes.begin(), magnitudes.end())) {
76+
if (!std::is_sorted(retval.begin(), retval.end()))
77+
{
6578
throw std::runtime_error("magnitudes must be sorted");
6679
}
80+
return retval;
81+
}
82+
83+
ComplexToAMP8IPHS8I::ComplexToAMP8IPHS8I(const six::AmplitudeTable *pAmplitudeTable)
84+
{
85+
magnitudes = get_magnitudes(pAmplitudeTable);
6786

6887
const auto p0 = GetPhase(Utilities::from_AMP8I_PHS8I(1, 0, pAmplitudeTable));
6988
const auto p1 = GetPhase(Utilities::from_AMP8I_PHS8I(1, 1, pAmplitudeTable));
7089
assert(p0 == 0);
7190
assert(p1 > p0);
7291
phase_delta = p1 - p0;
73-
for(size_t i = 0; i <= UINT8_MAX; i++)
92+
for(size_t i = 0; i <= UINT8_MAX; i++) // Be careful with indexing so that we don't wrap-around in the loops.
7493
{
7594
long double y, x;
7695
math::SinCos(p0 + gsl::narrow_cast<long double>(i) * phase_delta, y, x);
@@ -91,33 +110,34 @@ ComplexToAMP8IPHS8I::ComplexToAMP8IPHS8I() : ComplexToAMP8IPHS8I(nullptr /*pAmpl
91110
template<typename TIter>
92111
static uint8_t nearest(const TIter& begin, const TIter& end, long double value)
93112
{
94-
auto it = std::lower_bound(begin, end, value);
113+
const auto it = std::lower_bound(begin, end, value);
95114
if(it == begin) return 0;
96-
auto prev_it = std::prev(it);
97-
auto nearest = (it == end || value - *prev_it <= *it - value) ? prev_it : it;
98-
assert(std::distance(begin, nearest) <= std::numeric_limits<uint8_t>::max());
99-
return static_cast<uint8_t>(std::distance(begin, nearest));
115+
116+
const auto prev_it = std::prev(it);
117+
const auto nearest = (it == end || value - *prev_it <= *it - value) ? prev_it : it;
118+
const auto distance = std::distance(begin, nearest);
119+
assert(distance <= std::numeric_limits<uint8_t>::max());
120+
return gsl::narrow<uint8_t>(distance);
100121
}
101122

102123
ImageData::AMP8I_PHS8I_t ComplexToAMP8IPHS8I::nearest_neighbor(const std::complex<float> &v) const
103124
{
104-
ImageData::AMP8I_PHS8I_t ans;
125+
ImageData::AMP8I_PHS8I_t retval;
105126

106127
// Phase is determined via arithmetic because it's equally spaced.
107128
// There's an intentional conversion to zero when we cast 256 -> uint8. That wrap around
108129
// handles cases that are close to 2PI.
109-
ans.second = gsl::narrow_cast<uint8_t>(std::round(GetPhase(v) / phase_delta));
130+
retval.second = gsl::narrow_cast<uint8_t>(std::round(GetPhase(v) / phase_delta));
110131

111132
// We have to do a 1D nearest neighbor search for magnitude.
112133
// But it's not the magnitude of the input complex value - it's the projection of
113134
// the complex value onto the ray of candidate magnitudes at the selected phase.
114-
// I.e. dot product.
115-
auto&& direction = phase_directions[ans.second];
116-
const auto projection = direction.real() * gsl::narrow_cast<long double>(v.real()) + direction.imag() * gsl::narrow_cast<long double>(v.imag());
135+
// i.e. dot product.
136+
auto&& phase_direction = phase_directions[retval.second];
137+
const auto projection = phase_direction.real() * v.real() + phase_direction.imag() * v.imag();
117138
//assert(std::abs(projection - std::abs(v)) < 1e-5); // TODO ???
118-
ans.first = nearest(magnitudes.begin(), magnitudes.end(), projection);
119-
return ans;
139+
retval.first = nearest(magnitudes.begin(), magnitudes.end(), projection);
140+
return retval;
120141
}
121-
122142
}
123143
}

0 commit comments

Comments
 (0)