From 77305f09753a0414ae0090ed1ad966b7414b92bb Mon Sep 17 00:00:00 2001 From: Carl Philipp Klemm <philipp@uvos.xyz> Date: Tue, 17 Jan 2023 14:22:24 +0100 Subject: [PATCH] eistype: add operators to do math operations on DataPoints as complex numbers, add eisNyquistDistance --- eisgenerator/eistype.h | 42 ++++++++++++++++++++++++++++++++-- eistype.cpp | 52 ++++++++++++++++++++++++++++++++++-------- 2 files changed, 83 insertions(+), 11 deletions(-) diff --git a/eisgenerator/eistype.h b/eisgenerator/eistype.h index 6224047..c1c0466 100644 --- a/eisgenerator/eistype.h +++ b/eisgenerator/eistype.h @@ -2,6 +2,7 @@ #include <complex> #include <vector> #include <cassert> +#include <cmath> typedef double fvalue; @@ -12,10 +13,45 @@ class DataPoint public: std::complex<fvalue> im; fvalue omega; - bool operator==(const DataPoint& in) + DataPoint() = default; + DataPoint(std::complex<fvalue> imIn, fvalue omegaIn = 0): im(imIn), omega(omegaIn){} + bool operator==(const DataPoint& in) const { return im == in.im; } + DataPoint operator-(const DataPoint& in) const + { + DataPoint out(*this); + out.im = out.im - in.im; + return out; + } + DataPoint operator+(const DataPoint& in) const + { + DataPoint out(*this); + out.im = out.im + in.im; + return out; + } + DataPoint operator/(fvalue in) const + { + DataPoint out(*this); + out.im = out.im / in; + return out; + } + DataPoint operator*(fvalue in) const + { + DataPoint out(*this); + out.im = out.im * in; + return out; + } + DataPoint operator/=(fvalue in) + { + im = im / in; + return *this; + } + fvalue complexVectorLength() const + { + return std::sqrt(std::pow(im.real(), 2) + std::pow(im.imag(), 2)); + } }; class Range @@ -75,6 +111,8 @@ public: bool saveToDisk(const std::vector<DataPoint>& data, const std::string& fileName, std::string headStr = ""); -double eisDistance(const std::vector<eis::DataPoint>& a, const std::vector<eis::DataPoint>& b); +fvalue eisDistance(const std::vector<eis::DataPoint>& a, const std::vector<eis::DataPoint>& b); + +fvalue eisNyquistDistance(const std::vector<eis::DataPoint>& a, const std::vector<eis::DataPoint>& b); } diff --git a/eistype.cpp b/eistype.cpp index 6276fdd..5c43785 100644 --- a/eistype.cpp +++ b/eistype.cpp @@ -1,6 +1,7 @@ #include "eistype.h" #include <fstream> #include <sstream> +#include <algorithm> #include "strops.h" #include "log.h" @@ -22,9 +23,7 @@ bool eis::saveToDisk(const std::vector<DataPoint>& data, const std::string& file file<<"omega,real,im\n"; for(const eis::DataPoint& point : data) - { file<<point.omega<<','<<point.im.real()<<','<<point.im.imag()<<'\n'; - } file.close(); return true; } @@ -61,13 +60,13 @@ std::vector<Range> eis::Range::rangesFromParamString(const std::string& paramStr { ranges[i] = Range(std::stod(subTokens[0]), std::stod(subTokens[1]), count, log); if(subTokens.size() > 2) - Log(Log::WARN)<<"invalid parameter string "<<paramStr<<" more that two arguments at range "<<i; + throw std::invalid_argument(""); } } catch(const std::invalid_argument& ia) { - Log(Log::WARN)<<"invalid parameter string "<<paramStr; + throw std::invalid_argument("invalid parameter string \"{"+ paramStr + "}\""); } } return ranges; @@ -79,9 +78,11 @@ std::string eis::Range::getString() const ss<<start; if(count > 1) + { ss<<'~'<<end; - if(log) - ss<<'L'; + if(log) + ss<<'L'; + } return ss.str(); } @@ -95,7 +96,8 @@ bool eis::Range::isSane() const return true; } -double eis::eisDistance(const std::vector<eis::DataPoint>& a, const std::vector<eis::DataPoint>& b) +//Compute simmuliarity on a bode plot +fvalue eis::eisDistance(const std::vector<eis::DataPoint>& a, const std::vector<eis::DataPoint>& b) { assert(a.size() == b.size()); @@ -104,7 +106,39 @@ double eis::eisDistance(const std::vector<eis::DataPoint>& a, const std::vector< { double diffRe = std::pow(b[i].im.real() - a[i].im.real(), 2); double diffIm = std::pow(b[i].im.imag() - a[i].im.imag(), 2); - accum += std::sqrt(diffRe+diffIm); + accum += diffRe+diffIm; + } + return sqrt(accum/a.size()); +} + +//Compute simmuliarity on a nyquist plot +fvalue eis::eisNyquistDistance(const std::vector<eis::DataPoint>& a, const std::vector<eis::DataPoint>& b) +{ + assert(a.size() > 2 && b.size() > 3); + double accum = 0; + for(size_t i = 0; i < a.size(); ++i) + { + std::vector<std::pair<double, const eis::DataPoint*>> distances; + for(size_t j = 0; j < b.size(); ++j) + { + double diffRe = std::pow(b[j].im.real() - a[i].im.real(), 2); + double diffIm = std::pow(b[j].im.imag() - a[i].im.imag(), 2); + std::pair<double, const eis::DataPoint*> dp; + dp.first = sqrt(diffRe+diffIm); + dp.second = &b[j]; + distances.push_back(dp); + } + std::sort(distances.begin(), distances.end(), + [](const std::pair<double, const eis::DataPoint*>& a, const std::pair<double, const eis::DataPoint*>& b) -> bool + {return a.first < b.first;}); + + eis::DataPoint base = (*distances[0].second)-(*distances[1].second); + base = base/base.complexVectorLength(); + eis::DataPoint diff = (*distances[0].second)-a[i]; + diff = diff/diff.complexVectorLength(); + fvalue dprod = base.im.real()*diff.im.real() + base.im.imag()*diff.im.imag(); + fvalue dist = diff.complexVectorLength()*(1-dprod); + accum += std::pow(dist, 2); } - return accum/a.size(); + return std::sqrt(accum/a.size()); } -- GitLab