├── subprojects ├── sqlitewriter.wrap ├── nlohmann_json.wrap ├── doctest.wrap └── argparse.wrap ├── .gitignore ├── README.md ├── metachan.cc ├── meson.build ├── LICENSE ├── brent.hh ├── amoeba.h ├── streamint.cc └── nr3.h /subprojects/sqlitewriter.wrap: -------------------------------------------------------------------------------- 1 | [wrap-git] 2 | url = https://github.com/berthubert/sqlitewrite.git 3 | revision = head 4 | depth = 1 5 | 6 | [provide] 7 | sqlitewriter = sqlitewriter_dep 8 | -------------------------------------------------------------------------------- /subprojects/nlohmann_json.wrap: -------------------------------------------------------------------------------- 1 | [wrap-file] 2 | directory = nlohmann_json-3.11.2 3 | lead_directory_missing = true 4 | source_url = https://github.com/nlohmann/json/releases/download/v3.11.2/include.zip 5 | source_filename = nlohmann_json-3.11.2.zip 6 | source_hash = e5c7a9f49a16814be27e4ed0ee900ecd0092bfb7dbfca65b5a421b774dccaaed 7 | wrapdb_version = 3.11.2-1 8 | 9 | [provide] 10 | nlohmann_json = nlohmann_json_dep 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | -------------------------------------------------------------------------------- /subprojects/doctest.wrap: -------------------------------------------------------------------------------- 1 | [wrap-file] 2 | directory = doctest-2.4.11 3 | source_url = https://github.com/doctest/doctest/archive/refs/tags/v2.4.11.tar.gz 4 | source_filename = doctest-2.4.11.tar.gz 5 | source_hash = 632ed2c05a7f53fa961381497bf8069093f0d6628c5f26286161fbd32a560186 6 | source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/doctest_2.4.11-1/doctest-2.4.11.tar.gz 7 | wrapdb_version = 2.4.11-1 8 | 9 | [provide] 10 | dependency_names = doctest 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # voltmon 2 | Store, analyse and report on streaming voltage data 3 | 4 | # Idea 5 | Collect data at highest possible resolution and bitrate 6 | Prefix with metadata 7 | 8 | # Inspiration 9 | * https://www.analog.com/en/products/ade9430.html 10 | 11 | * https://www.mdpi.com/1424-8220/22/20/7769 - measurement techniques 12 | 13 | * 22kOhm input impedance for hifiberry: https://support.hifiberry.com/hc/en-us/community/posts/4404557297169-Data-Acquisition 14 | 15 | 16 | -------------------------------------------------------------------------------- /subprojects/argparse.wrap: -------------------------------------------------------------------------------- 1 | [wrap-file] 2 | directory = argparse-3.0 3 | source_url = https://github.com/p-ranav/argparse/archive/refs/tags/v3.0.tar.gz 4 | source_filename = argparse-3.0.tar.gz 5 | source_hash = ba7b465759bb01069d57302855eaf4d1f7d677f21ad7b0b00b92939645c30f47 6 | patch_filename = argparse_3.0-1_patch.zip 7 | patch_url = https://wrapdb.mesonbuild.com/v2/argparse_3.0-1/get_patch 8 | patch_hash = f83ed766f07c830d3922676c67959f2078a055c07bd360f19e0e114d375d1037 9 | source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/argparse_3.0-1/argparse-3.0.tar.gz 10 | wrapdb_version = 3.0-1 11 | 12 | [provide] 13 | argparse = argparse_dep 14 | -------------------------------------------------------------------------------- /metachan.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "nlohmann/json.hpp" 4 | #include 5 | #include "misc.hh" 6 | 7 | int main() 8 | { 9 | struct msmt { 10 | int32_t l; 11 | int32_t r; 12 | }; 13 | static_assert(sizeof(msmt)==8); 14 | 15 | nlohmann::json j = nlohmann::json::object(); 16 | j["datarate"]=192000; 17 | j["channels"]=1; 18 | j["format"]="S32_LE"; 19 | j["source"]="power"; 20 | j["starttime"]=getSubsecUnixTime(); 21 | printf("%s\n", j.dump().c_str()); 22 | fflush(stdout); 23 | msmt m; 24 | while(fread(&m, 1, sizeof(m), stdin) == 8) { 25 | if(fwrite(&m.r, 1, 4, stdout) != 4) 26 | break; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project('voltmon', 'cpp', default_options : ['cpp_std=c++17']) 2 | 3 | sqlitedep = dependency('sqlite3', version : '>3') 4 | thread_dep = dependency('threads') 5 | json_dep = dependency('nlohmann_json') 6 | fmt_dep = dependency('fmt', static: true) 7 | 8 | #cpphttplib = dependency('cpp-httplib') 9 | sqlitewriter_dep = dependency('sqlitewriter', static: true) 10 | doctest_dep=dependency('doctest') 11 | #simplesockets_dep = dependency('simplesockets', static: true) 12 | argparse_dep = dependency('argparse', version: '>=3') 13 | 14 | executable('streamint', 'streamint.cc', 'misc.cc', 15 | dependencies: [sqlitedep, json_dep, fmt_dep, sqlitewriter_dep,argparse_dep]) 16 | 17 | executable('metachan', 'metachan.cc', 'misc.cc', 18 | dependencies: [argparse_dep, json_dep]) 19 | 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 bert hubert 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /brent.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include "nr3.h" 5 | 6 | struct Brent { 7 | double ax,bx,cx; 8 | inline void shft3(double &a, double &b, double &c, const double d) 9 | { 10 | a=b; 11 | b=c; 12 | c=d; 13 | } 14 | 15 | double xmin,fmin; 16 | const double tol; 17 | Brent(const double toll=3.0e-8) : tol(toll) {} 18 | 19 | template 20 | double minimize(T &func) 21 | { 22 | const int ITMAX=100; 23 | const double CGOLD=0.3819660; 24 | const double ZEPS=std::numeric_limits::epsilon()*1.0e-3; 25 | double a,b,d=0.0,etemp,fu,fv,fw,fx; 26 | double p,q,r,tol1,tol2,u,v,w,x,xm; 27 | double e=0.0; 28 | 29 | a=(ax < cx ? ax : cx); 30 | b=(ax > cx ? ax : cx); 31 | x=w=v=bx; 32 | fw=fv=fx=func(x); 33 | for (int iter=0;iter tol1) { 41 | r=(x-w)*(fx-fv); 42 | q=(x-v)*(fx-fw); 43 | p=(x-v)*q-(x-w)*r; 44 | q=2.0*(q-r); 45 | if (q > 0.0) p = -p; 46 | q=abs(q); 47 | etemp=e; 48 | e=d; 49 | if (abs(p) >= abs(0.5*q*etemp) || p <= q*(a-x) 50 | || p >= q*(b-x)) 51 | d=CGOLD*(e=(x >= xm ? a-x : b-x)); 52 | else { 53 | d=p/q; 54 | u=x+d; 55 | if (u-a < tol2 || b-u < tol2) 56 | d=SIGN(tol1,xm-x); 57 | } 58 | } else { 59 | d=CGOLD*(e=(x >= xm ? a-x : b-x)); 60 | } 61 | u=(abs(d) >= tol1 ? x+d : x+SIGN(tol1,d)); 62 | fu=func(u); 63 | if (fu <= fx) { 64 | if (u >= x) a=x; else b=x; 65 | shft3(v,w,x,u); 66 | shft3(fv,fw,fx,fu); 67 | } else { 68 | if (u < x) a=u; else b=u; 69 | if (fu <= fw || w == x) { 70 | v=w; 71 | w=u; 72 | fv=fw; 73 | fw=fu; 74 | } else if (fu <= fv || v == x || v == w) { 75 | v=u; 76 | fv=fu; 77 | } 78 | } 79 | } 80 | throw std::runtime_error("Too many iterations in brent"); 81 | } 82 | }; 83 | -------------------------------------------------------------------------------- /amoeba.h: -------------------------------------------------------------------------------- 1 | bool g_pleaseStop; 2 | 3 | struct Amoeba { 4 | const Doub ftol; 5 | Int nfunc; 6 | Int mpts; 7 | Int ndim; 8 | Doub fmin; 9 | VecDoub y; 10 | MatDoub p; 11 | Amoeba(const Doub ftoll) : ftol(ftoll) {} 12 | template 13 | VecDoub minimize(VecDoub_I &point, const Doub del, T &func) 14 | { 15 | VecDoub dels(point.size(),del); 16 | return minimize(point,dels,func); 17 | } 18 | template 19 | VecDoub minimize(VecDoub_I &point, VecDoub_I &dels, T &func) 20 | { 21 | Int ndim=point.size(); 22 | MatDoub pp(ndim+1,ndim); 23 | for (Int i=0;i 31 | VecDoub minimize(MatDoub_I &pp, T &func) 32 | { 33 | const Int NMAX=64; 34 | const Doub TINY=1.0e-10; 35 | Int ihi,ilo,inhi; 36 | mpts=pp.nrows(); 37 | ndim=pp.ncols(); 38 | VecDoub psum(ndim),pmin(ndim),x(ndim); 39 | p=pp; 40 | y.resize(mpts); 41 | for (Int i=0;iy[1] ? (inhi=1,0) : (inhi=0,1); 52 | 53 | 54 | 55 | for (Int i=0;i y[ihi]) { 58 | inhi=ihi; 59 | ihi=i; 60 | } else if (y[i] > y[inhi] && i != ihi) inhi=i; 61 | } 62 | 63 | if (!(nfunc%NMAX)) { 64 | // cout << y[ihi] << " - " << y[ilo] << endl; 65 | } 66 | 67 | Doub rtol=2.0*abs(y[ihi]-y[ilo])/(abs(y[ihi])+abs(y[ilo])+TINY); 68 | if (rtol < ftol || g_pleaseStop) { 69 | SWAP(y[0],y[ilo]); 70 | for (Int i=0;i= y[inhi]) { 82 | Doub ysave=y[ihi]; 83 | ytry=amotry(p,y,psum,ihi,0.5,func); 84 | if (ytry >= ysave) { 85 | for (Int i=0;i 108 | Doub amotry(MatDoub_IO &p, VecDoub_O &y, VecDoub_IO &psum, 109 | const Int ihi, const Doub fac, T &func) 110 | { 111 | VecDoub ptry(ndim); 112 | Doub fac1=(1.0-fac)/ndim; 113 | Doub fac2=fac1-fac; 114 | for (Int j=0;j 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "sqlwriter.hh" 10 | #include 11 | #include "nlohmann/json.hpp" 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "misc.hh" 17 | 18 | using namespace boost::accumulators; 19 | using namespace std; 20 | #include "nr3.h" 21 | #include "amoeba.h" 22 | #include "brent.hh" 23 | 24 | /* 25 | Receiver of a stream of best data we can get (32 bit, 192kHz for example). 26 | We do anomaly detection at this prime data rate, since it allows us to see the most. 27 | We have a ringbuffer of the full data 28 | 29 | We study every second independently 30 | If there is an anomaly, emit past few seconds at high resolution, and continue emitting for a few seconds more. If there are subsequent anomalies, extend the period. 31 | 32 | */ 33 | 34 | int32_t getVal(const vector& vals, int hz, double t, double w) 35 | { 36 | int64_t begin = (t - w/2) * hz; 37 | int64_t end = (t + w/2) * hz; 38 | if(begin < 0) 39 | return *vals.begin(); 40 | 41 | if(end + 1 >= (int64_t)vals.size()) 42 | return *vals.rbegin(); 43 | 44 | if(begin == end) 45 | return vals.at(begin); 46 | 47 | int64_t s = 0; 48 | for(size_t pos = begin; pos < (size_t)end; ++pos) // this is the dumb average 49 | s += vals.at(pos); 50 | return s / (end - begin); 51 | } 52 | 53 | vector getVals(const vector& vals, int hz, double begin, double end, double step) 54 | { 55 | vector ret; 56 | ret.reserve((end-begin)/step); 57 | for(double t = begin ; t < end; t+= step) 58 | ret.push_back(getVal(vals,hz,t, step)); 59 | return ret; 60 | } 61 | 62 | double vdiff(const vector& a, const vector& b) 63 | { 64 | if(a.size() != b.size()) 65 | throw std::runtime_error("Unequal size"); 66 | double diff=0; 67 | for(size_t pos = 0; pos < a.size(); ++pos) 68 | diff += abs(b[pos] - a[pos]); 69 | return diff; 70 | } 71 | double sdiff(const vector& a, const vector& b) 72 | { 73 | if(a.size() != b.size()) 74 | throw std::runtime_error("Unequal size"); 75 | double diff=0; 76 | for(size_t pos = 0; pos < a.size(); ++pos) 77 | diff += pow(b[pos] - a[pos], 2); 78 | return diff; 79 | } 80 | 81 | double sexcess(const vector& a, const vector& b, double lim) 82 | { 83 | if(a.size() != b.size()) 84 | throw std::runtime_error("Unequal size"); 85 | 86 | uint32_t excess = 0; 87 | for(size_t pos = 0; pos < a.size(); ++pos) 88 | if(abs(b[pos] - a[pos]) > fabs(lim)) 89 | excess++; 90 | return 1.0*excess/a.size(); 91 | } 92 | 93 | double maxdiff(const vector& a, const vector& b) 94 | { 95 | if(a.size() != b.size()) 96 | throw std::runtime_error("Unequal size"); 97 | 98 | uint32_t mdiff=0; 99 | for(size_t pos = 0; pos < a.size(); ++pos) { 100 | uint32_t diff = abs(b[pos] - a[pos]); 101 | if(diff > mdiff) 102 | mdiff = diff; 103 | } 104 | return mdiff; 105 | } 106 | 107 | 108 | double asum(const vector& a) 109 | { 110 | double ret = 0; 111 | for(const auto& v : a) 112 | ret += abs(v); 113 | return ret; 114 | } 115 | 116 | 117 | void getData(FILE* fp, vector& data, uint32_t samples) 118 | { 119 | data.resize(samples); 120 | int rc = fread(&data[0], 4, samples, fp); 121 | if(rc >= 0) 122 | data.resize(rc); 123 | else 124 | throw std::runtime_error("fread: "+string(strerror(errno))); 125 | } 126 | 127 | int main(int argc, char** argv) 128 | { 129 | unsigned int hz=0; 130 | unsigned int channels=0; 131 | string format; 132 | string source; 133 | double startTime=0; 134 | try { 135 | string line; 136 | getline(cin, line); 137 | nlohmann::json meta; 138 | 139 | meta = nlohmann::json::parse(line); 140 | meta.at("datarate").get_to(hz); 141 | meta.at("channels").get_to(channels); 142 | meta.at("format").get_to(format); 143 | meta.at("source").get_to(source); 144 | meta.at("starttime").get_to(startTime); 145 | } 146 | catch(std::exception& e) { 147 | fmt::print(stderr,"Failed to parse metadata from incoming stream. Pass data through metachan first!\n"); 148 | fmt::print(stderr,"Error: {}\n", e.what()); 149 | return EXIT_FAILURE; 150 | } 151 | 152 | if(channels != 1 || format != "S32_LE") { 153 | fmt::print(stderr, "Only 1 channel signer 32 bit little endian data is supported right now\n"); 154 | return EXIT_FAILURE; 155 | } 156 | 157 | fmt::print("Source '{}' sends data at {} Hz, {} channels format {}, start time {}\n", source, hz, channels, format, startTime); 158 | 159 | SQLiteWriter sqlw("voltmon.sqlite"); 160 | fmt::print("t,tstamp,absv,minv,maxv,q01,q99,phz,phz2,relabsdev,dc,amp,offset,percexcess5,percexcess10\n"); 161 | 162 | 163 | vector data; 164 | typedef accumulator_set > bacc_t; 165 | accumulator_set > rolling_amp(tag::rolling_window::window_size = 30); 166 | 167 | 168 | for(int t=0;;++t) { 169 | getData(stdin, data, hz); 170 | if(data.size() != hz) // whole seconds only, discard last bit 171 | break; 172 | 173 | if(!t) // first second often has bad data, let's skip it 174 | continue; 175 | 176 | double step=0.0001; // 0.1ms, 10kHz, downsample 177 | auto interp = getVals(data, hz, 0.1, 0.2, step); // 0.1 seconds for Hz determination 178 | 179 | uint64_t abssum=0; 180 | int32_t minv= std::numeric_limits::max(); 181 | int32_t maxv= std::numeric_limits::min(); 182 | bacc_t acc0(quantile_probability = 0.01); 183 | bacc_t acc1(quantile_probability = 0.99); 184 | 185 | for(const auto& v : interp) { 186 | abssum += abs(v); 187 | minv = min(v, minv); 188 | maxv = max(v, maxv); 189 | acc0(v); 190 | acc1(v); 191 | } 192 | 193 | double q01= extract_result< tag::p_square_quantile >( acc0); 194 | double q99= extract_result< tag::p_square_quantile >( acc1) ; 195 | 196 | 197 | auto func = [&](double phz) { 198 | double offset = 1.0/phz; 199 | auto vals2 = getVals(data, hz, 0.1 + offset, 0.2 + offset, step); 200 | return fabs(vdiff(interp, vals2)); 201 | }; 202 | Brent b; 203 | b.ax=35; 204 | b.bx=50; 205 | b.cx=65; 206 | double phz = b.minimize(func); 207 | 208 | interp = getVals(data, hz, 0.0, 1.0, step); // whole chunk 209 | auto genWave = [&](const vector & params) 210 | { 211 | // dc + amp * sin(2*Pi*freq*(t-offset)) 212 | const double& dc = params[0]; 213 | const double& amp = params[1]; 214 | const double& freq = params[2]; 215 | const double& offset = params[3]; 216 | vector gen; 217 | gen.resize(interp.size()); 218 | 219 | // fmt::print("a {}, b {}\n", a, b); 220 | //auto out = fmt::output_file("fit-"+to_string(ctr++)+".csv"); 221 | //out.print("t,gen,interp\n"); 222 | for(size_t pos = 0 ; pos < gen.size(); ++pos) { 223 | const double t = 1.0*pos*step; 224 | gen[pos] = dc + amp * sin(2*M_PI*freq*(t-offset)); 225 | // out.print("{},{},{}\n", t, gen[pos], interp[pos]); 226 | } 227 | return gen; 228 | }; 229 | auto func2= [&](const vector& params) 230 | { 231 | auto gen = genWave(params); 232 | auto ret = vdiff(interp, gen); 233 | return ret; 234 | }; 235 | 236 | Amoeba amo(0.001); 237 | double offsethint=0; 238 | double dc=(maxv+minv)/2.0; // or use q99? 239 | for(size_t pos = 1 ; pos < 0.1*interp.size(); ++pos) { 240 | if(interp[pos-1] < dc && interp[pos] > dc) { 241 | offsethint = pos * step; 242 | break; 243 | } 244 | } 245 | // dc amp 246 | vector params{dc, (maxv-minv)/2.0, phz, offsethint}; 247 | vector deltas{0.1*(maxv-minv)/2.0, 0.1*(maxv-minv)/2.0, 0.01, 0.0001}; 248 | 249 | // do the simplex optimization 250 | vector res = amo.minimize(params, deltas, func2); 251 | 252 | // plot the fit, and see how good it really is 253 | auto gen = genWave(res); 254 | double amp = res[1]; 255 | double absreldev = sdiff(gen,interp)/asum(gen); 256 | double percexcess5 = 100.0 * sexcess(gen, interp, 0.05*res[1]); // amplitude, 5% 257 | double percexcess10 = 100.0 * sexcess(gen, interp, 0.10*res[1]); // amplitude, 10% 258 | double maxpercdev = 100.0*maxdiff(gen, interp)/res[1]; 259 | 260 | // fmt::print("{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}\n", startTime +t, 1.0*abssum/data.size(), minv, maxv, q01, q99, phz, res[2], 261 | // absreldev, res[0], res[1], res[3], percexcess5, percexcess10,maxpercdev); 262 | 263 | // fmt::print("t,tstamp,absv,minv,maxv,q01,q99,phz,phz2,relabsdev,dc,amp,offset,percexcess5,percexcess10\n"); 264 | 265 | sqlw.addValue({{"source", source}, {"t", (time_t)startTime +t}, {"tstamp", startTime + t}, {"rectime", getSubsecUnixTime()}, {"rawtime", getMonotonicUnadjustedTimeValue() + startTime}, {"absv", 1.0*abssum/data.size()}, {"minv", minv}, {"maxv", maxv}, {"q01", q01}, {"q99", q99}, {"phz", phz}, {"phz2", res[2]}, {"absreldev", absreldev}, {"dc", res[0]}, {"amp", res[1]}, {"offset", res[3]}, {"percexcess5", percexcess5}, {"percexcess10", percexcess10}, {"maxpercdev", maxpercdev}}); 266 | 267 | 268 | // fflush(stdout); 269 | 270 | rolling_amp(fabs(amp)); 271 | 272 | map> rules; 273 | rules["maxv q99"] = [&]() { return maxv > 1.05*q99; }; 274 | rules["minv q01"] = [&]() { return minv < 1.05*q01; }; 275 | rules["percexcess10"] = [&]() { return percexcess10 > 1; }; 276 | rules["percexcess5"] = [&]() { return percexcess10 > 6; }; 277 | rules["maxpercdev"] = [&]() { return maxpercdev > 11; }; 278 | rules["absreldev"] = [&]() { return absreldev > 370000; }; 279 | rules["ampdev"] = [&]() { double dev = fabs(amp)/rolling_mean(rolling_amp); return dev < 0.99 || dev > 1.01; }; 280 | 281 | set fails; 282 | for(const auto& r : rules) { 283 | if(r.second()) 284 | fails.insert(r.first); 285 | } 286 | 287 | if(!fails.empty()) { 288 | fmt::print(stderr, "Anomalies {} at {}, inmag = {}, dc = {}, amp = {}, phz2 = {}\n", 289 | fails, t, params[1], res[0], res[1], res[2]); 290 | 291 | nlohmann::json j(fails); 292 | vector raw; 293 | raw.resize(4* data.size()); 294 | raw.assign((uint8_t*)&data[0], ((uint8_t*)&data[0]) + raw.size()); 295 | 296 | sqlw.addValue({{"source", source}, {"t", (time_t)startTime +t}, {"tstamp", startTime +t}, {"hz", hz}, {"format", "S32_LE"}, {"raw", raw}, {"reasons", j.dump()}}, "dumps"); 297 | } 298 | } 299 | } 300 | -------------------------------------------------------------------------------- /nr3.h: -------------------------------------------------------------------------------- 1 | #ifndef _NR3_H_ 2 | #define _NR3_H_ 3 | 4 | //#define _CHECKBOUNDS_ 1 5 | #define _USESTDVECTOR_ 1 6 | //#define _USENRERRORCLASS_ 1 7 | //#define _TURNONFPES_ 1 8 | 9 | // all the system #include's we'll ever need 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | using namespace std; 25 | 26 | // macro-like inline functions 27 | 28 | template 29 | inline T SQR(const T a) {return a*a;} 30 | 31 | template 32 | inline const T &MAX(const T &a, const T &b) 33 | {return b > a ? (b) : (a);} 34 | 35 | inline float MAX(const double &a, const float &b) 36 | {return b > a ? (b) : float(a);} 37 | 38 | inline float MAX(const float &a, const double &b) 39 | {return b > a ? float(b) : (a);} 40 | 41 | template 42 | inline const T &MIN(const T &a, const T &b) 43 | {return b < a ? (b) : (a);} 44 | 45 | inline float MIN(const double &a, const float &b) 46 | {return b < a ? (b) : float(a);} 47 | 48 | inline float MIN(const float &a, const double &b) 49 | {return b < a ? float(b) : (a);} 50 | 51 | template 52 | inline T SIGN(const T &a, const T &b) 53 | {return b >= 0 ? (a >= 0 ? a : -a) : (a >= 0 ? -a : a);} 54 | 55 | inline float SIGN(const float &a, const double &b) 56 | {return b >= 0 ? (a >= 0 ? a : -a) : (a >= 0 ? -a : a);} 57 | 58 | inline float SIGN(const double &a, const float &b) 59 | {return (float)(b >= 0 ? (a >= 0 ? a : -a) : (a >= 0 ? -a : a));} 60 | 61 | template 62 | inline void SWAP(T &a, T &b) 63 | {T dum=a; a=b; b=dum;} 64 | 65 | // exception handling 66 | 67 | #ifndef _USENRERRORCLASS_ 68 | #define throw(message) \ 69 | {printf("ERROR: %s\n in file %s at line %d\n", message,__FILE__,__LINE__); throw(1);} 70 | #else 71 | struct NRerror { 72 | char *message; 73 | char *file; 74 | int line; 75 | NRerror(char *m, char *f, int l) : message(m), file(f), line(l) {} 76 | }; 77 | #define throw(message) throw(NRerror(message,__FILE__,__LINE__)); 78 | void NRcatch(NRerror err) { 79 | printf("ERROR: %s\n in file %s at line %d\n", 80 | err.message, err.file, err.line); 81 | exit(1); 82 | } 83 | #endif 84 | 85 | // usage example: 86 | // 87 | // try { 88 | // somebadroutine(); 89 | // } 90 | // catch(NRerror s) {NRcatch(s);} 91 | // 92 | // (You can of course substitute any other catch body for NRcatch(s).) 93 | 94 | 95 | // Vector and Matrix Classes 96 | 97 | #ifdef _USESTDVECTOR_ 98 | #define NRvector vector 99 | #else 100 | 101 | template 102 | class NRvector { 103 | private: 104 | int nn; // size of array. upper index is nn-1 105 | T *v; 106 | public: 107 | NRvector(); 108 | explicit NRvector(int n); // Zero-based array 109 | NRvector(int n, const T &a); //initialize to constant value 110 | NRvector(int n, const T *a); // Initialize to array 111 | NRvector(const NRvector &rhs); // Copy constructor 112 | NRvector & operator=(const NRvector &rhs); //assignment 113 | typedef T value_type; // make T available externally 114 | inline T & operator[](const int i); //i'th element 115 | inline const T & operator[](const int i) const; 116 | inline int size() const; 117 | void resize(int newn); // resize (contents not preserved) 118 | void assign(int newn, const T &a); // resize and assign a constant value 119 | ~NRvector(); 120 | }; 121 | 122 | // NRvector definitions 123 | 124 | template 125 | NRvector::NRvector() : nn(0), v(NULL) {} 126 | 127 | template 128 | NRvector::NRvector(int n) : nn(n), v(n>0 ? new T[n] : NULL) {} 129 | 130 | template 131 | NRvector::NRvector(int n, const T& a) : nn(n), v(n>0 ? new T[n] : NULL) 132 | { 133 | for(int i=0; i 137 | NRvector::NRvector(int n, const T *a) : nn(n), v(n>0 ? new T[n] : NULL) 138 | { 139 | for(int i=0; i 143 | NRvector::NRvector(const NRvector &rhs) : nn(rhs.nn), v(nn>0 ? new T[nn] : NULL) 144 | { 145 | for(int i=0; i 149 | NRvector & NRvector::operator=(const NRvector &rhs) 150 | // postcondition: normal assignment via copying has been performed; 151 | // if vector and rhs were different sizes, vector 152 | // has been resized to match the size of rhs 153 | { 154 | if (this != &rhs) 155 | { 156 | if (nn != rhs.nn) { 157 | if (v != NULL) delete [] (v); 158 | nn=rhs.nn; 159 | v= nn>0 ? new T[nn] : NULL; 160 | } 161 | for (int i=0; i 168 | inline T & NRvector::operator[](const int i) //subscripting 169 | { 170 | #ifdef _CHECKBOUNDS_ 171 | if (i<0 || i>=nn) { 172 | throw("NRvector subscript out of bounds"); 173 | } 174 | #endif 175 | return v[i]; 176 | } 177 | 178 | template 179 | inline const T & NRvector::operator[](const int i) const //subscripting 180 | { 181 | #ifdef _CHECKBOUNDS_ 182 | if (i<0 || i>=nn) { 183 | throw("NRvector subscript out of bounds"); 184 | } 185 | #endif 186 | return v[i]; 187 | } 188 | 189 | template 190 | inline int NRvector::size() const 191 | { 192 | return nn; 193 | } 194 | 195 | template 196 | void NRvector::resize(int newn) 197 | { 198 | if (newn != nn) { 199 | if (v != NULL) delete[] (v); 200 | nn = newn; 201 | v = nn > 0 ? new T[nn] : NULL; 202 | } 203 | } 204 | 205 | template 206 | void NRvector::assign(int newn, const T& a) 207 | { 208 | if (newn != nn) { 209 | if (v != NULL) delete[] (v); 210 | nn = newn; 211 | v = nn > 0 ? new T[nn] : NULL; 212 | } 213 | for (int i=0;i 217 | NRvector::~NRvector() 218 | { 219 | if (v != NULL) delete[] (v); 220 | } 221 | 222 | // end of NRvector definitions 223 | 224 | #endif //ifdef _USESTDVECTOR_ 225 | 226 | template 227 | class NRmatrix { 228 | private: 229 | int nn; 230 | int mm; 231 | T **v; 232 | public: 233 | NRmatrix(); 234 | NRmatrix(int n, int m); // Zero-based array 235 | NRmatrix(int n, int m, const T &a); //Initialize to constant 236 | NRmatrix(int n, int m, const T *a); // Initialize to array 237 | NRmatrix(const NRmatrix &rhs); // Copy constructor 238 | NRmatrix & operator=(const NRmatrix &rhs); //assignment 239 | typedef T value_type; // make T available externally 240 | inline T* operator[](const int i); //subscripting: pointer to row i 241 | inline const T* operator[](const int i) const; 242 | inline int nrows() const; 243 | inline int ncols() const; 244 | void resize(int newn, int newm); // resize (contents not preserved) 245 | void assign(int newn, int newm, const T &a); // resize and assign a constant value 246 | ~NRmatrix(); 247 | }; 248 | 249 | template 250 | NRmatrix::NRmatrix() : nn(0), mm(0), v(NULL) {} 251 | 252 | template 253 | NRmatrix::NRmatrix(int n, int m) : nn(n), mm(m), v(n>0 ? new T*[n] : NULL) 254 | { 255 | int i,nel=m*n; 256 | if (v) v[0] = nel>0 ? new T[nel] : NULL; 257 | for (i=1;i 261 | NRmatrix::NRmatrix(int n, int m, const T &a) : nn(n), mm(m), v(n>0 ? new T*[n] : NULL) 262 | { 263 | int i,j,nel=m*n; 264 | if (v) v[0] = nel>0 ? new T[nel] : NULL; 265 | for (i=1; i< n; i++) v[i] = v[i-1] + m; 266 | for (i=0; i< n; i++) for (j=0; j 270 | NRmatrix::NRmatrix(int n, int m, const T *a) : nn(n), mm(m), v(n>0 ? new T*[n] : NULL) 271 | { 272 | int i,j,nel=m*n; 273 | if (v) v[0] = nel>0 ? new T[nel] : NULL; 274 | for (i=1; i< n; i++) v[i] = v[i-1] + m; 275 | for (i=0; i< n; i++) for (j=0; j 279 | NRmatrix::NRmatrix(const NRmatrix &rhs) : nn(rhs.nn), mm(rhs.mm), v(nn>0 ? new T*[nn] : NULL) 280 | { 281 | int i,j,nel=mm*nn; 282 | if (v) v[0] = nel>0 ? new T[nel] : NULL; 283 | for (i=1; i< nn; i++) v[i] = v[i-1] + mm; 284 | for (i=0; i< nn; i++) for (j=0; j 288 | NRmatrix & NRmatrix::operator=(const NRmatrix &rhs) 289 | // postcondition: normal assignment via copying has been performed; 290 | // if matrix and rhs were different sizes, matrix 291 | // has been resized to match the size of rhs 292 | { 293 | if (this != &rhs) { 294 | int i,j,nel; 295 | if (nn != rhs.nn || mm != rhs.mm) { 296 | if (v != NULL) { 297 | delete[] (v[0]); 298 | delete[] (v); 299 | } 300 | nn=rhs.nn; 301 | mm=rhs.mm; 302 | v = nn>0 ? new T*[nn] : NULL; 303 | nel = mm*nn; 304 | if (v) v[0] = nel>0 ? new T[nel] : NULL; 305 | for (i=1; i< nn; i++) v[i] = v[i-1] + mm; 306 | } 307 | for (i=0; i< nn; i++) for (j=0; j 313 | inline T* NRmatrix::operator[](const int i) //subscripting: pointer to row i 314 | { 315 | #ifdef _CHECKBOUNDS_ 316 | if (i<0 || i>=nn) { 317 | throw("NRmatrix subscript out of bounds"); 318 | } 319 | #endif 320 | return v[i]; 321 | } 322 | 323 | template 324 | inline const T* NRmatrix::operator[](const int i) const 325 | { 326 | #ifdef _CHECKBOUNDS_ 327 | if (i<0 || i>=nn) { 328 | throw("NRmatrix subscript out of bounds"); 329 | } 330 | #endif 331 | return v[i]; 332 | } 333 | 334 | template 335 | inline int NRmatrix::nrows() const 336 | { 337 | return nn; 338 | } 339 | 340 | template 341 | inline int NRmatrix::ncols() const 342 | { 343 | return mm; 344 | } 345 | 346 | template 347 | void NRmatrix::resize(int newn, int newm) 348 | { 349 | int i,nel; 350 | if (newn != nn || newm != mm) { 351 | if (v != NULL) { 352 | delete[] (v[0]); 353 | delete[] (v); 354 | } 355 | nn = newn; 356 | mm = newm; 357 | v = nn>0 ? new T*[nn] : NULL; 358 | nel = mm*nn; 359 | if (v) v[0] = nel>0 ? new T[nel] : NULL; 360 | for (i=1; i< nn; i++) v[i] = v[i-1] + mm; 361 | } 362 | } 363 | 364 | template 365 | void NRmatrix::assign(int newn, int newm, const T& a) 366 | { 367 | int i,j,nel; 368 | if (newn != nn || newm != mm) { 369 | if (v != NULL) { 370 | delete[] (v[0]); 371 | delete[] (v); 372 | } 373 | nn = newn; 374 | mm = newm; 375 | v = nn>0 ? new T*[nn] : NULL; 376 | nel = mm*nn; 377 | if (v) v[0] = nel>0 ? new T[nel] : NULL; 378 | for (i=1; i< nn; i++) v[i] = v[i-1] + mm; 379 | } 380 | for (i=0; i< nn; i++) for (j=0; j 384 | NRmatrix::~NRmatrix() 385 | { 386 | if (v != NULL) { 387 | delete[] (v[0]); 388 | delete[] (v); 389 | } 390 | } 391 | 392 | template 393 | class NRMat3d { 394 | private: 395 | int nn; 396 | int mm; 397 | int kk; 398 | T ***v; 399 | public: 400 | NRMat3d(); 401 | NRMat3d(int n, int m, int k); 402 | inline T** operator[](const int i); //subscripting: pointer to row i 403 | inline const T* const * operator[](const int i) const; 404 | inline int dim1() const; 405 | inline int dim2() const; 406 | inline int dim3() const; 407 | ~NRMat3d(); 408 | }; 409 | 410 | template 411 | NRMat3d::NRMat3d(): nn(0), mm(0), kk(0), v(NULL) {} 412 | 413 | template 414 | NRMat3d::NRMat3d(int n, int m, int k) : nn(n), mm(m), kk(k), v(new T**[n]) 415 | { 416 | int i,j; 417 | v[0] = new T*[n*m]; 418 | v[0][0] = new T[n*m*k]; 419 | for(j=1; j 428 | inline T** NRMat3d::operator[](const int i) //subscripting: pointer to row i 429 | { 430 | return v[i]; 431 | } 432 | 433 | template 434 | inline const T* const * NRMat3d::operator[](const int i) const 435 | { 436 | return v[i]; 437 | } 438 | 439 | template 440 | inline int NRMat3d::dim1() const 441 | { 442 | return nn; 443 | } 444 | 445 | template 446 | inline int NRMat3d::dim2() const 447 | { 448 | return mm; 449 | } 450 | 451 | template 452 | inline int NRMat3d::dim3() const 453 | { 454 | return kk; 455 | } 456 | 457 | template 458 | NRMat3d::~NRMat3d() 459 | { 460 | if (v != NULL) { 461 | delete[] (v[0][0]); 462 | delete[] (v[0]); 463 | delete[] (v); 464 | } 465 | } 466 | 467 | 468 | // basic type names (redefine if your bit lengths don't match) 469 | 470 | typedef int Int; // 32 bit integer 471 | typedef unsigned int Uint; 472 | 473 | #ifdef _MSC_VER 474 | typedef __int64 Llong; // 64 bit integer 475 | typedef unsigned __int64 Ullong; 476 | #else 477 | typedef long long int Llong; // 64 bit integer 478 | typedef unsigned long long int Ullong; 479 | #endif 480 | 481 | typedef char Char; // 8 bit integer 482 | typedef unsigned char Uchar; 483 | 484 | typedef double Doub; // default floating type 485 | typedef long double Ldoub; 486 | 487 | typedef complex Complex; // default complex type 488 | 489 | typedef bool Bool; 490 | 491 | // NaN: uncomment one of the following 3 methods of defining a global NaN 492 | // you can test by verifying that (NaN != NaN) is true 493 | 494 | static const Doub NaN = numeric_limits::quiet_NaN(); 495 | 496 | //Uint proto_nan[2]={0xffffffff, 0x7fffffff}; 497 | //double NaN = *( double* )proto_nan; 498 | 499 | //Doub NaN = sqrt(-1.); 500 | 501 | // vector types 502 | 503 | typedef const NRvector VecInt_I; 504 | typedef NRvector VecInt, VecInt_O, VecInt_IO; 505 | 506 | typedef const NRvector VecUint_I; 507 | typedef NRvector VecUint, VecUint_O, VecUint_IO; 508 | 509 | typedef const NRvector VecLlong_I; 510 | typedef NRvector VecLlong, VecLlong_O, VecLlong_IO; 511 | 512 | typedef const NRvector VecUllong_I; 513 | typedef NRvector VecUllong, VecUllong_O, VecUllong_IO; 514 | 515 | typedef const NRvector VecChar_I; 516 | typedef NRvector VecChar, VecChar_O, VecChar_IO; 517 | 518 | typedef const NRvector VecCharp_I; 519 | typedef NRvector VecCharp, VecCharp_O, VecCharp_IO; 520 | 521 | typedef const NRvector VecUchar_I; 522 | typedef NRvector VecUchar, VecUchar_O, VecUchar_IO; 523 | 524 | typedef const NRvector VecDoub_I; 525 | typedef NRvector VecDoub, VecDoub_O, VecDoub_IO; 526 | 527 | typedef const NRvector VecDoubp_I; 528 | typedef NRvector VecDoubp, VecDoubp_O, VecDoubp_IO; 529 | 530 | typedef const NRvector VecComplex_I; 531 | typedef NRvector VecComplex, VecComplex_O, VecComplex_IO; 532 | 533 | typedef const NRvector VecBool_I; 534 | typedef NRvector VecBool, VecBool_O, VecBool_IO; 535 | 536 | // matrix types 537 | 538 | typedef const NRmatrix MatInt_I; 539 | typedef NRmatrix MatInt, MatInt_O, MatInt_IO; 540 | 541 | typedef const NRmatrix MatUint_I; 542 | typedef NRmatrix MatUint, MatUint_O, MatUint_IO; 543 | 544 | typedef const NRmatrix MatLlong_I; 545 | typedef NRmatrix MatLlong, MatLlong_O, MatLlong_IO; 546 | 547 | typedef const NRmatrix MatUllong_I; 548 | typedef NRmatrix MatUllong, MatUllong_O, MatUllong_IO; 549 | 550 | typedef const NRmatrix MatChar_I; 551 | typedef NRmatrix MatChar, MatChar_O, MatChar_IO; 552 | 553 | typedef const NRmatrix MatUchar_I; 554 | typedef NRmatrix MatUchar, MatUchar_O, MatUchar_IO; 555 | 556 | typedef const NRmatrix MatDoub_I; 557 | typedef NRmatrix MatDoub, MatDoub_O, MatDoub_IO; 558 | 559 | typedef const NRmatrix MatBool_I; 560 | typedef NRmatrix MatBool, MatBool_O, MatBool_IO; 561 | 562 | // 3D matrix types 563 | 564 | typedef const NRMat3d Mat3DDoub_I; 565 | typedef NRMat3d Mat3DDoub, Mat3DDoub_O, Mat3DDoub_IO; 566 | 567 | // Floating Point Exceptions for Microsoft compilers 568 | 569 | #ifdef _TURNONFPES_ 570 | #ifdef _MSC_VER 571 | struct turn_on_floating_exceptions { 572 | turn_on_floating_exceptions() { 573 | int cw = _controlfp( 0, 0 ); 574 | cw &=~(EM_INVALID | EM_OVERFLOW | EM_ZERODIVIDE ); 575 | _controlfp( cw, MCW_EM ); 576 | } 577 | }; 578 | turn_on_floating_exceptions yes_turn_on_floating_exceptions; 579 | #endif /* _MSC_VER */ 580 | #endif /* _TURNONFPES */ 581 | 582 | #endif /* _NR3_H_ */ 583 | 584 | --------------------------------------------------------------------------------