Skip to content
Snippets Groups Projects
Commit 1ee1eefd authored by Marcel Loose's avatar Marcel Loose :sunglasses:
Browse files

Task #4589: Rewrote test for the Beam-former sub-band processor. Still needs...

Task #4589: Rewrote test for the Beam-former sub-band processor. Still needs some improvement, but it may be fine for now.
parent ec026277
No related branches found
No related tags found
No related merge requests found
//# tCorrelatorWorKQueueProcessSb.cc: test CorrelatorSubbandProc::processSubband()
//# tBeamFormerSubbandProcProcessSb: test of Beamformer subband processor.
//#
//# Copyright (C) 2013 ASTRON (Netherlands Institute for Radio Astronomy)
//# P.O. Box 2, 7990 AA Dwingeloo, The Netherlands
//#
......@@ -33,11 +34,14 @@ using namespace std;
using namespace LOFAR::Cobalt;
using namespace LOFAR::TYPES;
const unsigned nrChannel1 = 64;
const unsigned nrChannel2 = 64;
template<typename T> T inputSignal(size_t t)
{
size_t nrBits = sizeof(T) / 2 * 8;
// double freq = 1.0 / 2.0; // in samples
double freq = 1.0 / 32.0; // in samples
double freq = 1.0 / 4.0; // in samples
// double freq = (2 * 64.0 + 17.0) / 4096.0; // in samples
double amp = (1 << (nrBits - 1)) - 1;
double angle = (double)t * 2.0 * M_PI * freq;
......@@ -65,47 +69,93 @@ int main() {
Parset ps("tBeamFormerSubbandProcProcessSb.parset");
// Create very simple kernel programs, with predictable output. Skip as much as possible.
// Nr of channels/sb from the parset is 1, so the PPF will not even run.
// Parset also has turned of delay compensation and bandpass correction
// (but that kernel will run to convert int to float and to transform the data order).
// Input array sizes
const size_t nrBeams = ps.nrBeams();
const size_t nrStations = ps.nrStations();
const size_t nrPolarisations = ps.settings.nrPolarisations;
const size_t maxNrTABsPerSAP = ps.settings.beamFormer.maxNrTABsPerSAP();
const size_t nrSamplesPerSubband = ps.nrSamplesPerSubband();
const size_t nrBitsPerSample = ps.settings.nrBitsPerSample;
const size_t nrBytesPerComplexSample = ps.nrBytesPerComplexSample();
// We only support 8-bit or 16-bit input samples
ASSERT(nrBitsPerSample == 8 || nrBitsPerSample == 16);
// TODO: Amplitude is now calculated at two places. Dangerous!
const size_t amplitude = (1 << (nrBitsPerSample - 1)) - 1;
const size_t scaleFactor = nrBitsPerSample == 16 ? 1 : 16;
LOG_INFO_STR(
"Input info:" <<
"\n nrBeams = " << nrBeams <<
"\n nrStations = " << nrStations <<
"\n nrPolarisations = " << nrPolarisations <<
"\n maxNrTABsPerSAP = " << maxNrTABsPerSAP <<
"\n nrSamplesPerSubband = " << nrSamplesPerSubband <<
"\n nrBitsPerSample = " << nrBitsPerSample <<
"\n nrBytesPerComplexSample = " << nrBytesPerComplexSample);
// Output array sizes
const size_t nrStokes = ps.settings.beamFormer.incoherentSettings.nrStokes;
const size_t nrChannels =
ps.settings.beamFormer.incoherentSettings.nrChannels;
const size_t nrSamples =
ps.settings.beamFormer.incoherentSettings.nrSamples(
ps.settings.nrSamplesPerSubband());
LOG_INFO_STR(
"Output info:" <<
"\n nrStokes = " << nrStokes <<
"\n nrChannels = " << nrChannels <<
"\n nrSamples = " << nrSamples <<
"\n scaleFactor = " << scaleFactor);
// Create very simple kernel programs, with predictable output. Skip as much
// as possible. Nr of channels/sb from the parset is 1, so the PPF will not
// even run. Parset also has turned of delay compensation and bandpass
// correction (but that kernel will run to convert int to float and to
// transform the data order).
BeamFormerFactories factories(ps);
BeamFormerSubbandProc bwq(ps, ctx, factories);
LOG_INFO_STR(
"Input data:" <<
"\n nrBeams = " << ps.nrBeams() <<
"\n nrStations = " << ps.nrStations() <<
"\n nrPolarisations = " << ps.settings.nrPolarisations <<
"\n maxNrTABsPerSAP = " << ps.settings.beamFormer.maxNrTABsPerSAP() <<
"\n nrSamplesPerSubband = " << ps.nrSamplesPerSubband() <<
"\n nrBytesPerComplexSample = " << ps.nrBytesPerComplexSample());
SubbandProcInputData in(ps.nrBeams(), ps.nrStations(), ps.settings.nrPolarisations,
ps.settings.beamFormer.maxNrTABsPerSAP(),
ps.nrSamplesPerSubband(), ps.nrBytesPerComplexSample(), ctx);
SubbandProcInputData in(
nrBeams, nrStations, nrPolarisations, maxNrTABsPerSAP,
nrSamplesPerSubband, nrBytesPerComplexSample, ctx);
// Initialize synthetic input to input signal
for (size_t st = 0; st < ps.nrStations(); st++)
for (size_t i = 0; i < ps.nrSamplesPerSubband(); i++)
for (size_t pol = 0; pol < NR_POLARIZATIONS; pol++)
for (size_t st = 0; st < nrStations; st++)
for (size_t i = 0; i < nrSamplesPerSubband; i++)
for (size_t pol = 0; pol < nrPolarisations; pol++)
{
if (ps.nrBytesPerComplexSample() == 4) { // 16 bit mode
*(i16complex*)&in.inputSamples[st][i][pol][0] = inputSignal<i16complex>(i);
} else if (ps.nrBytesPerComplexSample() == 2) { // 8 bit mode
*(i8complex*)&in.inputSamples[st][i][pol][0] = inputSignal<i8complex>(i);
} else {
cerr << "Error: number of bits per sample must be 8, or 16" << endl;
exit(1);
switch(nrBitsPerSample) {
case 8:
reinterpret_cast<i8complex&>(in.inputSamples[st][i][pol][0]) =
inputSignal<i8complex>(i);
break;
case 16:
reinterpret_cast<i16complex&>(in.inputSamples[st][i][pol][0]) =
inputSignal<i16complex>(i);
break;
default:
break;
}
}
// Initialize subbands partitioning administration (struct BlockID). We only do the 1st block of whatever.
in.blockID.block = 0; // Block number: 0 .. inf
in.blockID.globalSubbandIdx = 0; // Subband index in the observation: [0, ps.nrSubbands())
in.blockID.localSubbandIdx = 0; // Subband index for this pipeline/workqueue: [0, subbandIndices.size())
in.blockID.subbandProcSubbandIdx = 0; // Subband index for this SubbandProc
// Initialize subbands partitioning administration (struct BlockID). We only
// do the 1st block of whatever.
// Block number: 0 .. inf
in.blockID.block = 0;
// Subband index in the observation: [0, ps.nrSubbands())
in.blockID.globalSubbandIdx = 0;
// Subband index for this pipeline/workqueue: [0, subbandIndices.size())
in.blockID.localSubbandIdx = 0;
// Subband index for this SubbandProc
in.blockID.subbandProcSubbandIdx = 0;
// Initialize delays. We skip delay compensation, but init anyway,
// so we won't copy uninitialized data to the device.
......@@ -118,18 +168,7 @@ int main() {
for (size_t i = 0; i < in.tabDelays.num_elements(); i++)
in.tabDelays.get<float>()[i] = 0.0f;
LOG_INFO_STR(
"BeamFormedData:" <<
"\n maxNrTABsPerSAP = " << ps.settings.beamFormer.maxNrTABsPerSAP() <<
"\n nrStokes = " << ps.settings.beamFormer.incoherentSettings.nrStokes <<
"\n nrChannels = " << ps.settings.beamFormer.incoherentSettings.nrChannels <<
"\n nrSamples = " << ps.settings.beamFormer.incoherentSettings.nrSamples(
ps.settings.nrSamplesPerSubband()));
BeamFormedData out(ps.settings.beamFormer.maxNrTABsPerSAP() * ps.settings.beamFormer.incoherentSettings.nrStokes,
ps.settings.beamFormer.incoherentSettings.nrChannels,
ps.settings.beamFormer.incoherentSettings.nrSamples(ps.settings.nrSamplesPerSubband()),
ctx);
BeamFormedData out(maxNrTABsPerSAP * nrStokes, nrChannels, nrSamples, ctx);
for (size_t i = 0; i < out.num_elements(); i++)
out.get<float>()[i] = 42.0f;
......@@ -143,39 +182,42 @@ int main() {
cout << "Output: " << endl;
// Output verification
// The int2float conversion scales its output to the same amplitude as in 16 bit mode.
// For 8 bit mode, that is a factor 256.
// Since we inserted all (1, 1) vals, for 8 bit mode this means that the correlator
// outputs 256*256. It then sums over nrSamplesPerSb values.
#if 0
unsigned scale = 1*1;
if (ps.nrBitsPerSample() == 8)
scale = 256*256;
#endif
bool unexpValueFound = false;
for (size_t b = 0; b < ps.settings.beamFormer.maxNrTABsPerSAP() * ps.settings.beamFormer.incoherentSettings.nrStokes; b++)
for (size_t t = 0; t < ps.settings.beamFormer.incoherentSettings.nrSamples(ps.settings.nrSamplesPerSubband()); t++)
for (size_t c = 0; c < ps.settings.beamFormer.incoherentSettings.nrChannels; c++)
{
float v = out[b][t][c];
// disable output validation until we've verified the beamformer pipeline!
#if 1
if (v != 4.0f)
{
unexpValueFound = true;
cout << '*'; // indicate error in output
}
#endif
cout << v << " ";
}
cout << endl;
if (unexpValueFound)
{
cerr << "Error: Found unexpected output value(s)" << endl;
return 1;
// We can calculate the expected output values, since we're supplying a
// complex sine/cosine input signal. We only have Stokes-I, so the output
// should be: (nrStation * amp * scaleFactor * nrChannel1 * nrChannel2)^2
// - amp is set to the maximum possible value for the bit-mode:
// i.e. 127 for 8-bit and 32767 for 16-bit mode
// - scaleFactor is the scaleFactor applied by the IntToFloat kernel.
// It is 16 for 8-bit mode and 1 for 16-bit mode.
// Hence, each output sample should be:
// - for 16-bit input: (2 * 32767 * 1 * 64 * 64)^2 = 72053196058525696
// - for 8-bit input: (2 * 127 * 16 * 64 * 64)^2 = 1082398867456
float outVal;
switch(nrBitsPerSample) {
case 8:
outVal =
nrStations * amplitude * scaleFactor * nrChannel1 * nrChannel2 *
nrStations * amplitude * scaleFactor * nrChannel1 * nrChannel2;
break;
case 16:
outVal =
nrStations * amplitude * scaleFactor * nrChannel1 * nrChannel2 *
nrStations * amplitude * scaleFactor * nrChannel1 * nrChannel2;
break;
default:
break;
}
cout << "outVal = " << outVal << endl;
for (size_t s = 0; s < nrStokes; s++)
for (size_t t = 0; t < nrSamples; t++)
for (size_t c = 0; c < nrChannels; c++)
ASSERTSTR(out[s][t][c] == outVal,
"out[" << s << "][" << t << "][" << c << "] = " <<
out[s][t][c] << "; outVal = " << outVal);
return 0;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment