// See http://en.wikipedia.org/wiki/Structure_factor, cf. (4) or (5). void DistanceService::FillStructureFactor(StructureFactor* structureFactor) const { // I'm using the equation from "Perfect Crystals" section, as it is faster, though may have worse precision (as doesn't use all the info from the particles). // It is also used in Jiao and Torquato (2011) Maximally random jammed packings of platonic solids, cf. 3. // For this code also Xu and Ching (2010) Effects of particle-size ratio on jamming of binary mixtures at zero temperature // "Due to the periodic boundary conditions, the wave vector must be chosen as..." structureFactor->waveVectorLengths.clear(); structureFactor->structureFactorValues.clear(); vector<StructureFactorPair> result; const int acceptableVectorsCount = 70000; // determined empirically const int maxDiscreteCoordinate = 12; const int currentVectorsCount = (2 * maxDiscreteCoordinate + 1) * (2 * maxDiscreteCoordinate + 1) * (2 * maxDiscreteCoordinate + 1); const FLOAT_TYPE vectorAcceptanceProbability = static_cast<FLOAT_TYPE>(acceptableVectorsCount) / currentVectorsCount; for (int i = -maxDiscreteCoordinate; i <= maxDiscreteCoordinate; ++i) { for (int j = -maxDiscreteCoordinate; j <= maxDiscreteCoordinate; ++j) { for (int k = -maxDiscreteCoordinate; k <= maxDiscreteCoordinate; ++k) { if (i == 0 && j == 0 && k == 0) { continue; } SpatialVector waveVector; waveVector[Axis::X] = i * 2.0 * PI / config->packingSize[Axis::X]; waveVector[Axis::Y] = j * 2.0 * PI / config->packingSize[Axis::Y]; waveVector[Axis::Z] = k * 2.0 * PI / config->packingSize[Axis::Z]; FLOAT_TYPE waveVectorLength = VectorUtilities::GetLength(waveVector); // Usually the first maximum of structure factor is around 2 * PI if (waveVectorLength > 2.0 * PI) { FLOAT_TYPE randomVariable = Math::GetNextRandom(); if (randomVariable > vectorAcceptanceProbability) { continue; } } complex<FLOAT_TYPE> complexSum(0.0, 0.0); complex<FLOAT_TYPE> imaginaryUnit(0.0, 1.0); for (ParticleIndex particleIndex = 0; particleIndex < config->particlesCount; ++particleIndex) { const Packing& particlesRef = *particles; FLOAT_TYPE dotProduct = VectorUtilities::GetDotProduct(waveVector, particlesRef[particleIndex].coordinates); complexSum += exp(imaginaryUnit * dotProduct); } StructureFactorPair pair; pair.waveVectorLength = waveVectorLength; pair.structureFactorValue = norm(complexSum) / config->particlesCount; result.push_back(pair); } } } StlUtilities::Sort(&result); for (vector<StructureFactorPair>::const_iterator it = result.begin(); it != result.end(); ++it) { StructureFactorPair pair = *it; structureFactor->waveVectorLengths.push_back(pair.waveVectorLength); structureFactor->structureFactorValues.push_back(pair.structureFactorValue); } }
int computeMoments(int startGate, int endGate, Beam *beam) { /* initialize summation quantities */ int igate; double sumPowerH = 0.0; double sumPowerV = 0.0; double nn = 0.0; Complex_t sumRvh0; sumRvh0.re = 0.0; sumRvh0.im = 0.0; /* loop through gates to be used for sun computations */ for (igate = startGate; igate <= endGate; igate++, nn++) { /* get the I/Q data time series for the gate */ /* the getGateIq() functions must be provided externally. */ const Complex_t *iqh = getGateIqH(igate); const Complex_t *iqv = getGateIqV(igate); /* compute lag 0 covariance = power */ double lag0_h = meanPower(iqh, nSamples - 1); double lag0_v = meanPower(iqv, nSamples - 1); /* check power for interference */ double dbmH = 10.0 * log10(lag0_h); double dbmV = 10.0 * log10(lag0_v); if (dbmH > maxValidDrxPowerDbm) { /* don't use this gate - probably interference */ continue; } /* compute lag0 conjugate product, for correlation */ Complex_t lag0_hv = meanConjugateProduct(iqh, iqv, nSamples - 1); /* sum up */ sumPowerH += lag0_h; sumPowerV += lag0_v; sumRvh0 = complexSum(&sumRvh0, &lag0_hv); } /* igate */ /* sanity check */ if (nn < 3) { fprintf(stderr, "Warning - computeMoments\n"); fprintf(stderr, " Insufficient good data found\n"); fprintf(stderr, " az, el: %lg, %lg\n", beam->az, beam->el); fprintf(stderr, " nn: %d\n", nn); return -1; } /* compute mean moments */ beam->powerH = sumPowerH / nn; beam->powerV = sumPowerV / nn; beam->dbmH = 10.0 * log10(beam->powerH); beam->dbmV = 10.0 * log10(beam->powerV); beam->dbm = (beam->dbmH + beam->dbmV)/2.0; beam->zdr = beam->dbmH - beam->dbmV; beam->SS = 1.0 / (2.0 * beam->zdr); double corrMag = mag(&sumRvh0) / nn; beam->corrHV = corrMag / sqrt(beam->powerH * beam->powerV); beam->phaseHV = argDeg(&sumRvh0); /* compute sun angle offset */ double sunEl, sunAz; computePosnNova(beam->time, &sunEl, &sunAz); double cosel = cos(beam->el * DEG_TO_RAD); beam->azOffset = computeAngleDiff(beam->az, sunAz) * cosel; beam->elOffset = computeAngleDiff(beam->el, sunEl); return 0; }