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