spectrum: Calculate PSD by combining received power, even when no precoding matrix is set
This commit is contained in:
@@ -280,49 +280,50 @@ ThreeGppSpectrumPropagationLossModel::CalcBeamformingGain(
|
||||
numRxPorts,
|
||||
isReverse);
|
||||
|
||||
// The precoding matrix is not set
|
||||
NS_ASSERT_MSG(rxParams->psd->GetValuesN() == rxParams->spectrumChannelMatrix->GetNumPages(),
|
||||
"RX PSD and the spectrum channel matrix should have the same number of RBs ");
|
||||
|
||||
// Calculate RX PSD from the spectrum channel matrix H and
|
||||
// the precoding matrix P as: PSD = (H*P)^h * (H*P)
|
||||
MatrixBasedChannelModel::Complex3DVector psd;
|
||||
MatrixBasedChannelModel::Complex3DVector p;
|
||||
if (!rxParams->precodingMatrix)
|
||||
{
|
||||
// Update rxParams->Psd.
|
||||
// Compute RX PSD from the channel matrix
|
||||
auto vit = rxParams->psd->ValuesBegin(); // psd iterator
|
||||
size_t rbIdx = 0;
|
||||
while (vit != rxParams->psd->ValuesEnd())
|
||||
// When the precoding matrix P is not set, we create one with a single column
|
||||
p = ComplexMatrixArray(rxParams->spectrumChannelMatrix->GetNumCols(), 1, 1);
|
||||
// Initialize it to the inverse square of the number of txPorts
|
||||
p.Elem(0, 0, 0) = 1.0 / sqrt(rxParams->spectrumChannelMatrix->GetNumCols());
|
||||
for (size_t rowI = 0; rowI < rxParams->spectrumChannelMatrix->GetNumCols(); rowI++)
|
||||
{
|
||||
// Calculate PSD for the first antenna port (correct for SISO)
|
||||
*vit = std::norm(rxParams->spectrumChannelMatrix->Elem(0, 0, rbIdx));
|
||||
vit++;
|
||||
rbIdx++;
|
||||
p.Elem(rowI, 0, 0) = p.Elem(0, 0, 0);
|
||||
}
|
||||
// Replicate vector to match the number of RBGs
|
||||
p = p.MakeNCopies(rxParams->spectrumChannelMatrix->GetNumPages());
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_ASSERT_MSG(rxParams->psd->GetValuesN() == rxParams->spectrumChannelMatrix->GetNumPages(),
|
||||
"RX PSD and the spectrum channel matrix should have the same number of RBs ");
|
||||
// Calculate RX PSD from the spectrum channel matrix, H and
|
||||
// the precoding matrix, P as:
|
||||
// PSD = (H*P)^h * (H*P),
|
||||
// where the dimensions are:
|
||||
// H (rxPorts,txPorts,numRbs) x P (txPorts,txStreams, numRbs) =
|
||||
// HxP (rxPorts,txStreams, numRbs)
|
||||
MatrixBasedChannelModel::Complex3DVector hP =
|
||||
*rxParams->spectrumChannelMatrix * (*rxParams->precodingMatrix);
|
||||
// (HxP)^h dimensions are (txStreams, rxPorts, numRbs)
|
||||
MatrixBasedChannelModel::Complex3DVector hPHerm = hP.HermitianTranspose();
|
||||
p = *rxParams->precodingMatrix;
|
||||
}
|
||||
// When we have the precoding matrix P, we first do
|
||||
// H(rxPorts,txPorts,numRbs) x P(txPorts,txStreams,numRbs) = HxP(rxPorts,txStreams,numRbs)
|
||||
MatrixBasedChannelModel::Complex3DVector hP = *rxParams->spectrumChannelMatrix * p;
|
||||
// Then (HxP)^h dimensions are (txStreams, rxPorts, numRbs)
|
||||
MatrixBasedChannelModel::Complex3DVector hPHerm = hP.HermitianTranspose();
|
||||
|
||||
// Finally, (HxP)^h x (HxP) = PSD (txStreams, txStreams, numRbs)
|
||||
MatrixBasedChannelModel::Complex3DVector psd = hPHerm * hP;
|
||||
// Update rxParams->Psd
|
||||
for (uint32_t rbIdx = 0; rbIdx < rxParams->psd->GetValuesN(); ++rbIdx)
|
||||
// Finally, (HxP)^h x (HxP) = PSD(txStreams, txStreams, numRbs)
|
||||
psd = hPHerm * hP;
|
||||
|
||||
// Update rxParams->Psd
|
||||
for (uint32_t rbIdx = 0; rbIdx < rxParams->psd->GetValuesN(); ++rbIdx)
|
||||
{
|
||||
(*rxParams->psd)[rbIdx] = 0.0;
|
||||
|
||||
for (size_t txStream = 0; txStream < psd.GetNumRows(); ++txStream)
|
||||
{
|
||||
(*rxParams->psd)[rbIdx] = 0.0;
|
||||
|
||||
for (size_t txStream = 0; txStream < psd.GetNumRows(); ++txStream)
|
||||
{
|
||||
(*rxParams->psd)[rbIdx] += std::real(psd(txStream, txStream, rbIdx));
|
||||
}
|
||||
(*rxParams->psd)[rbIdx] += std::real(psd(txStream, txStream, rbIdx));
|
||||
}
|
||||
}
|
||||
|
||||
return rxParams;
|
||||
}
|
||||
|
||||
|
||||
@@ -934,9 +934,18 @@ ThreeGppSpectrumPropagationLossModelTest::DoRun()
|
||||
// 1) check that the rx PSD is equal for both the direct and the reverse channel
|
||||
auto rxParamsNew =
|
||||
lossModel->DoCalcRxPowerSpectralDensity(txParams, rxMob, txMob, rxAntenna, txAntenna);
|
||||
NS_TEST_ASSERT_MSG_EQ((*rxParamsOld->psd == *rxParamsNew->psd),
|
||||
true,
|
||||
"The long term for the direct and the reverse channel are different");
|
||||
if ((rxParamsOld->spectrumChannelMatrix->GetNumCols() ==
|
||||
rxParamsNew->spectrumChannelMatrix->GetNumCols()) &&
|
||||
(rxParamsOld->spectrumChannelMatrix->GetNumRows() ==
|
||||
rxParamsNew->spectrumChannelMatrix->GetNumRows()) &&
|
||||
(rxParamsOld->spectrumChannelMatrix->GetNumCols() == 1) &&
|
||||
(rxParamsOld->spectrumChannelMatrix->GetNumRows() == 1))
|
||||
{
|
||||
// this is only really true in case of SISO (1x1 non-polarized port array)
|
||||
NS_TEST_ASSERT_MSG_EQ((*rxParamsOld->psd == *rxParamsNew->psd),
|
||||
true,
|
||||
"The long term for the direct and the reverse channel are different");
|
||||
}
|
||||
|
||||
// 2) check if the long term is updated when changing the BF vector
|
||||
// change the position of the rx device and recompute the beamforming vectors
|
||||
|
||||
Reference in New Issue
Block a user