707 lines
18 KiB
C++
707 lines
18 KiB
C++
/********************************************************
|
|
* ██████╗ ██████╗████████╗██╗
|
|
* ██╔════╝ ██╔════╝╚══██╔══╝██║
|
|
* ██║ ███╗██║ ██║ ██║
|
|
* ██║ ██║██║ ██║ ██║
|
|
* ╚██████╔╝╚██████╗ ██║ ███████╗
|
|
* ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝
|
|
* Geophysical Computational Tools & Library (GCTL)
|
|
*
|
|
* Copyright (c) 2022 Yi Zhang (yizhang-geo@zju.edu.cn)
|
|
*
|
|
* GCTL is distributed under a dual licensing scheme. You can redistribute
|
|
* it and/or modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation, either version 2
|
|
* of the License, or (at your option) any later version. You should have
|
|
* received a copy of the GNU Lesser General Public License along with this
|
|
* program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* If the terms and conditions of the LGPL v.2. would prevent you from using
|
|
* the GCTL, please consider the option to obtain a commercial license for a
|
|
* fee. These licenses are offered by the GCTL's original author. As a rule,
|
|
* licenses are provided "as-is", unlimited in time for a one time fee. Please
|
|
* send corresponding requests to: yizhang-geo@zju.edu.cn. Please do not forget
|
|
* to include some description of your company and the realm of its activities.
|
|
* Also add information on how to contact you by electronic and paper mail.
|
|
******************************************************/
|
|
|
|
#include "signal.h"
|
|
|
|
#ifdef GCTL_SEISMIC_MATHGL
|
|
|
|
gctl::SIG_PLOT::SIG_PLOT()
|
|
{
|
|
sig_ptr = nullptr;
|
|
}
|
|
|
|
gctl::SIG_PLOT::~SIG_PLOT(){}
|
|
|
|
void gctl::SIG_PLOT::link_source(SIG_UNIT *sig, std::string filename)
|
|
{
|
|
sig_ptr = sig; file = filename;
|
|
return;
|
|
}
|
|
|
|
int gctl::SIG_PLOT::Draw(mglGraph *gr)
|
|
{
|
|
gctl::array<double> x;
|
|
x.sequence(sig_ptr->rt0, sig_ptr->delta, sig_ptr->val.size());
|
|
|
|
mglData x_d, y_d;
|
|
x_d.Set(x.get(), x.size());
|
|
y_d.Set(sig_ptr->val.get(), sig_ptr->val.size());
|
|
|
|
double mean = sig_ptr->val.mean();
|
|
double mini = sig_ptr->val[0], maxi = sig_ptr->val[0];
|
|
for (size_t i = 1; i < sig_ptr->val.size(); i++)
|
|
{
|
|
mini = std::min(mini, sig_ptr->val[i]);
|
|
maxi = std::max(maxi, sig_ptr->val[i]);
|
|
}
|
|
|
|
gr->SetSize(800, 400);
|
|
gr->SetRanges(x.front(), x.back(), mini - 0.5*(mean - mini), maxi + 0.5*(maxi - mean));
|
|
gr->Title(sig_ptr->t0.time_str().c_str());
|
|
gr->Box();
|
|
gr->Axis("x");
|
|
gr->Axis("y");
|
|
gr->Grid("xy", "h:");
|
|
gr->Label('x', "Time (s)", 0.0);
|
|
gr->Plot(x_d, y_d, "B");
|
|
|
|
if (file != "null")
|
|
{
|
|
std::string tp = file.substr(file.find_last_of('.') + 1);
|
|
if (tp == "eps") gr->WriteEPS(file.c_str());
|
|
if (tp == "png") gr->WritePNG(file.c_str());
|
|
if (tp == "jpg") gr->WriteJPEG(file.c_str());
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#endif // GCTL_SEISMIC_MATHGL
|
|
|
|
void gctl::SIG_UNIT::init(int len, double init_val, double dt, UTC_TIME st, double rst)
|
|
{
|
|
val.resize(len, init_val);
|
|
delta = dt;
|
|
t0 = st;
|
|
te = st; te.add_duration((len-1)*delta);
|
|
rt0 = rst;
|
|
return;
|
|
}
|
|
|
|
void gctl::SIG_UNIT::info()
|
|
{
|
|
std::clog << "SIG_UNIT Info\n-------------\n";
|
|
std::clog << "T0: " << t0.time_str() << ", TE: " << te.time_str() << ", Rel-T: " << rt0 << " s\n";
|
|
std::clog << "Delta: " << delta << " s, Duration: " << (val.size()-1)*delta << " s, Singal-Len: " << val.size() << "\n";
|
|
std::clog << "-------------\n";
|
|
return;
|
|
}
|
|
|
|
void gctl::SIG_UNIT::save(std::string filename)
|
|
{
|
|
std::ofstream outfile;
|
|
open_outfile(outfile, filename, ".txt");
|
|
|
|
outfile << "# T0: " << t0.time_str() << "\n";
|
|
outfile << "# Rel-T0: " << rt0 << "\n";
|
|
outfile << "# Delta: " << delta << "\n";
|
|
outfile << "# Length: " << val.size() << "\n";
|
|
for (size_t i = 0; i < val.size(); i++)
|
|
{
|
|
outfile << rt0 + i*delta << " " << val[i] << "\n";
|
|
}
|
|
|
|
outfile.close();
|
|
return;
|
|
}
|
|
|
|
int gctl::SIG_UNIT::cut_section(SIG_UNIT &sig, double cst, double cet) const
|
|
{
|
|
if (cet <= cst || cst < 0 || cet > (double) (val.size() - 1)*delta)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
int c = 0;
|
|
int s_id = round(cst/delta);
|
|
int e_id = round(cet/delta);
|
|
|
|
sig.t0 = t0;
|
|
sig.te = t0;
|
|
sig.t0.add_duration(s_id*delta);
|
|
sig.te.add_duration(e_id*delta);
|
|
|
|
sig.delta = delta;
|
|
sig.val.resize(e_id - s_id + 1);
|
|
for (int i = s_id; i <= e_id; i++)
|
|
{
|
|
sig.val[c] = val[i]; c++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int gctl::SIG_UNIT::cut_section(SIG_UNIT &sig, const UTC_TIME &cst, double clen) const
|
|
{
|
|
double stt = cst.diff_sec(t0);
|
|
double ett = stt + clen;
|
|
|
|
if (ett <= stt || stt < 0 || (ett - (val.size() - 1)*delta) > 0.0005)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
int c = 0;
|
|
int s_id = round(stt/delta);
|
|
int e_id = round(ett/delta);
|
|
|
|
sig.t0 = cst;
|
|
sig.te = cst;
|
|
sig.te.add_duration(clen);
|
|
|
|
sig.delta = delta;
|
|
sig.val.resize(e_id - s_id + 1);
|
|
for (int i = s_id; i <= e_id; i++)
|
|
{
|
|
sig.val[c] = val[i]; c++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int gctl::SIG_UNIT::cut_multiple_sections(time_unit roundup, double clen, array<SIG_UNIT> &sigs)
|
|
{
|
|
UTC_TIME tmp_t, cst = t0;
|
|
cst.round_up_to(roundup);
|
|
tmp_t = cst;
|
|
|
|
UTC_TIME et = t0;
|
|
et.add_duration(delta*(val.size() - 1));
|
|
|
|
int ss = 0;
|
|
do
|
|
{
|
|
tmp_t.add_duration(clen);
|
|
if (et.diff_sec(tmp_t) >= 0) ss++;
|
|
else break;
|
|
} while (1);
|
|
|
|
sigs.resize(ss);
|
|
for (size_t i = 0; i < ss; i++)
|
|
{
|
|
if (cut_section(sigs[i], cst, clen)) return -1;
|
|
cst.add_duration(clen);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int gctl::SIG_UNIT::down_sampling(int factor)
|
|
{
|
|
if (factor < 1)
|
|
{
|
|
throw std::invalid_argument("[GCTL_SEISMIC] Invalid parameter for gctl::SIG_UNIT::down_sampling(...)");
|
|
return -1;
|
|
}
|
|
|
|
int s = 1 + (val.size() - 1)/factor;
|
|
if (s <= 1) return -1;
|
|
|
|
gctl::array<double> ret(s);
|
|
for (size_t i = 0; i < ret.size(); i++)
|
|
{
|
|
ret[i] = val[factor*i];
|
|
}
|
|
|
|
delta *= factor;
|
|
val = ret;
|
|
|
|
double dur = delta*(s - 1);
|
|
te = t0;
|
|
te.add_duration(dur);
|
|
return 0;
|
|
}
|
|
|
|
int gctl::SIG_UNIT::resampling(double dt, time_unit roundup)
|
|
{
|
|
if (fabs(dt - delta) < 0.001) return 0;
|
|
|
|
if (dt < delta)
|
|
{
|
|
throw std::invalid_argument("[GCTL_SEISMIC] Invalid parameter for gctl::SIG_UNIT::resampling(...)");
|
|
return -1;
|
|
}
|
|
|
|
UTC_TIME st = t0;
|
|
st.round_up_to(roundup);
|
|
|
|
double stt = st.diff_sec(t0);
|
|
int sid = round(stt/delta);
|
|
int dn = round(dt/delta);
|
|
|
|
int s = 0;
|
|
int id = sid;
|
|
int vnum = val.size();
|
|
while (id < vnum)
|
|
{
|
|
id += dn;
|
|
s++;
|
|
}
|
|
|
|
if (s < 2) return -1;
|
|
|
|
gctl::array<double> ret(s);
|
|
for (size_t i = 0; i < ret.size(); i++)
|
|
{
|
|
ret[i] = val[sid + i*dn];
|
|
}
|
|
|
|
val = ret;
|
|
delta = dt;
|
|
t0 = st;
|
|
|
|
double dur = delta*(s - 1);
|
|
te = t0;
|
|
te.add_duration(dur);
|
|
return 0;
|
|
}
|
|
|
|
void gctl::SIG_UNIT::remove_mean(int win_size)
|
|
{
|
|
double mean;
|
|
if (win_size <= 1)
|
|
{
|
|
mean = val.mean();
|
|
for (size_t i = 0; i < val.size(); i++)
|
|
{
|
|
val[i] -= mean;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
double sum;
|
|
int val_s = val.size();
|
|
int ht = win_size/2;
|
|
int id, cnt;
|
|
|
|
for (size_t i = 0; i < val_s; i++)
|
|
{
|
|
sum = 0.0;
|
|
cnt = 0;
|
|
for (size_t j = 0; j < win_size; j++)
|
|
{
|
|
// 一种滑动窗口算法 窗口会延时启动(小于半个窗口时不开始滑动)并提前终止(小于半个窗口时不再滑动)
|
|
//id = i + j - ht;
|
|
//if (i <= ht) id = j;
|
|
//if (val_s - i <= ht) id = val_s - win_size + j;
|
|
//sum += val[id];
|
|
|
|
id = i + j - ht;
|
|
if (id >= 0 && id < val_s) {sum += val[id]; cnt++;}
|
|
}
|
|
|
|
//val[i] -= sum/win_size;
|
|
val[i] -= sum/cnt;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
void gctl::SIG_UNIT::remove_outliers(double factor)
|
|
{
|
|
double std = val.std();
|
|
double mean = val.mean();
|
|
|
|
int vs = val.size();
|
|
for (size_t i = 0; i < vs; i++)
|
|
{
|
|
if (fabs(val[i] - mean) > factor*std)
|
|
{
|
|
val[i] = mean;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
void gctl::SIG_UNIT::normalize(double norm)
|
|
{
|
|
norm = fabs(norm);
|
|
|
|
double maxi = val[0];
|
|
double mini = val[0];
|
|
for (size_t i = 1; i < val.size(); i++)
|
|
{
|
|
maxi = std::max(maxi, val[i]);
|
|
mini = std::min(mini, val[i]);
|
|
}
|
|
|
|
for (size_t i = 0; i < val.size(); i++)
|
|
{
|
|
val[i] = 2.0*norm*(val[i] - mini)/(maxi - mini) - norm;
|
|
}
|
|
return;
|
|
}
|
|
|
|
void gctl::SIG_UNIT::normalize_1bit()
|
|
{
|
|
for (size_t i = 0; i < val.size(); i++)
|
|
{
|
|
val[i] = val[i]>0?1:-1;
|
|
}
|
|
return;
|
|
}
|
|
|
|
void gctl::SIG_UNIT::spectral_whitening(int avg_num)
|
|
{
|
|
_1d_array V;
|
|
cosine_extrapolate_1d(val, V);
|
|
|
|
int vnum = val.size();
|
|
int Vnum = V.size();
|
|
int l_num = (Vnum - vnum)/2;
|
|
|
|
_1cd_array spec;
|
|
gctl::dft_r2c_1d(V, spec);
|
|
|
|
int f_size = spec.size();
|
|
int ht = avg_num/2;
|
|
//int id;
|
|
int id, cnt;
|
|
double sum;
|
|
for (size_t i = 0; i < f_size; i++)
|
|
{
|
|
sum = 1e-8;
|
|
cnt = 0;
|
|
for (size_t j = 0; j < avg_num; j++)
|
|
{
|
|
// 一种滑动窗口算法 窗口会延时启动(小于半个窗口时不开始滑动)并提前终止(小于半个窗口时不再滑动)
|
|
id = i + j - ht;
|
|
if (i <= ht) id = j;
|
|
if (f_size - i <= ht) id = f_size - avg_num + j;
|
|
sum += sqrt(power2(spec[id].real()) + power2(spec[id].imag()));
|
|
|
|
//id = i + j - ht;
|
|
//if (id >= 0 && id < f_size) {sum += sqrt(power2(spec[id].real()) + power2(spec[id].imag())); cnt++;}
|
|
}
|
|
sum /= avg_num;
|
|
//sum /= cnt;
|
|
|
|
spec[i].real(spec[i].real()/sum);
|
|
spec[i].imag(spec[i].imag()/sum);
|
|
}
|
|
|
|
gctl::dft_c2r_1d(spec, V);
|
|
for (size_t i = 0; i < vnum; i++)
|
|
{
|
|
val[i] = V[l_num + i];
|
|
}
|
|
return;
|
|
}
|
|
|
|
void gctl::SIG_UNIT::filter(gctl::filting_type_e fi_type, gctl::filter_type_e fr_type, int order, double f1, double f2)
|
|
{
|
|
fft_filter ft(fi_type, fr_type, order, 1.0/delta, f1, f2);
|
|
|
|
array<double> ret;
|
|
ft.filter(val, ret);
|
|
|
|
val = ret;
|
|
return;
|
|
}
|
|
|
|
void gctl::SIG_UNIT::stack_sig_units(const gctl::array<SIG_UNIT*> &sigs)
|
|
{
|
|
int ls = sigs.size();
|
|
if (sigs.empty())
|
|
{
|
|
throw std::runtime_error("[GCTL_SEISMIC] Invalid stacking list for gctl::SIG_UNIT::stack_sig_units(...)");
|
|
}
|
|
|
|
for (size_t i = 0; i < ls - 1; i++)
|
|
{
|
|
if ((sigs[i]->t0 != sigs[i+1]->t0) || (sigs[i]->delta != sigs[i+1]->delta) || (sigs[i]->val.size() != sigs[i+1]->val.size()))
|
|
{
|
|
throw std::runtime_error("[GCTL_SEISMIC] Stacking singals do not match for gctl::SIG_UNIT::stack_sig_units(...)");
|
|
}
|
|
}
|
|
|
|
rt0 = sigs[0]->rt0;
|
|
t0 = sigs[0]->t0;
|
|
te = sigs[0]->te;
|
|
delta = sigs[0]->delta;
|
|
val.resize(sigs[0]->val.size());
|
|
for (size_t i = 0; i < val.size(); i++)
|
|
{
|
|
val[i] = 0.0;
|
|
for (size_t j = 0; j < ls; j++)
|
|
{
|
|
val[i] += sigs[j]->val[i];
|
|
}
|
|
val[i] /= ls;
|
|
}
|
|
return;
|
|
}
|
|
|
|
void gctl::SIG_UNIT::stack_sig_units(const array<SIG_UNIT> &sigs)
|
|
{
|
|
int ls = sigs.size();
|
|
if (sigs.empty())
|
|
{
|
|
throw std::runtime_error("[GCTL_SEISMIC] Invalid stacking list for gctl::SIG_UNIT::stack_sig_units(...)");
|
|
}
|
|
|
|
for (size_t i = 0; i < ls - 1; i++)
|
|
{
|
|
if ((sigs[i].t0 != sigs[i+1].t0) || (sigs[i].delta != sigs[i+1].delta) || (sigs[i].val.size() != sigs[i+1].val.size()))
|
|
{
|
|
throw std::runtime_error("[GCTL_SEISMIC] Stacking singals do not match for gctl::SIG_UNIT::stack_sig_units(...)");
|
|
}
|
|
}
|
|
|
|
rt0 = sigs[0].rt0;
|
|
t0 = sigs[0].t0;
|
|
te = sigs[0].te;
|
|
delta = sigs[0].delta;
|
|
val.resize(sigs[0].val.size());
|
|
for (size_t i = 0; i < val.size(); i++)
|
|
{
|
|
val[i] = 0.0;
|
|
for (size_t j = 0; j < ls; j++)
|
|
{
|
|
val[i] += sigs[j].val[i];
|
|
}
|
|
val[i] /= ls;
|
|
}
|
|
return;
|
|
}
|
|
|
|
void gctl::SIG_UNIT::stack_sig_units(const std::vector<SIG_UNIT> &sigs)
|
|
{
|
|
int ls = sigs.size();
|
|
if (sigs.empty())
|
|
{
|
|
throw std::runtime_error("[GCTL_SEISMIC] Invalid stacking list for gctl::SIG_UNIT::stack_sig_units(...)");
|
|
}
|
|
|
|
for (size_t i = 0; i < ls - 1; i++)
|
|
{
|
|
if ((sigs[i].t0 != sigs[i+1].t0) || (sigs[i].delta != sigs[i+1].delta) || (sigs[i].val.size() != sigs[i+1].val.size()))
|
|
{
|
|
throw std::runtime_error("[GCTL_SEISMIC] Stacking singals do not match for gctl::SIG_UNIT::stack_sig_units(...)");
|
|
}
|
|
}
|
|
|
|
rt0 = sigs[0].rt0;
|
|
t0 = sigs[0].t0;
|
|
te = sigs[0].te;
|
|
delta = sigs[0].delta;
|
|
val.resize(sigs[0].val.size());
|
|
for (size_t i = 0; i < val.size(); i++)
|
|
{
|
|
val[i] = 0.0;
|
|
for (size_t j = 0; j < ls; j++)
|
|
{
|
|
val[i] += sigs[j].val[i];
|
|
}
|
|
val[i] /= ls;
|
|
}
|
|
return;
|
|
}
|
|
|
|
void gctl::SIG_UNIT::merge_sig_units(const array<SIG_UNIT> &sigs)
|
|
{
|
|
if (sigs.empty()) return;
|
|
|
|
delta = sigs[0].delta;
|
|
for (size_t i = 1; i < sigs.size(); i++)
|
|
{
|
|
if (sigs[i].delta != delta)
|
|
{
|
|
throw std::runtime_error("[GCTL_SEISMIC] Can't merge signal units with different sampling rates. From gctl::SIG_UNIT::merge_sig_units(...)");
|
|
}
|
|
}
|
|
|
|
t0 = sigs[0].t0;
|
|
te = sigs[0].te;
|
|
for (size_t i = 1; i < sigs.size(); i++)
|
|
{
|
|
if (sigs[i].t0 < t0) t0 = sigs[i].t0;
|
|
if (te < sigs[i].te) te = sigs[i].te;
|
|
}
|
|
|
|
int sig_n = round(te.diff_sec(t0)/delta) + 1;
|
|
array<int> cnt(sig_n, 0);
|
|
|
|
int s_id;
|
|
val.resize(sig_n, 0.0);
|
|
for (size_t i = 0; i < sigs.size(); i++)
|
|
{
|
|
s_id = round(sigs[i].t0.diff_sec(t0)/delta);
|
|
for (size_t n = 0; n < sigs[i].val.size(); n++)
|
|
{
|
|
val[s_id+n] = (val[s_id+n]*cnt[s_id+n] + sigs[i].val[n])/(cnt[s_id+n] + 1);
|
|
cnt[s_id+n] += 1;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
void gctl::SIG_UNIT::merge_sig_units(const std::vector<SIG_UNIT> &sigs)
|
|
{
|
|
if (sigs.empty()) return;
|
|
|
|
delta = sigs[0].delta;
|
|
for (size_t i = 1; i < sigs.size(); i++)
|
|
{
|
|
if (sigs[i].delta != delta)
|
|
{
|
|
throw std::runtime_error("[GCTL_SEISMIC] Can't merge signal units with different sampling rates. From gctl::SIG_UNIT::merge_sig_units(...)");
|
|
}
|
|
}
|
|
|
|
t0 = sigs[0].t0;
|
|
te = sigs[0].te;
|
|
for (size_t i = 1; i < sigs.size(); i++)
|
|
{
|
|
if (sigs[i].t0 < t0) t0 = sigs[i].t0;
|
|
if (te < sigs[i].te) te = sigs[i].te;
|
|
}
|
|
|
|
int sig_n = round(te.diff_sec(t0)/delta) + 1;
|
|
array<int> cnt(sig_n, 0);
|
|
|
|
int s_id;
|
|
val.resize(sig_n, 0.0);
|
|
for (size_t i = 0; i < sigs.size(); i++)
|
|
{
|
|
s_id = round(sigs[i].t0.diff_sec(t0)/delta);
|
|
for (size_t n = 0; n < sigs[i].val.size(); n++)
|
|
{
|
|
val[s_id+n] = (val[s_id+n]*cnt[s_id+n] + sigs[i].val[n])/(cnt[s_id+n] + 1);
|
|
cnt[s_id+n] += 1;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
void gctl::SIG_UNIT::linear_cross_correlation(const SIG_UNIT &a, const SIG_UNIT &b)
|
|
{
|
|
if (a.t0 != b.t0 || a.val.size() != b.val.size() || fabs(a.delta - b.delta) > 1e-6 || fabs(a.rt0 - b.rt0) > 1e-6)
|
|
{
|
|
throw std::runtime_error("[GCTL_SEISMIC] Singals do not match for gctl::SIG_UNIT::linear_cross_correlation(...)");
|
|
}
|
|
|
|
int hs = a.val.size();
|
|
|
|
// There is no excat start time for a result from the linear cross correlation. So it will be set to the start of year 1900.
|
|
t0 = UTC_START;
|
|
te = UTC_START;
|
|
delta = a.delta;
|
|
rt0 = -1*(hs - 1)*delta;
|
|
val.resize(2*hs - 1);
|
|
|
|
int s, as, bs;
|
|
for (size_t i = 0; i < val.size(); i++)
|
|
{
|
|
val[i] = 0;
|
|
s = i + 1 - 2*((i+1)%hs)*(i/hs); // dot size
|
|
as = (i/hs)*((i+1)%hs); // start index for 'a' which is not moving
|
|
bs = ((2*hs-2-i)/hs)*((2*hs-1-i)%hs); // start index for 'b' which is moving
|
|
for (size_t n = 0; n < s; n++)
|
|
{
|
|
val[i] += a.val[as+n]*b.val[bs+n];
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
void gctl::SIG_UNIT::linear_cross_correlation_freq(const SIG_UNIT &a, const SIG_UNIT &b, int avg_num)
|
|
{
|
|
_1d_array A, B;
|
|
cosine_extrapolate_1d(a.val, A);
|
|
cosine_extrapolate_1d(b.val, B);
|
|
|
|
int anum = a.val.size();
|
|
int Anum = A.size();
|
|
int l_num = (Anum - anum)/2;
|
|
|
|
_1cd_array a_spec, b_spec, cohere;
|
|
gctl::dft_r2c_1d(A, a_spec);
|
|
gctl::dft_r2c_1d(B, b_spec);
|
|
|
|
int f_size = a_spec.size();
|
|
int ht = avg_num/2;
|
|
int id;
|
|
double a_sum, b_sum;
|
|
|
|
cohere.resize(f_size);
|
|
for (size_t i = 0; i < f_size; i++)
|
|
{
|
|
a_sum = b_sum = 0.0;
|
|
for (size_t j = 0; j < avg_num; j++)
|
|
{
|
|
// 一种滑动窗口算法 窗口会延时启动(小于半个窗口时不开始滑动)并提前终止(小于半个窗口时不再滑动)
|
|
id = i + j - ht;
|
|
if (i <= ht) id = j;
|
|
if (f_size - i <= ht) id = f_size - avg_num + j;
|
|
|
|
a_sum += sqrt(power2(a_spec[id].real()) + power2(a_spec[id].imag()));
|
|
b_sum += sqrt(power2(b_spec[id].real()) + power2(b_spec[id].imag()));
|
|
}
|
|
|
|
a_sum /= avg_num;
|
|
b_sum /= avg_num;
|
|
|
|
cohere[i].real(0.5*Anum*(a_spec[i].real()*b_spec[i].real() + a_spec[i].imag()*b_spec[i].imag())/(a_sum*b_sum + 1e-8));
|
|
cohere[i].imag(0.5*Anum*(a_spec[i].imag()*b_spec[i].real() - a_spec[i].real()*b_spec[i].imag())/(a_sum*b_sum + 1e-8));
|
|
}
|
|
|
|
array<double> V;
|
|
gctl::dft_c2r_1d(cohere, V);
|
|
|
|
val.resize(anum);
|
|
for (size_t i = 0; i < anum; i++)
|
|
{
|
|
val[i] = V[l_num + i];
|
|
}
|
|
return;
|
|
}
|
|
|
|
void gctl::SIG_UNIT::circular_cross_correlation(const SIG_UNIT &a, const SIG_UNIT &b)
|
|
{
|
|
if (a.t0 != b.t0 || a.val.size() != b.val.size() || fabs(a.delta - b.delta) > 1e-6 || fabs(a.rt0 - b.rt0) > 1e-6)
|
|
{
|
|
throw std::runtime_error("[GCTL_SEISMIC] Singals do not match for gctl::SIG_UNIT::circular_cross_correlation(...)");
|
|
}
|
|
|
|
int hs = a.val.size();
|
|
|
|
t0 = a.t0;
|
|
te = a.te;
|
|
rt0 = a.rt0;
|
|
delta = a.delta;
|
|
val.resize(hs);
|
|
|
|
int bs;
|
|
for (size_t i = 0; i < hs; i++)
|
|
{
|
|
val[i] = 0;
|
|
bs = (hs - i)%hs;
|
|
for (size_t n = 0; n < hs; n++)
|
|
{
|
|
val[i] += a.val[n]*b.val[(bs+n)%hs];
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
#ifdef GCTL_SEISMIC_MATHGL
|
|
|
|
int gctl::SIG_UNIT::plot(std::string filename)
|
|
{
|
|
plt.link_source(this, filename);
|
|
mglFLTK gr(&plt, "SIG_UNIT plot");
|
|
return gr.Run();
|
|
}
|
|
|
|
#endif // GCTL_SEISMIC_MATHGL
|