File indexing completed on 2024-12-22 04:17:59
0001 /*************************************************************************** 0002 psd.cpp: Power Spectra for KST 0003 ------------------- 0004 begin : Fri Feb 10 2002 0005 copyright : (C) 2002 by C. Barth Netterfield 0006 email : netterfield@astro.utoronto.ca 0007 ***************************************************************************/ 0008 0009 /*************************************************************************** 0010 * * 0011 * This program is free software; you can redistribute it and/or modify * 0012 * it under the terms of the GNU General Public License as published by * 0013 * the Free Software Foundation; either version 2 of the License, or * 0014 * (at your option) any later version. * 0015 * * 0016 ***************************************************************************/ 0017 0018 /** A class for handling power spectra for kst 0019 *@author C. Barth Netterfield 0020 */ 0021 0022 #include "psd.h" 0023 0024 #include <assert.h> 0025 #include <math.h> 0026 0027 #include <QXmlStreamWriter> 0028 0029 0030 #include <qdebug.h> 0031 0032 #include "dialoglauncher.h" 0033 #include "datacollection.h" 0034 #include "debug.h" 0035 #include "psdcalculator.h" 0036 #include "objectstore.h" 0037 0038 #include "dataobjectscriptinterface.h" 0039 0040 using namespace std; 0041 0042 extern "C" void rdft(int n, int isgn, double *a); 0043 0044 namespace Kst { 0045 0046 const QString PSD::staticTypeString = "Power Spectrum"; 0047 const QString PSD::staticTypeTag = "powerspectrum"; 0048 0049 static const QLatin1String& INVECTOR = QLatin1String("I"); 0050 static const QLatin1String& SVECTOR = QLatin1String("S"); 0051 static const QLatin1String& FVECTOR = QLatin1String("F"); 0052 0053 #define KSTPSDMAXLEN 27 0054 0055 PSD::PSD(ObjectStore *store) 0056 : DataObject(store) { 0057 _changed = true; 0058 _typeString = staticTypeString; 0059 _type = "PowerSpectrum"; 0060 _initializeShortName(); 0061 0062 Q_ASSERT(store); 0063 VectorPtr ov = store->createObject<Vector>(); 0064 ov->setProvider(this); 0065 ov->setSlaveName("f"); 0066 ov->resize(2); 0067 _fVector = _outputVectors.insert(FVECTOR, ov).value(); 0068 0069 ov = store->createObject<Vector>(); 0070 ov->setProvider(this); 0071 ov->setSlaveName("psd"); 0072 ov->resize(2); 0073 _sVector = _outputVectors.insert(SVECTOR, ov).value(); 0074 } 0075 0076 void PSD::_initializeShortName() { 0077 _shortName = 'S'+QString::number(_psdnum); 0078 if (_psdnum>max_psdnum) 0079 max_psdnum = _psdnum; 0080 _psdnum++; 0081 } 0082 0083 0084 ScriptInterface* PSD::createScriptInterface() { 0085 return new SpectrumSI(this); 0086 } 0087 0088 0089 void PSD::change(VectorPtr in_V, 0090 double in_freq, bool in_average, int in_averageLen, bool in_apodize, 0091 bool in_removeMean, const QString& in_VUnits, const QString& in_RUnits, 0092 ApodizeFunction in_apodizeFxn, double in_gaussianSigma, PSDType in_output) { 0093 0094 if (in_V) { 0095 _inputVectors[INVECTOR] = in_V; 0096 } 0097 _Frequency = in_freq; 0098 _Average = in_average; 0099 _Apodize = in_apodize; 0100 _apodizeFxn = in_apodizeFxn; 0101 _gaussianSigma = in_gaussianSigma; 0102 _prevOutput = PSDUndefined; 0103 _RemoveMean = in_removeMean; 0104 _vectorUnits = in_VUnits; 0105 _rateUnits = in_RUnits; 0106 _Output = in_output; 0107 _averageLength = in_averageLen; 0108 0109 _last_n_subsets = 0; 0110 _last_n_new = 0; 0111 _last_n_new = 0; 0112 0113 _PSDLength = 1; 0114 0115 _fVector->resize(_PSDLength); 0116 _sVector->resize(_PSDLength); 0117 0118 _changed = true; 0119 updateVectorLabels(); 0120 } 0121 0122 0123 PSD::~PSD() { 0124 _sVector = 0L; 0125 _fVector = 0L; 0126 } 0127 0128 0129 const CurveHintList *PSD::curveHints() const { 0130 _curveHints->clear(); 0131 _curveHints->append(new CurveHint(tr("PSD Curve"), _fVector->shortName(), 0132 _sVector->shortName())); 0133 return _curveHints; 0134 } 0135 0136 0137 void PSD::internalUpdate() { 0138 writeLockInputsAndOutputs(); 0139 0140 VectorPtr iv = _inputVectors[INVECTOR]; 0141 0142 const int v_len = iv->length(); 0143 0144 _last_n_new += iv->numNew(); 0145 assert(_last_n_new >= 0); 0146 0147 int n_subsets = (v_len)/_PSDLength; 0148 0149 // determine if the PSD needs to be updated. 0150 // if not using averaging, then we need at least _PSDLength/16 new data points. 0151 // if averaging, then we want enough new data for a complete subset. 0152 // ... unless we are counting from end at fixed length (scrolling data). 0153 bool scrolling_data = (_last_n == iv->length()); 0154 if ( (!_changed) && ((_last_n_new < _PSDLength/16) || 0155 (_Average && scrolling_data && (_last_n_new < _PSDLength/16)) || 0156 (_Average && !scrolling_data && (n_subsets - _last_n_subsets < 1))) && 0157 iv->length() != iv->numNew()) { 0158 unlockInputsAndOutputs(); 0159 return; 0160 } 0161 0162 _changed = false; 0163 0164 _adjustLengths(); 0165 0166 double *psd = _sVector->raw_V_ptr(); 0167 double *f = _fVector->raw_V_ptr(); 0168 0169 int i_samp; 0170 for (i_samp = 0; i_samp < _PSDLength; ++i_samp) { 0171 f[i_samp] = i_samp * 0.5 * _Frequency / (_PSDLength - 1); 0172 } 0173 //f[0] = -1E-280; // really 0 (this shouldn't be needed...) 0174 0175 _psdCalculator.calculatePowerSpectrum(iv->noNanValue(), v_len, psd, _PSDLength, _RemoveMean, _Average, _averageLength, _Apodize, _apodizeFxn, _gaussianSigma, _Output, _Frequency); 0176 0177 _last_n_subsets = n_subsets; 0178 _last_n_new = 0; 0179 _last_n = iv->length(); 0180 0181 updateVectorLabels(); 0182 0183 // should be updated by the update manager 0184 //_sVector->update(); 0185 //_fVector->update(); 0186 0187 unlockInputsAndOutputs(); 0188 0189 return; 0190 } 0191 0192 0193 void PSD::_adjustLengths() { 0194 int nPSDLen = PSDCalculator::calculateOutputVectorLength(_inputVectors[INVECTOR]->length(), _Average, _averageLength); 0195 0196 if (_PSDLength != nPSDLen) { 0197 _sVector->resize(nPSDLen); 0198 _fVector->resize(nPSDLen); 0199 0200 if ( (_sVector->length() == nPSDLen) && (_fVector->length() == nPSDLen) ) { 0201 _PSDLength = nPSDLen; 0202 } else { 0203 Debug::self()->log(tr("Attempted to create a PSD that used all memory."), Debug::Error); 0204 } 0205 0206 _last_n_subsets = 0; 0207 _changed = true; 0208 } 0209 } 0210 0211 0212 void PSD::save(QXmlStreamWriter &s) { 0213 s.writeStartElement(staticTypeTag); 0214 s.writeAttribute("vector", _inputVectors[INVECTOR]->Name()); 0215 s.writeAttribute("samplerate", QString::number(_Frequency)); 0216 s.writeAttribute("gaussiansigma", QString::number(_gaussianSigma)); 0217 s.writeAttribute("average", QVariant(_Average).toString()); 0218 s.writeAttribute("fftlength", QString::number(int(ceil(log(double(_PSDLength*2)) / log(2.0))))); 0219 s.writeAttribute("removemean", QVariant(_RemoveMean).toString()); 0220 s.writeAttribute("apodize", QVariant(_Apodize).toString()); 0221 s.writeAttribute("apodizefunction", QString::number(_apodizeFxn)); 0222 s.writeAttribute("vectorunits", _vectorUnits); 0223 s.writeAttribute("rateunits", _rateUnits); 0224 s.writeAttribute("outputtype", QString::number(_Output)); 0225 saveNameInfo(s, VECTORNUM|PSDNUM|SCALARNUM); 0226 0227 s.writeEndElement(); 0228 } 0229 0230 0231 bool PSD::apodize() const { 0232 return _Apodize; 0233 } 0234 0235 0236 void PSD::setApodize(bool in_apodize) { 0237 _Apodize = in_apodize; 0238 _changed = true; 0239 } 0240 0241 0242 bool PSD::removeMean() const { 0243 return _RemoveMean; 0244 } 0245 0246 0247 void PSD::setRemoveMean(bool in_removeMean) { 0248 _RemoveMean = in_removeMean; 0249 _changed = true; 0250 } 0251 0252 0253 bool PSD::average() const { 0254 return _Average; 0255 } 0256 0257 0258 void PSD::setAverage(bool in_average) { 0259 _Average = in_average; 0260 _changed = true; 0261 } 0262 0263 0264 double PSD::frequency() const { 0265 return _Frequency; 0266 } 0267 0268 0269 void PSD::setFrequency(double in_frequency) { 0270 if (in_frequency > 0.0) { 0271 _Frequency = in_frequency; 0272 } else { 0273 _Frequency = 1.0; 0274 } 0275 _changed = true; 0276 } 0277 0278 0279 int PSD::length() const { 0280 return _averageLength; 0281 } 0282 0283 0284 void PSD::setLength(int in_length) { 0285 if (in_length != _averageLength) { 0286 _averageLength = in_length; 0287 } 0288 _changed = true; 0289 } 0290 0291 0292 PSDType PSD::output() const { 0293 return _Output; 0294 } 0295 0296 0297 void PSD::setOutput(PSDType in_output) { 0298 if (in_output != _Output) { 0299 _Output = in_output; 0300 } 0301 _changed = true; 0302 } 0303 0304 0305 VectorPtr PSD::vector() const { 0306 return _inputVectors[INVECTOR]; 0307 } 0308 0309 0310 void PSD::setVector(VectorPtr new_v) { 0311 Q_ASSERT(myLockStatus() == KstRWLock::WRITELOCKED); 0312 0313 VectorPtr v = _inputVectors[INVECTOR]; 0314 if (v) { 0315 if (v == new_v) { 0316 return; 0317 } 0318 v->unlock(); 0319 } 0320 0321 _inputVectors.remove(INVECTOR); 0322 new_v->writeLock(); 0323 _inputVectors[INVECTOR] = new_v; 0324 _changed = true; 0325 } 0326 0327 0328 bool PSD::slaveVectorsUsed() const { 0329 return true; 0330 } 0331 0332 0333 QString PSD::propertyString() const { 0334 return tr("PSD: %1").arg(_inputVectors[INVECTOR]->Name()); 0335 } 0336 0337 0338 void PSD::showNewDialog() { 0339 DialogLauncher::self()->showPowerSpectrumDialog(); 0340 } 0341 0342 0343 void PSD::showEditDialog() { 0344 DialogLauncher::self()->showPowerSpectrumDialog(this); 0345 } 0346 0347 0348 const QString& PSD::vectorUnits() const { 0349 return _vectorUnits; 0350 } 0351 0352 0353 void PSD::setVectorUnits(const QString& units) { 0354 _vectorUnits = units; 0355 } 0356 0357 0358 const QString& PSD::rateUnits() const { 0359 return _rateUnits; 0360 } 0361 0362 0363 void PSD::setRateUnits(const QString& units) { 0364 _rateUnits = units; 0365 } 0366 0367 0368 ApodizeFunction PSD::apodizeFxn() const { 0369 return _apodizeFxn; 0370 } 0371 0372 0373 void PSD::setApodizeFxn(ApodizeFunction in_apodizeFxn) { 0374 if (_apodizeFxn != in_apodizeFxn) { 0375 _apodizeFxn = in_apodizeFxn; 0376 } 0377 _changed = true; 0378 } 0379 0380 0381 double PSD::gaussianSigma() const { 0382 return _gaussianSigma; 0383 } 0384 0385 0386 void PSD::setGaussianSigma(double in_gaussianSigma) { 0387 if (_gaussianSigma != in_gaussianSigma) { 0388 _gaussianSigma = in_gaussianSigma; 0389 } 0390 _changed = true; 0391 } 0392 0393 0394 DataObjectPtr PSD::makeDuplicate() const { 0395 0396 PSDPtr powerspectrum = store()->createObject<PSD>(); 0397 Q_ASSERT(powerspectrum); 0398 0399 powerspectrum->writeLock(); 0400 powerspectrum->setVector(_inputVectors[INVECTOR]); 0401 powerspectrum->setFrequency(_Frequency); 0402 powerspectrum->setAverage(_Average); 0403 powerspectrum->setLength(_averageLength); 0404 powerspectrum->setApodize(_Apodize); 0405 powerspectrum->setRemoveMean(_RemoveMean); 0406 powerspectrum->setVectorUnits(_vectorUnits); 0407 powerspectrum->setRateUnits(_rateUnits); 0408 powerspectrum->setApodizeFxn(_apodizeFxn); 0409 powerspectrum->setGaussianSigma(_gaussianSigma); 0410 powerspectrum->setOutput(_Output); 0411 if (descriptiveNameIsManual()) { 0412 powerspectrum->setDescriptiveName(descriptiveName()); 0413 } 0414 powerspectrum->registerChange(); 0415 powerspectrum->unlock(); 0416 0417 return DataObjectPtr(powerspectrum); 0418 } 0419 0420 0421 void PSD::updateVectorLabels() { 0422 LabelInfo label_info; 0423 0424 switch (_Output) { 0425 default: 0426 case 0: // amplitude spectral density (default) [V/Hz^1/2] 0427 label_info.quantity = tr("Spectral Density"); 0428 if (_vectorUnits.isEmpty() || _rateUnits.isEmpty()) { 0429 label_info.units.clear(); 0430 } else { 0431 label_info.units = QString("%1/%2^{1/2}").arg(_vectorUnits).arg(_rateUnits); 0432 } 0433 break; 0434 case 1: // power spectral density [V^2/Hz] 0435 label_info.quantity = tr("PSD"); 0436 if (_vectorUnits.isEmpty() || _rateUnits.isEmpty()) { 0437 label_info.units.clear(); 0438 } else { 0439 label_info.units = QString("%1^2/%2").arg(_vectorUnits).arg(_rateUnits); 0440 } 0441 break; 0442 case 2: // amplitude spectrum [V] 0443 label_info.quantity = tr("Amplitude Spectrum"); 0444 if (_vectorUnits.isEmpty() || _rateUnits.isEmpty()) { 0445 label_info.units.clear(); 0446 } else { 0447 label_info.units = QString("%1").arg(_vectorUnits); 0448 } 0449 break; 0450 case 3: // power spectrum [V^2] 0451 label_info.quantity = tr("Power Spectrum"); 0452 if (_vectorUnits.isEmpty() || _rateUnits.isEmpty()) { 0453 label_info.units.clear(); 0454 } else { 0455 label_info.units = QString("%1^2").arg(_vectorUnits); 0456 } 0457 break; 0458 } 0459 label_info.name.clear(); 0460 _sVector->setLabelInfo(label_info); 0461 0462 label_info.quantity = tr("Frequency"); 0463 label_info.units = _rateUnits; 0464 _fVector->setLabelInfo(label_info); 0465 0466 label_info.quantity.clear(); 0467 label_info.units.clear(); 0468 label_info.name = _inputVectors[INVECTOR]->labelInfo().name; 0469 label_info.file = _inputVectors[INVECTOR]->labelInfo().file; 0470 _sVector->setTitleInfo(label_info); 0471 0472 } 0473 0474 QString PSD::_automaticDescriptiveName() const { 0475 return vector()->descriptiveName(); 0476 } 0477 0478 QString PSD::descriptionTip() const { 0479 QString tip; 0480 0481 tip = tr("Spectrum: %1\n FFT Length: 2^%2").arg(Name()).arg(length()); 0482 0483 if (average() || apodize() || removeMean()) { 0484 tip += "\n "; 0485 if (average()) tip += tr("Average; "); 0486 if (apodize()) tip += tr("Apodize; "); 0487 if (removeMean()) tip += tr("Remove Mean;"); 0488 } 0489 tip += tr("\nInput: %1").arg(_inputVectors[INVECTOR]->descriptionTip()); 0490 return tip; 0491 } 0492 } 0493 // vim: ts=2 sw=2 et