#include <DampingResults.h>
Classes | |
struct | Result |
Public Slots | |
void | save (QString fileName=QString::null) |
Public Member Functions | |
bool | compute (int ig, const Signal *sig, const Parameters ¶m) |
void | createObjects (SubSignalPool *subPool) |
DampingResults (QWidget *parent=0) | |
void | setWindowTitle (QString title) |
~DampingResults () | |
Public Attributes | |
QMenu * | menuTools |
Static Protected Member Functions | |
static double | misfitFunk (double x[]) |
Protected Attributes | |
LineLayer ** | _averageCurveLayers |
TextEdit ** | _comments |
LineLayer ** | _fitCurveLayers |
QString | _log |
QVector< Result > | _results |
LineLayer ** | _stddevCurveLayers |
Static Protected Attributes | |
static Curve< Point2D > | _aveCurve |
static double | _fitW = 0 |
static int | _nSampFit = 0 |
DampingResults::DampingResults | ( | QWidget * | parent = 0 | ) |
References SciFigs::GraphicSheetMenu::addMenu(), menuTools, save(), QGpCoreTools::tr(), and TRACE.
: GraphicSheetMenu(parent) { TRACE; Settings::getSize(this, "DampingResults" ); QAction * a; menuTools=addMenu(tr( "&Tools" )); a=new QAction(tr( "&Save results" ), this); a->setStatusTip(tr( "Save results of spectral analysis in a text file with process information (.log file)" )); connect(a, SIGNAL(triggered()), this, SLOT(save()) ); menuTools->addAction(a); }
References _averageCurveLayers, _comments, _fitCurveLayers, _stddevCurveLayers, and TRACE.
{ TRACE; Settings::setSize(this, "DampingResults" ); delete [] _comments; delete [] _averageCurveLayers; delete [] _stddevCurveLayers; delete [] _fitCurveLayers; }
bool DampingResults::compute | ( | int | ig, |
const Signal * | sig, | ||
const Parameters & | param | ||
) |
References _aveCurve, _averageCurveLayers, _comments, _fitCurveLayers, _fitW, _log, _nSampFit, _results, _stddevCurveLayers, GeopsyCore::TimeRangeParameters::absoluteRange(), SciFigs::LineLayer::addLine(), QGpCoreTools::amoeba(), QGpCoreTools::Curve< pointType >::at(), SciFigs::GraphContent::boundingRect(), SciFigs::LineLayer::clear(), QGpCoreTools::Curve< pointType >::clear(), CONST_LOCK_SAMPLES, GeopsyCore::DoubleSignal::copySamplesFrom(), SciFigs::AxisWindow::deepUpdate(), GeopsyCore::DoubleSignal::deltaT(), GeopsyCore::TimeRange::end(), QGpCoreTools::endl(), QGpCoreTools::exp(), Parameters::filter(), GeopsyCore::DoubleSignal::filter(), Parameters::fitLength(), SciFigs::GraphContent::graph(), SciFigs::GraphContentLayer::graphContent(), GeopsyCore::SignalTemplate< sampleType >::initValues(), Parameters::isFilter(), GeopsyCore::TimeRange::lengthSeconds(), misfitFunk(), MSG_ID, GeopsyCore::Signal::nameComponent(), QGpCoreTools::Curve< pointType >::resize(), GeopsyCore::DoubleSignal::restoreType(), GeopsyCore::DoubleSignal::saveType(), GeopsyCore::DoubleSignal::setDeltaT(), SciFigs::Axis::setRange(), SciFigs::TextEdit::setText(), QGpCoreTools::sin(), QGpCoreTools::sqrt(), GeopsyCore::TimeRange::start(), GeopsyCore::DoubleSignal::subtractValue(), GeopsyCore::Signal::t0(), Parameters::timeRange(), Parameters::toString(), QGpCoreTools::tr(), TRACE, UNLOCK_SAMPLES, SciFigs::TextEdit::update(), w, Parameters::windowLength(), QGpCoreTools::Point2D::x(), QGpCoreTools::Rect::x1(), QGpCoreTools::Rect::x2(), SciFigs::AxisWindow::xAxis(), QGpCoreTools::Point2D::y(), QGpCoreTools::Rect::y1(), QGpCoreTools::Rect::y2(), and SciFigs::AxisWindow::yAxis().
{ TRACE; _log=param.toString(); _averageCurveLayers[ig]->clear(); _stddevCurveLayers[ig]->clear(); _fitCurveLayers[ig]->clear(); // Cut the time window to process TimeRange tw=param.timeRange().absoluteRange(sig); double dt=sig->deltaT(); int nSampSig=(int)round((tw.end()-tw.start())/dt); int nSampWin=(int)ceil(param.windowLength()/dt); _nSampFit=(int)ceil(param.fitLength()/dt); if(nSampWin>nSampSig) nSampWin=nSampSig; if(_nSampFit>nSampWin) { Message::warning(MSG_ID, tr("Damping toolbox"), tr("The fitting length cannot be greater than the window length. " "Continuing with a fitting length reduced to window length"), Message::ok(), true); _nSampFit=nSampWin; } // Get result vectors ready _aveCurve.clear(); Curve<Point2D> minCurve, maxCurve, fitCurve; _aveCurve.resize(nSampWin); minCurve.resize(nSampWin); maxCurve.resize(nSampWin); fitCurve.resize(_nSampFit); // Set x coordinates for curves, and init y double t=0; int iw; for(iw=0;iw < _nSampFit;iw++, t += dt) { _aveCurve[iw].setX(t); _aveCurve[iw].setY(0); minCurve[iw].setX(t); minCurve[iw].setY(0); maxCurve[iw].setX(t); maxCurve[iw].setY(0); fitCurve[iw].setX(t); fitCurve[iw].setY(0); } for( ;iw < nSampWin;iw++, t += dt) { _aveCurve[iw].setX(t); _aveCurve[iw].setY(0); minCurve[iw].setX(t); minCurve[iw].setY(0); maxCurve[iw].setX(t); maxCurve[iw].setY(0); } int nWin=0; double tau, val; // time shift relative to signal sampling const DoubleSignal * sigfft=sig->saveType(DoubleSignal::Waveform); DoubleSignal * tSig=new DoubleSignal(nSampSig); tSig->initValues(0.0, 0, nSampSig); tSig->setDeltaT(dt); tSig->copySamplesFrom(sigfft, tw.start()-sig->t0(), 0.0, tw.lengthSeconds()); tSig->subtractValue(); sig->restoreType(sigfft); if(param.isFilter()) { tSig->filter(param.filter()); } CONST_LOCK_SAMPLES(double, samp, tSig) // Stack windows (sum for ave, sum2 for min) int ns=nSampSig - nSampWin - 1; for(int is=0;is < ns;is++ ) { if(samp[ is ] <= 0 && samp[ is + 1 ] >= 0) { nWin++; if(samp[ is ]==0) tau=0; else tau=samp[ is ]/(samp[ is ] - samp[ is + 1 ] ); for(iw=1;iw < nSampWin;iw++ ) { val=samp[ is + iw ] + tau * (samp[ is + iw + 1 ] - samp[ is + iw ] ); _aveCurve[iw].setY(_aveCurve.at(iw).y() + val); minCurve[iw].setY(minCurve.at(iw).y() + val * val); } } } UNLOCK_SAMPLES(tSig); delete tSig; // Compute average and std deviation for(iw=1;iw < nSampWin;iw++ ) { val=_aveCurve.at(iw).y()/(double) nWin; _aveCurve[iw].setY(val); tau=sqrt(minCurve[iw].y()/(double) nWin - val * val); minCurve[iw].setY(val - tau); maxCurve[iw].setY(val + tau); } // Fit function A/w*e^(-Zwt)*sin(wt), A, w, Z are the unknowns // Use the downhill simplex algorithm to find the minimum // Init the algorithm with good estimates. Estimate the amplitude of signal // average at the first absolute maximum double z=0.01, a=0; int iw0=0, nw0=0; int nw=_nSampFit - 1; for(iw=1;iw < nw;iw++ ) { if(_aveCurve[iw].y() < 0 && _aveCurve[iw + 1].y() > 0) { nw0++; iw0=iw; } } if(iw0==0) { Message::warning(MSG_ID, tr("Damping"), tr("For signal %1, the first maximum cannot be found. This is " "likely that the specified time range contains no signal at all. Check the time " "limits.").arg(sig->nameComponent()), Message::cancel()); return false; } _fitW=2 * nw0 * M_PI/(iw0 * dt); // a=aveCurve->at(1).y/dt; for(iw=1;iw < _nSampFit;iw++ ) { if(fabs( _aveCurve.at(iw).y()) > a) { a=fabs(_aveCurve.at(iw).y()); iw0=iw; } } a *= _fitW/exp( -z * _fitW * iw0 * dt); // Init an initial tetrahedron double * p[ 3 ], pv[ 6 ], y[ 3 ]; p[ 0 ]=pv; p[ 1 ]=pv + 2; p[ 2 ]=pv + 4; // p[0][0]=a; // p[0][1]=w; // p[0][2]=z; // y[0]=misfitFunk(p[0]); // p[1][0]=a*1.01; // p[1][1]=w*1.1; // p[1][2]=z*1.5; // y[1]=misfitFunk(p[1]); // p[2][0]=a*0.99; // p[2][1]=w*0.9; // p[2][2]=z*0.5; // y[2]=misfitFunk(p[2]); // p[3][0]=a*1.005; // p[3][1]=w*1.05; // p[3][2]=z*1.2; // y[3]=misfitFunk(p[3]); // p[0][0]=a*0.9; // p[0][1]=w; // p[0][2]=z*0.5; // y[0]=misfitFunk(p[0]); // p[1][0]=a*1.1; // p[1][1]=p[0][1]; // p[1][2]=p[0][2]; // y[1]=misfitFunk(p[1]); // p[2][0]=a; // p[2][1]=w; // p[2][2]=p[0][2]; // y[2]=misfitFunk(p[2]); // p[3][0]=a; // p[3][1]=w; // p[3][2]=z*1.5; // y[3]=misfitFunk(p[3]); p[ 0 ][ 0 ]=a * 0.9; p[ 0 ][ 1 ]=z * 0.9; y[ 0 ]=misfitFunk(p[ 0 ] ); p[ 1 ][ 0 ]=a * 0.9; p[ 1 ][ 1 ]=z * 1.1; y[ 1 ]=misfitFunk(p[ 1 ] ); p[ 2 ][ 0 ]=a * 1.1; p[ 2 ][ 1 ]=z; y[ 2 ]=misfitFunk(p[ 2 ] ); int nfunk; amoeba(p, y, 2, 2.5e-8, misfitFunk, &nfunk); App::stream() << tr( "%1 function evaluations were necessary to converge").arg(nfunk) << endl; // Get the mean a,w and z a=0.25 * (p[ 0 ][ 0 ] + p[ 1 ][ 0 ] + p[ 2 ][ 0 ] ); z=0.25 * (p[ 0 ][ 1 ] + p[ 1 ][ 1 ] + p[ 2 ][ 1 ] ); // get the fitCurve for(iw=1;iw < _nSampFit;iw++ ) { t=fitCurve.at(iw).x(); fitCurve[iw].setY(a/_fitW * exp( -z * _fitW * t) * sin(_fitW * t) ); } // Set comments _comments[ ig ] ->setText(tr("f=%1 Hz\nz=%2%\nN win=%3") .arg(_fitW/(2 * M_PI), 0, 'f', 2) .arg(z * 100.0, 0, 'f', 4) .arg(nWin)); _comments[ ig ] ->update(); // Add curves to graph static_cast<PlotLine2D *>(_averageCurveLayers[ig]->addLine())->setCurve(_aveCurve); static_cast<PlotLine2D *>(_stddevCurveLayers[ig]->addLine())->setCurve(minCurve); static_cast<PlotLine2D *>(_stddevCurveLayers[ig]->addLine())->setCurve(maxCurve); static_cast<PlotLine2D *>(_fitCurveLayers[ig]->addLine())->setCurve(fitCurve); // Set limits correctly GraphContent * gc=_averageCurveLayers[ig]->graphContent(); AxisWindow * w=gc->graph(); Rect r=gc->boundingRect(); w->xAxis()->setRange(r.x1(), r.x2()); double maxY=-r.y1(); if(r.y2()>maxY) maxY=r.y2(); maxY*=1.05; w->yAxis()->setRange(-maxY, maxY); w->deepUpdate(); // Keep results _results[ig].frequency=_fitW/(2*M_PI); _results[ig].damping=z*100.0; _results[ig].nWindows=nWin; return true; }
void DampingResults::createObjects | ( | SubSignalPool * | subPool | ) |
References _averageCurveLayers, _comments, _fitCurveLayers, _results, _stddevCurveLayers, SciFigs::GraphicSheetMenu::addGraph(), SciFigs::GraphicSheetMenu::addText(), GeopsyCore::SubSignalPool::at(), GeopsyCore::SubSignalPool::count(), geopsyGui, GeopsyCore::Signal::nameComponent(), SciFigs::GraphicSheetMenu::setGraphGeometry(), SciFigs::Axis::setNumberPrecision(), SciFigs::Axis::setNumberPrecisionInversedScale(), SciFigs::Axis::setNumberType(), SciFigs::AbstractLine::setPen(), SciFigs::LineLayer::setReferenceLine(), SciFigs::GraphicSheet::setStatusBar(), SciFigs::Axis::setTitle(), SciFigs::Axis::setTitleInversedScale(), SciFigs::GraphicSheetMenu::sheet(), TRACE, w, SciFigs::AxisWindow::xAxis(), and SciFigs::AxisWindow::yAxis().
{ TRACE; sheet()->setStatusBar(geopsyGui->statusBar()); double y=0.5; // Resize containers to fit the number of signals int n=subPool->count(); _comments=new TextEdit* [n]; _averageCurveLayers=new LineLayer* [n]; _stddevCurveLayers=new LineLayer* [n]; _fitCurveLayers=new LineLayer* [n]; _results.resize(n); for(int ig=0; ig<n; ig++) { AxisWindow * w=addGraph(); setGraphGeometry(w, 0.5, 15.0, y, 6.0); Signal * sig=subPool->at(ig); w->xAxis()->setTitle("Time (s)"); w->xAxis()->setNumberPrecision(2); w->xAxis()->setTitleInversedScale("1/Time (1/s)"); w->xAxis()->setNumberPrecisionInversedScale(2); w->yAxis()->setTitle(sig->nameComponent()); w->yAxis()->setNumberType(Number::Scientific); w->yAxis()->setNumberPrecision(1); w->yAxis()->setTitleInversedScale(sig->nameComponent()); w->yAxis()->setNumberPrecisionInversedScale(1); PlotLine2D * line; LineLayer * layer; layer=new LineLayer(w); line=new PlotLine2D; line->setPen(Pen(Qt::black, 0.6, Qt::SolidLine)); layer->setReferenceLine(line); layer->setObjectName("average"); _averageCurveLayers[ig]=layer; layer=new LineLayer(w); line=new PlotLine2D; line->setPen(Pen(Qt::black, 0.6, Qt::DotLine)); layer->setReferenceLine(line); layer->setObjectName("stddev"); _stddevCurveLayers[ig]=layer; layer=new LineLayer(w); line=new PlotLine2D; line->setPen(Pen(Qt::red, 0.3, Qt::SolidLine)); layer->setReferenceLine(line); layer->setObjectName("fit"); _fitCurveLayers[ig]=layer; _comments[ig]=addText(16, y, 4, 5.0); _results[ig].name=sig->nameComponent(); y+=6.0; } }
double DampingResults::misfitFunk | ( | double | x[] | ) | [static, protected] |
Damping sinusoide to fit to calculated data, returns a misfit Used with call back in amoeba
References _aveCurve, _nSampFit, A, QGpCoreTools::exp(), misfit(), QGpCoreTools::sin(), TRACE, w, and Z.
Referenced by compute().
void DampingResults::save | ( | QString | fileName = QString::null | ) | [slot] |
References _log, _results, QGpCoreTools::endl(), MSG_ID, QGpCoreTools::tr(), and TRACE.
Referenced by DampingResults().
{ TRACE; if(fileName.isEmpty()) { fileName=Message::getSaveFileName(tr("Save results"), tr("Damping results (*.damping)")); } if(fileName.isEmpty()) { return; } QString message; QFileInfo fi(fileName); if(fi.exists()) { message += tr( "File %1 already exists.\n" ).arg(fi.filePath()); } QDir d(fi.absolutePath()); QFileInfo filog(d.absoluteFilePath(fi.baseName() + ".log" )); if(filog.exists()) { message += tr( "File %1 already exists.\n" ).arg(filog.filePath()); } if(!message.isEmpty()) { if(Message::warning(MSG_ID, tr( "Saving result files" ), tr( "%1\nDo you want to replace it(them)?" ).arg(message), Message::no(), Message::yes(), true)==Message::Answer0) return; } // Save a log file with parameters QFile flog(filog.filePath()); if( !flog.open(QIODevice::WriteOnly) ) { Message::warning(MSG_ID, tr( "Saving log file" ), tr( "Unable to open file %1 for writing" ).arg(filog.filePath()), Message::cancel(), true); return; } QTextStream slog(&flog); slog << "### Parameters ###\n" << _log << "### End Parameters ###" << endl; // Save a result file with frequency, damping, number of windows QFile fres(fileName); if( !fres.open(QIODevice::WriteOnly) ) { Message::warning(MSG_ID, tr( "Saving result file" ), tr( "Unable to open file %1 for writing" ).arg(fileName), Message::cancel(), true); return; } QTextStream sres(&fres); sres << "# Name | Frequency | Damping | Number of windows" << endl; for(QVector<Result>::iterator it=_results.begin();it!=_results.end(); it++) { sres << it->name << "\t" << QString::number(it->frequency) << "\t" << QString::number(it->damping) << "\t" << QString::number(it->nWindows) << endl; } }
void DampingResults::setWindowTitle | ( | QString | title | ) | [inline] |
{GraphicSheetMenu::setWindowTitle(title);}
Curve< Point2D > DampingResults::_aveCurve [static, protected] |
Referenced by compute(), and misfitFunk().
LineLayer** DampingResults::_averageCurveLayers [protected] |
Referenced by compute(), createObjects(), and ~DampingResults().
TextEdit** DampingResults::_comments [protected] |
Referenced by compute(), createObjects(), and ~DampingResults().
LineLayer** DampingResults::_fitCurveLayers [protected] |
Referenced by compute(), createObjects(), and ~DampingResults().
double DampingResults::_fitW = 0 [static, protected] |
Referenced by compute().
QString DampingResults::_log [protected] |
int DampingResults::_nSampFit = 0 [static, protected] |
Referenced by compute(), and misfitFunk().
QVector<Result> DampingResults::_results [protected] |
Referenced by compute(), createObjects(), and save().
LineLayer** DampingResults::_stddevCurveLayers [protected] |
Referenced by compute(), createObjects(), and ~DampingResults().
QMenu* DampingResults::menuTools |
Referenced by DampingResults().