File indexing completed on 2025-01-05 04:12:50
0001 /*************************************************************************** 0002 * * 0003 * copyright : (C) 2007 The University of Toronto * 0004 * netterfield@astro.utoronto.ca * 0005 * copyright : (C) 2005 University of British Columbia * 0006 * dscott@phas.ubc.ca * 0007 * * 0008 * This program is free software; you can redistribute it and/or modify * 0009 * it under the terms of the GNU General Public License as published by * 0010 * the Free Software Foundation; either version 2 of the License, or * 0011 * (at your option) any later version. * 0012 * * 0013 ***************************************************************************/ 0014 0015 0016 #include "crosscorrelation.h" 0017 #include "objectstore.h" 0018 #include "ui_crosscorrelationconfig.h" 0019 0020 #include <gsl/gsl_fft_real.h> 0021 #include <gsl/gsl_fft_halfcomplex.h> 0022 0023 0024 static const QString& VECTOR_IN_ONE = "Vector One In"; 0025 static const QString& VECTOR_IN_TWO = "Vector Two In"; 0026 static const QString& VECTOR_OUT_STEP = "Offset"; 0027 static const QString& VECTOR_OUT_CORRELATED = "C"; 0028 0029 class ConfigCrossCorrelationPlugin : public Kst::DataObjectConfigWidget, public Ui_CrossCorrelationConfig { 0030 public: 0031 ConfigCrossCorrelationPlugin(QSettings* cfg) : DataObjectConfigWidget(cfg), Ui_CrossCorrelationConfig() { 0032 _store = 0; 0033 setupUi(this); 0034 } 0035 0036 ~ConfigCrossCorrelationPlugin() {} 0037 0038 void setObjectStore(Kst::ObjectStore* store) { 0039 _store = store; 0040 _vectorOne->setObjectStore(store); 0041 _vectorTwo->setObjectStore(store); 0042 } 0043 0044 void setupSlots(QWidget* dialog) { 0045 if (dialog) { 0046 connect(_vectorOne, SIGNAL(selectionChanged(QString)), dialog, SIGNAL(modified())); 0047 connect(_vectorTwo, SIGNAL(selectionChanged(QString)), dialog, SIGNAL(modified())); 0048 } 0049 } 0050 0051 Kst::VectorPtr selectedVectorOne() { return _vectorOne->selectedVector(); }; 0052 void setSelectedVectorOne(Kst::VectorPtr vector) { return _vectorOne->setSelectedVector(vector); }; 0053 0054 Kst::VectorPtr selectedVectorTwo() { return _vectorTwo->selectedVector(); }; 0055 void setSelectedVectorTwo(Kst::VectorPtr vector) { return _vectorTwo->setSelectedVector(vector); }; 0056 0057 virtual void setupFromObject(Kst::Object* dataObject) { 0058 if (CrossCorrelationSource* source = static_cast<CrossCorrelationSource*>(dataObject)) { 0059 setSelectedVectorOne(source->vectorOne()); 0060 setSelectedVectorTwo(source->vectorTwo()); 0061 } 0062 } 0063 0064 virtual bool configurePropertiesFromXml(Kst::ObjectStore *store, QXmlStreamAttributes& attrs) { 0065 Q_UNUSED(store); 0066 Q_UNUSED(attrs); 0067 0068 bool validTag = true; 0069 0070 // QStringRef av; 0071 // av = attrs.value("value"); 0072 // if (!av.isNull()) { 0073 // _configValue = QVariant(av.toString()).toBool(); 0074 // } 0075 0076 return validTag; 0077 } 0078 0079 public slots: 0080 virtual void save() { 0081 if (_cfg) { 0082 _cfg->beginGroup("Cross Correlation DataObject Plugin"); 0083 _cfg->setValue("Input Vector One", _vectorOne->selectedVector()->Name()); 0084 _cfg->setValue("Input Vector Two", _vectorTwo->selectedVector()->Name()); 0085 _cfg->endGroup(); 0086 } 0087 } 0088 0089 virtual void load() { 0090 if (_cfg && _store) { 0091 _cfg->beginGroup("Cross Correlation DataObject Plugin"); 0092 QString vectorName = _cfg->value("Input Vector One").toString(); 0093 Kst::Object* object = _store->retrieveObject(vectorName); 0094 Kst::Vector* vector = static_cast<Kst::Vector*>(object); 0095 if (vector) { 0096 setSelectedVectorOne(vector); 0097 } 0098 vectorName = _cfg->value("Input Vector Two").toString(); 0099 Kst::Object* object2 = _store->retrieveObject(vectorName); 0100 Kst::Vector* vector2 = static_cast<Kst::Vector*>(object2); 0101 if (vector2) { 0102 setSelectedVectorTwo(vector2); 0103 } 0104 _cfg->endGroup(); 0105 } 0106 } 0107 0108 private: 0109 Kst::ObjectStore *_store; 0110 0111 }; 0112 0113 0114 CrossCorrelationSource::CrossCorrelationSource(Kst::ObjectStore *store) 0115 : Kst::BasicPlugin(store) { 0116 } 0117 0118 0119 CrossCorrelationSource::~CrossCorrelationSource() { 0120 } 0121 0122 0123 QString CrossCorrelationSource::_automaticDescriptiveName() const { 0124 return tr("Cross Correlation"); 0125 } 0126 0127 0128 void CrossCorrelationSource::change(Kst::DataObjectConfigWidget *configWidget) { 0129 if (ConfigCrossCorrelationPlugin* config = static_cast<ConfigCrossCorrelationPlugin*>(configWidget)) { 0130 setInputVector(VECTOR_IN_ONE, config->selectedVectorOne()); 0131 setInputVector(VECTOR_IN_TWO, config->selectedVectorTwo()); 0132 } 0133 } 0134 0135 0136 void CrossCorrelationSource::setupOutputs() { 0137 setOutputVector(VECTOR_OUT_STEP, ""); 0138 setOutputVector(VECTOR_OUT_CORRELATED, ""); 0139 } 0140 0141 0142 bool CrossCorrelationSource::algorithm() { 0143 Kst::VectorPtr inputVectorOne = _inputVectors[VECTOR_IN_ONE]; 0144 Kst::VectorPtr inputVectorTwo = _inputVectors[VECTOR_IN_TWO]; 0145 Kst::VectorPtr outputVectorStep = _outputVectors[VECTOR_OUT_STEP]; 0146 Kst::VectorPtr outputVectorCorrelated = _outputVectors[VECTOR_OUT_CORRELATED]; 0147 0148 if (inputVectorOne->length() <= 0 || inputVectorTwo->length() <= 0 || inputVectorOne->length() != inputVectorTwo->length()) { 0149 _errorString = tr("Error: Input Vectors - invalid size"); 0150 return false; 0151 } 0152 0153 double* pdArrayOne; 0154 double* pdArrayTwo; 0155 double* pdResult[2]; 0156 double dReal; 0157 double dImag; 0158 0159 int iLength; 0160 int iLengthNew; 0161 0162 bool bReturn = false; 0163 0164 // 0165 // zero-pad the array... 0166 // 0167 iLength = inputVectorOne->length(); 0168 iLength *= 2; 0169 0170 outputVectorStep->resize(inputVectorOne->length(), false); 0171 outputVectorCorrelated->resize(inputVectorTwo->length(), false); 0172 0173 // 0174 // round iLength up to the nearest power of two... 0175 // 0176 iLengthNew = 64; 0177 while( iLengthNew < iLength && iLengthNew > 0) { 0178 iLengthNew *= 2; 0179 } 0180 iLength = iLengthNew; 0181 0182 if (iLength <= 0) { 0183 _errorString = tr("Error: Invalid Input length calculated"); 0184 return false; 0185 } 0186 0187 pdArrayOne = new double[iLength]; 0188 pdArrayTwo = new double[iLength]; 0189 if (pdArrayOne != NULL && pdArrayTwo != NULL) { 0190 // 0191 // zero-pad the two arrays... 0192 // 0193 memset( pdArrayOne, 0, iLength * sizeof( double ) ); 0194 memcpy( pdArrayOne, inputVectorOne->value(), inputVectorOne->length() * sizeof( double ) ); 0195 0196 memset( pdArrayTwo, 0, iLength * sizeof( double ) ); 0197 memcpy( pdArrayTwo, inputVectorTwo->value(), inputVectorTwo->length() * sizeof( double ) ); 0198 0199 // 0200 // calculate the FFTs of the two functions... 0201 // 0202 if (gsl_fft_real_radix2_transform( pdArrayOne, 1, iLength ) == 0) { 0203 if (gsl_fft_real_radix2_transform( pdArrayTwo, 1, iLength ) == 0) { 0204 // 0205 // multiply one FFT by the complex conjugate of the other... 0206 // 0207 for (int i=0; i<iLength/2; i++) { 0208 if (i==0 || i==(iLength/2)-1) { 0209 pdArrayOne[i] = pdArrayOne[i] * pdArrayTwo[i]; 0210 } else { 0211 dReal = pdArrayOne[i] * pdArrayTwo[i] + pdArrayOne[iLength-i] * pdArrayTwo[iLength-i]; 0212 dImag = pdArrayOne[i] * pdArrayTwo[iLength-i] - pdArrayOne[iLength-i] * pdArrayTwo[i]; 0213 0214 pdArrayOne[i] = dReal; 0215 pdArrayOne[iLength-i] = dImag; 0216 } 0217 } 0218 0219 // 0220 // do the inverse FFT... 0221 // 0222 if (gsl_fft_halfcomplex_radix2_inverse( pdArrayOne, 1, iLength ) == 0) { 0223 pdResult[0] = outputVectorStep->raw_V_ptr(); 0224 pdResult[1] = outputVectorCorrelated->raw_V_ptr(); 0225 0226 if (pdResult[0] != NULL && pdResult[1] != NULL) { 0227 for (int i = 0; i < inputVectorOne->length(); ++i) { 0228 outputVectorStep->raw_V_ptr()[i] = pdResult[0][i]; 0229 } 0230 for (int i = 0; i < inputVectorTwo->length(); ++i) { 0231 outputVectorCorrelated->raw_V_ptr()[i] = pdResult[1][i]; 0232 } 0233 0234 for (int i = 0; i < inputVectorOne->length(); i++) { 0235 outputVectorStep->raw_V_ptr()[i] = (double)( i - ( inputVectorOne->length() / 2 ) ); 0236 } 0237 0238 memcpy( &(outputVectorCorrelated->raw_V_ptr()[inputVectorOne->length() / 2]), 0239 &(pdArrayOne[0]), 0240 ( ( inputVectorOne->length() + 1 ) / 2 ) * sizeof( double ) ); 0241 0242 memcpy( &(outputVectorCorrelated->raw_V_ptr()[0]), 0243 &(pdArrayOne[iLength - (inputVectorOne->length() / 2)]), 0244 ( inputVectorOne->length() / 2 ) * sizeof( double ) ); 0245 0246 bReturn = true; 0247 } 0248 } 0249 } 0250 } 0251 } 0252 delete[] pdArrayOne; 0253 delete[] pdArrayTwo; 0254 0255 return bReturn; 0256 } 0257 0258 0259 Kst::VectorPtr CrossCorrelationSource::vectorOne() const { 0260 return _inputVectors[VECTOR_IN_ONE]; 0261 } 0262 0263 0264 Kst::VectorPtr CrossCorrelationSource::vectorTwo() const { 0265 return _inputVectors[VECTOR_IN_TWO]; 0266 } 0267 0268 0269 QStringList CrossCorrelationSource::inputVectorList() const { 0270 QStringList vectors(VECTOR_IN_ONE); 0271 vectors += VECTOR_IN_TWO; 0272 return vectors; 0273 } 0274 0275 0276 QStringList CrossCorrelationSource::inputScalarList() const { 0277 return QStringList( /*SCALAR_IN*/ ); 0278 } 0279 0280 0281 QStringList CrossCorrelationSource::inputStringList() const { 0282 return QStringList( /*STRING_IN*/ ); 0283 } 0284 0285 0286 QStringList CrossCorrelationSource::outputVectorList() const { 0287 QStringList vectors(VECTOR_OUT_CORRELATED); 0288 vectors += VECTOR_OUT_STEP; 0289 return vectors; 0290 } 0291 0292 0293 QStringList CrossCorrelationSource::outputScalarList() const { 0294 return QStringList( /*SCALAR_OUT*/ ); 0295 } 0296 0297 0298 QStringList CrossCorrelationSource::outputStringList() const { 0299 return QStringList( /*STRING_OUT*/ ); 0300 } 0301 0302 0303 void CrossCorrelationSource::saveProperties(QXmlStreamWriter &s) { 0304 Q_UNUSED(s); 0305 // s.writeAttribute("value", _configValue); 0306 } 0307 0308 0309 QString CrossCorrelationPlugin::pluginName() const { return tr("Cross Correlation"); } 0310 QString CrossCorrelationPlugin::pluginDescription() const { return tr("Generates the correlation of one vector with another."); } 0311 0312 0313 Kst::DataObject *CrossCorrelationPlugin::create(Kst::ObjectStore *store, Kst::DataObjectConfigWidget *configWidget, bool setupInputsOutputs) const { 0314 0315 if (ConfigCrossCorrelationPlugin* config = static_cast<ConfigCrossCorrelationPlugin*>(configWidget)) { 0316 0317 CrossCorrelationSource* object = store->createObject<CrossCorrelationSource>(); 0318 0319 if (setupInputsOutputs) { 0320 object->setupOutputs(); 0321 object->setInputVector(VECTOR_IN_ONE, config->selectedVectorOne()); 0322 object->setInputVector(VECTOR_IN_TWO, config->selectedVectorTwo()); 0323 } 0324 0325 object->setPluginName(pluginName()); 0326 0327 object->writeLock(); 0328 object->registerChange(); 0329 object->unlock(); 0330 0331 return object; 0332 } 0333 return 0; 0334 } 0335 0336 0337 Kst::DataObjectConfigWidget *CrossCorrelationPlugin::configWidget(QSettings *settingsObject) const { 0338 ConfigCrossCorrelationPlugin *widget = new ConfigCrossCorrelationPlugin(settingsObject); 0339 return widget; 0340 } 0341 0342 #ifndef QT5 0343 Q_EXPORT_PLUGIN2(kstplugin_ConvolvePlugin, CrossCorrelationPlugin) 0344 #endif 0345 0346 // vim: ts=2 sw=2 et