diff --git a/src/backend/nsl/nsl_corr.c b/src/backend/nsl/nsl_corr.c index 8a99e6e0d..02fb3c673 100644 --- a/src/backend/nsl/nsl_corr.c +++ b/src/backend/nsl/nsl_corr.c @@ -1,204 +1,205 @@ /*************************************************************************** File : nsl_corr.c Project : LabPlot Description : NSL discrete correlation functions -------------------------------------------------------------------- Copyright : (C) 2018 by Stefan Gerlach (stefan.gerlach@uni.kn) ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * ***************************************************************************/ #include "nsl_corr.h" #include "nsl_common.h" #include #include #ifdef HAVE_FFTW3 #include #endif const char* nsl_corr_type_name[] = {i18n("linear (zero-padded)"), i18n("circular")}; const char* nsl_corr_norm_name[] = {i18n("none"), i18n("biased"), i18n("unbiased"), i18n("coeff")}; int nsl_corr_correlation(double s[], size_t n, double r[], size_t m, nsl_corr_type_type type, nsl_corr_norm_type normalize, double out[]) { return nsl_corr_fft_type(s, n, r, m, type, normalize, out); } int nsl_corr_fft_type(double s[], size_t n, double r[], size_t m, nsl_corr_type_type type, nsl_corr_norm_type normalize, double out[]) { size_t i, size, N = GSL_MAX(n, m), maxlag = N - 1; if (type == nsl_corr_type_linear) size = maxlag + N; else // circular size = N; size_t oldsize = size; #ifdef HAVE_FFTW3 // already zero-pad here for FFT method and FFTW r2c size = 2*(size/2+1); #endif // zero-padded arrays double *stmp = (double*)malloc(size*sizeof(double)); if (stmp == NULL) { printf("nsl_corr_fft_type(): ERROR allocating memory for 'stmp'!\n"); return -1; } double *rtmp = (double*)malloc(size*sizeof(double)); if (rtmp == NULL) { free(stmp); printf("nsl_corr_fft_type(): ERROR allocating memory for 'rtmp'!\n"); return -1; } if (type == nsl_corr_type_linear) { for (i = 0; i < maxlag; i++) stmp[i] = 0.; for (i = 0; i < n; i++) stmp[i+maxlag] = s[i]; for (i = n+maxlag; i < size; i++) stmp[i] = 0; for (i = 0; i < m; i++) rtmp[i] = r[i]; for (i = m; i < size; i++) rtmp[i] = 0; } else { // circular for (i = 0; i < n; i++) stmp[i] = s[i]; for (i = n; i < N; i++) stmp[i] = 0.; for (i = 0; i < m; i++) rtmp[i] = r[i]; for (i = m; i < N; i++) rtmp[i] = 0.; } int status; #ifdef HAVE_FFTW3 // already wraps output status = nsl_corr_fft_FFTW(stmp, rtmp, oldsize, out); #else // GSL status = nsl_corr_fft_GSL(stmp, rtmp, size, out); #endif free(stmp); free(rtmp); /* normalization */ switch (normalize) { case nsl_corr_norm_none: break; case nsl_corr_norm_biased: for (i = 0; i < oldsize; i++) out[i] = out[i]/N; break; case nsl_corr_norm_unbiased: for (i = 0; i < oldsize; i++) { size_t norm = i < oldsize/2 ? i+1 : oldsize - i; out[i] = out[i]/norm; } break; case nsl_corr_norm_coeff: { double snorm = cblas_dnrm2((int)n, s, 1); double rnorm = cblas_dnrm2((int)m, r, 1); for (i = 0; i < oldsize; i++) out[i] = out[i]/snorm/rnorm; break; } } // reverse array for circular type if (type == nsl_corr_type_circular) { for (i = 0; i < N/2; i++) { double tmp = out[i]; out[i] = out[N - i - 1]; out[N -i - 1] = tmp; } } return status; } #ifdef HAVE_FFTW3 int nsl_corr_fft_FFTW(double s[], double r[], size_t n, double out[]) { - size_t i; - - if (n == 0) + if (n <= 0) return -1; const size_t size = 2*(n/2+1); double* in = (double*)malloc(size*sizeof(double)); fftw_plan rpf = fftw_plan_dft_r2c_1d(n, in, (fftw_complex*)in, FFTW_ESTIMATE); fftw_execute_dft_r2c(rpf, s, (fftw_complex*)s); fftw_execute_dft_r2c(rpf, r, (fftw_complex*)r); fftw_destroy_plan(rpf); + size_t i; + // multiply for (i = 0; i < size; i += 2) { double re = s[i]*r[i] + s[i+1]*r[i+1]; double im = s[i+1]*r[i] - s[i]*r[i+1]; s[i] = re; s[i+1] = im; } // back transform double* o = (double*)malloc(size*sizeof(double)); fftw_plan rpb = fftw_plan_dft_c2r_1d(n, (fftw_complex*)o, o, FFTW_ESTIMATE); fftw_execute_dft_c2r(rpb, (fftw_complex*)s, s); fftw_destroy_plan(rpb); for (i = 0; i < n; i++) out[i] = s[i]/n; + free(in); + free(o); return 0; } #endif int nsl_corr_fft_GSL(double s[], double r[], size_t n, double out[]) { gsl_fft_real_workspace *work = gsl_fft_real_workspace_alloc(n); gsl_fft_real_wavetable *real = gsl_fft_real_wavetable_alloc(n); /* FFT s and r */ gsl_fft_real_transform(s, 1, n, real, work); gsl_fft_real_transform(r, 1, n, real, work); gsl_fft_real_wavetable_free(real); size_t i; /* calculate halfcomplex product */ out[0] = s[0]*r[0]; for (i = 1; i < n; i++) { if (i%2) { /* Re */ out[i] = s[i]*r[i]; if (i < n-1) /* when n is even last value is real */ out[i] += s[i+1]*r[i+1]; } else /* Im */ out[i] = s[i]*r[i-1] - s[i-1]*r[i]; } /* back transform */ gsl_fft_halfcomplex_wavetable *hc = gsl_fft_halfcomplex_wavetable_alloc(n); gsl_fft_halfcomplex_inverse(out, 1, n, hc, work); gsl_fft_halfcomplex_wavetable_free(hc); gsl_fft_real_workspace_free(work); return 0; } - diff --git a/src/commonfrontend/widgets/DateTimeSpinBox.cpp b/src/commonfrontend/widgets/DateTimeSpinBox.cpp index cd50c1461..2125b7616 100644 --- a/src/commonfrontend/widgets/DateTimeSpinBox.cpp +++ b/src/commonfrontend/widgets/DateTimeSpinBox.cpp @@ -1,300 +1,300 @@ /*************************************************************************** File : DateTimeSpinBox.cpp Project : LabPlot Description : widget for setting datetimes with a spinbox -------------------------------------------------------------------- Copyright : (C) 2019 Martin Marmsoler (martin.marmsoler@gmail.com) ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * ***************************************************************************/ #include "DateTimeSpinBox.h" #include #include #include DateTimeSpinBox::DateTimeSpinBox(QWidget* parent) : QAbstractSpinBox(parent) { lineEdit()->setText("0000.00.00 00:00:00.001"); - stepEnabled(); + DateTimeSpinBox::stepEnabled(); m_regularExpressionValidator = new QRegularExpressionValidator(); QRegularExpression regExp("([0-9]+)\\.(0[0-9]|1[0-2]|[0-9])\\.(0[0-9]|[0-2][0-9]|30|[0-9]) ([0-1][0-9]|2[0-3]|[0-9])\\:([0-5][0-9]|[0-9])\\:([0-5][0-9]|[0-9])\\.[0-9]{0,3}"); m_regularExpressionValidator->setRegularExpression(regExp); lineEdit()->setValidator(m_regularExpressionValidator); } void DateTimeSpinBox::keyPressEvent(QKeyEvent* event) { if (event->key() >= Qt::Key_0 && event->key() <= Qt::Key_9) { int cursorPos = lineEdit()->cursorPosition(); int textLenght = lineEdit()->text().length(); QAbstractSpinBox::keyPressEvent(event); getValue(); if (lineEdit()->text().length() != textLenght) lineEdit()->setCursorPosition(cursorPos + 1); else lineEdit()->setCursorPosition(cursorPos); } else if (event->key() == Qt::Key_Up) { Type type = determineType(lineEdit()->cursorPosition()); increaseValue(type, 1); writeValue(); setCursorPosition(type); } else if (event->key() == Qt::Key_Down) { Type type = determineType(lineEdit()->cursorPosition()); increaseValue(type, -1); writeValue(); setCursorPosition(type); } else { QAbstractSpinBox::keyPressEvent(event); getValue(); } } QAbstractSpinBox::StepEnabled DateTimeSpinBox::stepEnabled() const { return QAbstractSpinBox::StepEnabledFlag::StepUpEnabled | QAbstractSpinBox::StepEnabledFlag::StepDownEnabled; // for testing } void DateTimeSpinBox::stepBy(int steps) { Type type = determineType(lineEdit()->cursorPosition()); increaseValue(type, steps); writeValue(); setCursorPosition(type); } /*! * Write value to lineEdit of the spinbox */ void DateTimeSpinBox::writeValue() { lineEdit()->setText(QString::number(m_year) + '.' + QString("%1").arg(m_month, 2, 10, QLatin1Char('0')) + QLatin1Char('.') + QString("%1").arg(m_day, 2, 10, QLatin1Char('0')) + QLatin1Char(' ') + QString("%1").arg(m_hour, 2, 10, QLatin1Char('0')) + QLatin1Char(':') + QString("%1").arg(m_minute, 2, 10, QLatin1Char('0')) + QLatin1Char(':') + QString("%1").arg(m_second, 2, 10, QLatin1Char('0')) + QLatin1Char('.') + QString("%1").arg(m_millisecond, 3, 10, QLatin1Char('0'))); emit valueChanged(); } void DateTimeSpinBox::setValue(qint64 increment) { qint64 divisor = qint64(12) * 30 * 24 * 60 * 60 * 1000; qint64 rest; m_year = increment / divisor; rest = increment - m_year * divisor; divisor = qint64(30) * 24 * 60 * 60 * 1000; m_month = rest / divisor; rest = rest - m_month * divisor; divisor = qint64(24) * 60 * 60 * 1000; m_day = rest / divisor; rest = rest - m_day * divisor; divisor = qint64(60) * 60 * 1000; m_hour = rest / divisor; rest -= m_hour * divisor; divisor = qint64(60)* 1000; m_minute = rest / divisor; rest -= m_minute * divisor; divisor = qint64(1000); m_second = rest /divisor; rest -= m_second * divisor; m_millisecond = rest; writeValue(); } qint64 DateTimeSpinBox::value() { return m_millisecond + 1000 * (m_second + 60 * (m_minute + 60 * (m_hour + 24 * (m_day + 30 * (m_month + 12 * m_year))))); } /*! * Read value from lineEdit of the spinbox */ void DateTimeSpinBox::getValue() { QString text = lineEdit()->text(); int counter = 0; int startIndex = 0; for (int i=0; i< text.length(); i++) { if (text[i] == '.' || text[i] == ':' || text[i] == ' ' || i == text.length()-1) { switch(counter) { case Type::year: m_year = text.mid(startIndex, i - startIndex).toInt(); break; case Type::month: m_month = text.mid(startIndex, i - startIndex).toInt(); break; case Type::day: m_day = text.mid(startIndex, i - startIndex).toInt(); break; case Type::hour: m_hour = text.mid(startIndex, i - startIndex).toInt(); break; case Type::minute: m_minute = text.mid(startIndex, i - startIndex).toInt(); break; case Type::second: m_second = text.mid(startIndex, i - startIndex).toInt(); break; case Type::millisecond: m_millisecond = text.mid(startIndex, i - startIndex + 1).toInt(); // because of the condition (i == text.length()-1) break; } startIndex = i+1; counter ++; } } emit valueChanged(); } void DateTimeSpinBox::setCursorPosition(Type type) { QString text = lineEdit()->text(); int counter = 0; for (int i = 0; i < text.length(); i++) { if (text[i] == '.' || text[i] == ':' || text[i] == ' ') counter ++; if (counter-1 == type) { lineEdit()->setCursorPosition(i); break; } } } bool DateTimeSpinBox::valid() { return true; } // step can also be negative bool DateTimeSpinBox::increaseValue(DateTimeSpinBox::Type type, int step) { switch (type) { case Type::year: { if (m_year + step < 0 && step < 0) { if (m_year + step < 0) { m_year = 0; return false; } } m_year += step; return true; } break; case Type::month: return changeValue(m_month, Type::year, step); break; case Type::day: return changeValue(m_day, Type::month, step); break; case Type::hour: return changeValue(m_hour, Type::day, step); break; case Type::minute: return changeValue(m_minute, Type::hour, step); break; case Type::second: return changeValue(m_second, Type::minute, step); break; case Type::millisecond: return changeValue(m_millisecond, Type::second, step); break; default: return false; break; } } bool DateTimeSpinBox::changeValue(qint64& thisType, DateTimeSpinBox::Type nextTypeType, int step) { int maxValue = 1; switch (nextTypeType) { case (Type::year): maxValue = 12; break; case (Type::month): maxValue = 30; break; case (Type::day): maxValue = 24; break; case (Type::hour): maxValue = 60; break; case (Type::minute): maxValue = 60; break; case (Type::second): maxValue = 1000; break; case (Type::millisecond): return false; } int nextTypeCounter = step / maxValue; step -= nextTypeCounter * maxValue; if (thisType + step < 0 && step < 0) { nextTypeCounter --; if (increaseValue(nextTypeType, nextTypeCounter)) { step += maxValue; thisType += step; return true; } else { thisType = 0; return false; } } else if ( thisType + step > maxValue-1 && step > 0) { step -= nextTypeCounter * maxValue; if (thisType + step > maxValue-1) { nextTypeCounter ++; step -= maxValue; thisType += step; } else thisType += step; return increaseValue(nextTypeType, nextTypeCounter); } thisType += step; return true; } DateTimeSpinBox::Type DateTimeSpinBox::determineType(int cursorPos) const{ QString text = lineEdit()->text(); if (cursorPos > text.length()) cursorPos = text.length(); int counter = 0; for (int i = 0; i < cursorPos; i++) { if (text[i] == '.' || text[i] == ':' || text[i] == ' ') counter ++; } if (counter <= Type::millisecond) return static_cast(counter); return Type::millisecond; }