Add files via upload
This commit is contained in:
107
UTSR/GenerateModelFilter.cpp
Normal file
107
UTSR/GenerateModelFilter.cpp
Normal file
@ -0,0 +1,107 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <complex>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
|
||||
// Forward declarations
|
||||
struct ScanData {
|
||||
struct CscanData {
|
||||
std::string WaveType;
|
||||
double Cl;
|
||||
double Cs;
|
||||
std::vector<double> X;
|
||||
double ProbeDiameter;
|
||||
double Frequency;
|
||||
double Bandwidth;
|
||||
std::string DefectType;
|
||||
double Diameter;
|
||||
double Tilt;
|
||||
} CscanData;
|
||||
std::vector<double> timeScale;
|
||||
std::vector<std::vector<double>> AscanValues;
|
||||
};
|
||||
|
||||
std::tuple<std::vector<std::vector<std::complex<double>>>,
|
||||
std::vector<std::vector<std::complex<double>>>,
|
||||
std::vector<std::vector<std::complex<double>>>,
|
||||
std::vector<std::complex<double>>,
|
||||
std::vector<std::complex<double>>>
|
||||
GenerateModelFilter(const ScanData& scanData,
|
||||
bool pad = true,
|
||||
double ep = 0.03,
|
||||
std::string TrFreqSp = "gaussian",
|
||||
int Rx = 1,
|
||||
double T1 = 0) {
|
||||
// Verify scanData parameter
|
||||
assert(scanData.CscanData.WaveType != "" && "scanData invalid structure");
|
||||
|
||||
// Verify input parameters
|
||||
assert(Rx > 0 && "Rx must be positive");
|
||||
assert(T1 >= 0 && "Excitation pulse width must be positive");
|
||||
|
||||
// Get scan data information
|
||||
double c = (scanData.CscanData.WaveType == "L") ? scanData.CscanData.Cl : scanData.CscanData.Cs;
|
||||
double ERMv = c / 2;
|
||||
|
||||
double scanX = scanData.CscanData.X[0] * 1e-3;
|
||||
double deltaScanX = (scanData.CscanData.X[1] - scanData.CscanData.X[0]) * 1e-3 / Rx;
|
||||
double deltaT = (scanData.timeScale[1] - scanData.timeScale[0]) * 1e-6;
|
||||
|
||||
// Get acquisition matrix sizes
|
||||
int nt0 = scanData.AscanValues.size();
|
||||
int nu0 = (scanData.AscanValues[0].size() - 1) * Rx + 1;
|
||||
|
||||
// Zero-padding
|
||||
int nt = pad ? std::pow(2, std::ceil(std::log2(nt0)) + 1) : nt0;
|
||||
int nu = pad ? 2 * nu0 : nu0;
|
||||
|
||||
// Calculate matched filters
|
||||
auto [C1, Hed] = pCalcMatchedFilter(nt, deltaT, nu, deltaScanX,
|
||||
scanData.CscanData.ProbeDiameter * 1e-3,
|
||||
scanData.CscanData.Frequency * 1e6,
|
||||
scanData.CscanData.Bandwidth * 1e6,
|
||||
ERMv, TrFreqSp, T1);
|
||||
|
||||
// Calculate flaw response
|
||||
auto SA = pCalcScatteringAmplitude(nt, deltaT, c,
|
||||
scanData.CscanData.DefectType,
|
||||
scanData.CscanData.Diameter * 1e-3 / 2,
|
||||
scanData.CscanData.Tilt);
|
||||
|
||||
// Build Model and Filter
|
||||
std::vector<std::vector<std::complex<double>>> Model(nt, std::vector<std::complex<double>>(nu));
|
||||
for (int i = 0; i < nt; ++i) {
|
||||
for (int j = 0; j < nu; ++j) {
|
||||
Model[i][j] = C1[i][j] * std::conj(Hed[i] * SA[i]);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::vector<std::complex<double>>> Filter(nt, std::vector<std::complex<double>>(nu));
|
||||
for (int i = 0; i < nt; ++i) {
|
||||
for (int j = 0; j < nu; ++j) {
|
||||
std::complex<double> AA = std::conj(C1[i][j]) / (C1[i][j] * std::conj(C1[i][j]) + ep);
|
||||
Filter[i][j] = AA * std::conj(Hed[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_tuple(Model, Filter, C1, Hed, SA);
|
||||
}
|
||||
|
||||
// Protected function to calculate match filter response
|
||||
std::tuple<std::vector<std::vector<std::complex<double>>>, std::vector<std::complex<double>>>
|
||||
pCalcMatchedFilter(int nt, double dt, int nx, double dx, double d, double fc, double BW, double ERMv,
|
||||
const std::string& TrFreqSp, double T1) {
|
||||
// Implementation details omitted for brevity
|
||||
// This function would return C1 and Hed
|
||||
}
|
||||
|
||||
// Protected function to calculate scattering amplitude response
|
||||
std::vector<std::complex<double>> pCalcScatteringAmplitude(int nt, double dt, double c,
|
||||
const std::string& flaw, double b, double ang) {
|
||||
// Implementation details omitted for brevity
|
||||
// This function would return SA
|
||||
}
|
124
UTSR/ModS2.cpp
Normal file
124
UTSR/ModS2.cpp
Normal file
@ -0,0 +1,124 @@
|
||||
#include <vector>
|
||||
#include <complex>
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <fftw3.h>
|
||||
|
||||
std::vector<std::vector<double>> ModS2(const std::vector<std::vector<double>>& image, double dt, double du, double ERMv, double tau0, const std::vector<std::vector<double>>& ModTransd, int R_x = 1) {
|
||||
// Check R_x argument
|
||||
R_x = std::max(1, R_x);
|
||||
assert(R_x > 0 && "R_x must be positive");
|
||||
|
||||
// Zero-padding
|
||||
int nt0 = image.size();
|
||||
int nu0 = image[0].size();
|
||||
int nt = ModTransd.size();
|
||||
int nu = ModTransd[0].size();
|
||||
if (nt < nt0) {
|
||||
nt = std::pow(2, std::ceil(std::log2(nt0)) + 1);
|
||||
}
|
||||
if (nu < nu0) {
|
||||
nu = 2 * nu0;
|
||||
}
|
||||
|
||||
// Data and image grids
|
||||
std::vector<std::vector<double>> f(nt, std::vector<double>(nu));
|
||||
std::vector<std::vector<double>> ku(nt, std::vector<double>(nu));
|
||||
std::vector<std::vector<double>> fkz(nt, std::vector<double>(nu));
|
||||
|
||||
for (int i = 0; i < nt; ++i) {
|
||||
for (int j = 0; j < nu; ++j) {
|
||||
f[i][j] = (i - nt/2) / (dt * nt);
|
||||
ku[i][j] = (j - nu/2) / (du * nu);
|
||||
fkz[i][j] = ERMv * std::copysign(1.0, f[i][j]) * std::sqrt(std::pow(ku[i][j], 2) + std::pow(f[i][j] / ERMv, 2));
|
||||
}
|
||||
}
|
||||
|
||||
// Converting image to frequency domain
|
||||
fftw_complex *in, *out;
|
||||
fftw_plan p;
|
||||
in = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * nt * nu);
|
||||
out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * nt * nu);
|
||||
|
||||
for (int i = 0; i < nt0; ++i) {
|
||||
for (int j = 0; j < nu0; ++j) {
|
||||
in[i*nu + j][0] = image[i][j];
|
||||
in[i*nu + j][1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
p = fftw_plan_dft_2d(nt, nu, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
|
||||
fftw_execute(p);
|
||||
|
||||
std::vector<std::vector<std::complex<double>>> ftimage(nt, std::vector<std::complex<double>>(nu));
|
||||
for (int i = 0; i < nt; ++i) {
|
||||
for (int j = 0; j < nu; ++j) {
|
||||
ftimage[i][j] = std::complex<double>(out[i*nu + j][0], out[i*nu + j][1]);
|
||||
}
|
||||
}
|
||||
|
||||
// Generates data spectrum (by adjoint of linear interpolation)
|
||||
// Note: linterpAdj function is not provided, so it's omitted here
|
||||
std::vector<std::vector<std::complex<double>>> ftdata = ftimage; // Placeholder
|
||||
|
||||
if (tau0 != 0) {
|
||||
for (int i = 0; i < nt; ++i) {
|
||||
for (int j = 0; j < nu; ++j) {
|
||||
ftdata[i][j] *= std::exp(std::complex<double>(0, 2 * M_PI * (fkz[i][j] - f[i][j]) * tau0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Inserts transducer model (if exists)
|
||||
if (!ModTransd.empty()) {
|
||||
int rowShift = (nt - ModTransd.size()) / 2;
|
||||
int colShift = (nu - ModTransd[0].size()) / 2;
|
||||
for (int i = 0; i < nt; ++i) {
|
||||
for (int j = 0; j < nu; ++j) {
|
||||
int ii = (i + rowShift) % nt;
|
||||
int jj = (j + colShift) % nu;
|
||||
if (ii < ModTransd.size() && jj < ModTransd[0].size()) {
|
||||
ftdata[i][j] *= ModTransd[ii][jj];
|
||||
} else {
|
||||
ftdata[i][j] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Converting data to time domain
|
||||
for (int i = 0; i < nt; ++i) {
|
||||
for (int j = 0; j < nu; ++j) {
|
||||
in[i*nu + j][0] = ftdata[i][j].real();
|
||||
in[i*nu + j][1] = ftdata[i][j].imag();
|
||||
}
|
||||
}
|
||||
|
||||
p = fftw_plan_dft_2d(nt, nu, in, out, FFTW_BACKWARD, FFTW_ESTIMATE);
|
||||
fftw_execute(p);
|
||||
|
||||
std::vector<std::vector<double>> data(nt0, std::vector<double>(nu0));
|
||||
for (int i = 0; i < nt0; ++i) {
|
||||
for (int j = 0; j < nu0; ++j) {
|
||||
data[i][j] = out[i*nu + j][0] / (nt * nu);
|
||||
}
|
||||
}
|
||||
|
||||
// Applies sub-sampling
|
||||
if (R_x > 1) {
|
||||
for (int i = 0; i < nt0; ++i) {
|
||||
for (int j = 0; j < nu0; j += R_x) {
|
||||
data[i][j/R_x] = data[i][j] * R_x;
|
||||
}
|
||||
}
|
||||
data[0].resize(nu0/R_x);
|
||||
}
|
||||
|
||||
fftw_destroy_plan(p);
|
||||
fftw_free(in);
|
||||
fftw_free(out);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
89
UTSR/ModS2T.cpp
Normal file
89
UTSR/ModS2T.cpp
Normal file
@ -0,0 +1,89 @@
|
||||
#include <vector>
|
||||
#include <complex>
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <fftw3.h>
|
||||
|
||||
// Function declaration
|
||||
std::vector<std::vector<double>> ModS2T(const std::vector<std::vector<double>>& data, double dt, double du, double ERMv, double tau0, const std::vector<std::vector<double>>& Filter, int R_x = 1) {
|
||||
// Check R_x argument
|
||||
R_x = std::max(1, R_x);
|
||||
assert(R_x > 0 && "R_x must be positive");
|
||||
|
||||
std::vector<std::vector<double>> processedData = data;
|
||||
|
||||
// Applies linear interpolation (if necessary)
|
||||
if (R_x > 1) {
|
||||
// Implementation of linear interpolation
|
||||
// Note: This part needs a more detailed implementation
|
||||
}
|
||||
|
||||
// Zero-padding
|
||||
int nt0 = processedData.size();
|
||||
int nu0 = processedData[0].size();
|
||||
int nt = std::max(static_cast<int>(std::pow(2, std::ceil(std::log2(nt0)) + 1)), static_cast<int>(Filter.size()));
|
||||
int nu = std::max(2 * nu0, static_cast<int>(Filter[0].size()));
|
||||
|
||||
// Data and image grids
|
||||
std::vector<std::vector<double>> f(nt, std::vector<double>(nu));
|
||||
std::vector<std::vector<double>> ku(nt, std::vector<double>(nu));
|
||||
std::vector<std::vector<double>> fkz(nt, std::vector<double>(nu));
|
||||
|
||||
for (int i = 0; i < nt; ++i) {
|
||||
for (int j = 0; j < nu; ++j) {
|
||||
f[i][j] = (i - nt/2) / (dt * nt);
|
||||
ku[i][j] = (j - nu/2) / (du * nu);
|
||||
fkz[i][j] = ERMv * std::copysign(1.0, f[i][j]) * std::sqrt(std::pow(ku[i][j], 2) + std::pow(f[i][j] / ERMv, 2));
|
||||
}
|
||||
}
|
||||
|
||||
// Converting data to frequency domain
|
||||
std::vector<std::vector<std::complex<double>>> ftdata(nt, std::vector<std::complex<double>>(nu));
|
||||
// Note: FFTW library should be used here for efficient FFT computation
|
||||
|
||||
if (tau0 != 0) {
|
||||
for (int i = 0; i < nt; ++i) {
|
||||
for (int j = 0; j < nu; ++j) {
|
||||
ftdata[i][j] *= std::exp(std::complex<double>(0, -2 * M_PI * (fkz[i][j] - f[i][j]) * tau0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Applies filter (if it exists)
|
||||
if (!Filter.empty()) {
|
||||
// Implementation of filter application
|
||||
// Note: This part needs a more detailed implementation
|
||||
}
|
||||
|
||||
// Generating image spectrum (by linear interpolation)
|
||||
std::vector<std::vector<std::complex<double>>> ftimage(nt, std::vector<std::complex<double>>(nu));
|
||||
// Note: Linear interpolation should be implemented here
|
||||
|
||||
// Converting image to space domain
|
||||
std::vector<std::vector<double>> image(nt0, std::vector<double>(nu0));
|
||||
// Note: Inverse FFT should be applied here using FFTW library
|
||||
|
||||
for (int i = 0; i < nt0; ++i) {
|
||||
for (int j = 0; j < nu0; ++j) {
|
||||
image[i][j] *= R_x;
|
||||
}
|
||||
}
|
||||
|
||||
// Evaluates the gain
|
||||
double enImage = 0, enData = 0;
|
||||
for (const auto& row : image) {
|
||||
for (double val : row) {
|
||||
enImage += val * val;
|
||||
}
|
||||
}
|
||||
for (const auto& row : data) {
|
||||
for (double val : row) {
|
||||
enData += val * val;
|
||||
}
|
||||
}
|
||||
double gain = std::sqrt(enImage / enData);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
67
UTSR/cossquare.cpp
Normal file
67
UTSR/cossquare.cpp
Normal file
@ -0,0 +1,67 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
// Function to check if input is a vector
|
||||
bool isvector(double* f, int rows, int cols) {
|
||||
return (rows == 1 || cols == 1);
|
||||
}
|
||||
|
||||
// Function to check if input is a matrix
|
||||
bool ismatrix(double* f, int rows, int cols) {
|
||||
return (rows > 1 && cols > 1);
|
||||
}
|
||||
|
||||
// Function to check if input is a scalar
|
||||
bool isscalar(double* f, int rows, int cols) {
|
||||
return (rows == 1 && cols == 1);
|
||||
}
|
||||
|
||||
// Main function
|
||||
double* cossquare(double* f, int rows, int cols, double fc, double BW) {
|
||||
double f1 = fc - BW;
|
||||
double f4 = fc + BW;
|
||||
double* r = malloc(rows * cols * sizeof(double));
|
||||
|
||||
if (isvector(f, rows, cols)) {
|
||||
int n = rows * cols;
|
||||
for (int i = 0; i < n; i++) {
|
||||
double ss = sin(M_PI * f[i] / (2 * fc));
|
||||
bool ri1 = (fabs(f[i]) > fc) && (fabs(f[i]) <= f4);
|
||||
bool ri2 = (fabs(f[i]) <= fc) && (fabs(f[i]) <= f4);
|
||||
double ff1 = ri1 ? fabs(f[i]) : 0;
|
||||
double ff2 = ri2 ? fabs(f[i]) : 0;
|
||||
double r1 = ri1 ? pow(cos(M_PI * (fc - ff1) / (f4 - f1)), 2) : 0;
|
||||
double r2 = ri2 ? ss * pow(cos(M_PI * (fc - ff2) / (f4 - f1)), 2) : 0;
|
||||
r[i] = r1 + (f[i] >= 0 ? 1 : -1) * r2;
|
||||
}
|
||||
} else if (ismatrix(f, rows, cols)) {
|
||||
for (int c = 0; c < cols; c++) {
|
||||
for (int i = 0; i < rows; i++) {
|
||||
double ss = sin(M_PI * f[i * cols + c] / (2 * fc));
|
||||
bool ri1 = (fabs(f[i * cols + c]) > fc) && (fabs(f[i * cols + c]) <= f4);
|
||||
bool ri2 = (fabs(f[i * cols + c]) <= fc) && (fabs(f[i * cols + c]) <= f4);
|
||||
double ff1 = ri1 ? fabs(f[i * cols + c]) : 0;
|
||||
double ff2 = ri2 ? fabs(f[i * cols + c]) : 0;
|
||||
double r1 = ri1 ? pow(cos(M_PI * (fc - ff1) / (f4 - f1)), 2) : 0;
|
||||
double r2 = ri2 ? ss * pow(cos(M_PI * (fc - ff2) / (f4 - f1)), 2) : 0;
|
||||
r[i * cols + c] = r1 + (f[i * cols + c] >= 0 ? 1 : -1) * r2;
|
||||
}
|
||||
}
|
||||
} else if (isscalar(f, rows, cols)) {
|
||||
if ((fabs(f[0]) >= f1) && (fabs(f[0]) <= f4)) {
|
||||
if (fabs(f[0]) > fc) {
|
||||
r[0] = pow(cos(M_PI * (fc - fabs(f[0])) / (f4 - f1)), 2);
|
||||
} else {
|
||||
r[0] = sin(M_PI * f[0] / (2 * fc)) * pow(cos(M_PI * (fc - fabs(f[0])) / (f4 - f1)), 2);
|
||||
}
|
||||
} else {
|
||||
r[0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
215
UTSR/datNDTread.cpp
Normal file
215
UTSR/datNDTread.cpp
Normal file
@ -0,0 +1,215 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <limits>
|
||||
#include <numeric>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
struct ScanData {
|
||||
struct CscanData {
|
||||
int Rows;
|
||||
int AscanPoints;
|
||||
double TsGate;
|
||||
double TendGate;
|
||||
std::vector<double> X;
|
||||
double Cl;
|
||||
double Cs;
|
||||
double Density;
|
||||
double Frequency;
|
||||
double Bandwidth;
|
||||
char WaveType;
|
||||
double BeamAngle;
|
||||
double ProbeDiameter;
|
||||
double MaxSdtRef;
|
||||
double Y;
|
||||
int Cols;
|
||||
std::vector<std::vector<double>> CscanValues;
|
||||
double Wavelength;
|
||||
double Nearfield;
|
||||
double NearfieldTime;
|
||||
double ProbeEllipX;
|
||||
double ProbeEllipY;
|
||||
double TrueAngle;
|
||||
double CalValue;
|
||||
std::string DefectType;
|
||||
double PosX;
|
||||
double PosY;
|
||||
double DepthCentre;
|
||||
double Diameter;
|
||||
double Height;
|
||||
double Tilt;
|
||||
double MaxSignal;
|
||||
};
|
||||
|
||||
CscanData CscanData;
|
||||
std::vector<std::vector<double>> AscanValues;
|
||||
std::vector<double> timeScale;
|
||||
};
|
||||
|
||||
ScanData datNDTread(const std::map<std::string, std::variant<double, std::string>>& args) {
|
||||
ScanData scanData;
|
||||
|
||||
// Parse input arguments
|
||||
double TsGate = std::get<double>(args.at("TsGate"));
|
||||
double TendGate = std::get<double>(args.at("TendGate"));
|
||||
double deltaT = std::get<double>(args.at("deltaT"));
|
||||
double minX = std::get<double>(args.at("minX"));
|
||||
double maxX = std::get<double>(args.at("maxX"));
|
||||
double deltaX = std::get<double>(args.at("deltaX"));
|
||||
double backDepth = std::get<double>(args.at("backDepth"));
|
||||
double Density = std::get<double>(args.at("Density"));
|
||||
double fc = std::get<double>(args.at("fc"));
|
||||
double bw = std::get<double>(args.at("bw"));
|
||||
char WaveType = std::get<std::string>(args.at("WaveType"))[0];
|
||||
double BeamAngle = std::get<double>(args.at("BeamAngle"));
|
||||
double d = std::get<double>(args.at("d"));
|
||||
std::string baseFolder = std::get<std::string>(args.at("baseFolder"));
|
||||
double gain = std::get<double>(args.at("gain"));
|
||||
double A0 = std::get<double>(args.at("A0"));
|
||||
double alpha = std::get<double>(args.at("alpha"));
|
||||
|
||||
// Get file list in base folder
|
||||
std::vector<fs::path> files;
|
||||
for (const auto& entry : fs::directory_iterator(baseFolder)) {
|
||||
if (entry.path().extension() == ".dat") {
|
||||
files.push_back(entry.path());
|
||||
}
|
||||
}
|
||||
|
||||
// Create AscanValues element
|
||||
scanData.CscanData.Rows = files.size();
|
||||
scanData.AscanValues.resize(scanData.CscanData.Rows);
|
||||
|
||||
// Import data as columns
|
||||
std::vector<double> backWallIdx(files.size());
|
||||
for (size_t i = 0; i < files.size(); ++i) {
|
||||
std::string filename = files[i].filename().string();
|
||||
int col;
|
||||
sscanf(filename.c_str(), "pos%d.dat", &col);
|
||||
col++;
|
||||
|
||||
std::vector<double> dat;
|
||||
std::ifstream file(files[i]);
|
||||
double value;
|
||||
while (file >> value) {
|
||||
dat.push_back(value);
|
||||
}
|
||||
|
||||
size_t lenDat = dat.size();
|
||||
auto idxm = std::min_element(dat.begin(), dat.begin() + lenDat / 3) - dat.begin();
|
||||
auto limIdx = std::min_element(dat.begin() + 2 * lenDat / 3, dat.end()) - dat.begin();
|
||||
|
||||
auto idx2m = std::max_element(dat.begin() + 2 * lenDat / 3, dat.begin() + limIdx) - dat.begin();
|
||||
|
||||
backWallIdx[col - 1] = idx2m - idxm;
|
||||
scanData.AscanValues[col - 1].resize(lenDat, 0);
|
||||
std::copy(dat.begin() + idxm, dat.end(), scanData.AscanValues[col - 1].begin());
|
||||
}
|
||||
|
||||
// Create timeScale element
|
||||
scanData.CscanData.AscanPoints = scanData.AscanValues[0].size();
|
||||
scanData.timeScale.resize(scanData.CscanData.AscanPoints);
|
||||
std::iota(scanData.timeScale.begin(), scanData.timeScale.end(), 0);
|
||||
std::transform(scanData.timeScale.begin(), scanData.timeScale.end(), scanData.timeScale.begin(),
|
||||
[deltaT](double x) { return x * deltaT; });
|
||||
|
||||
// Define the time window for simulation
|
||||
std::vector<double> t;
|
||||
for (double time = TsGate; time <= TendGate; time += deltaT) {
|
||||
t.push_back(time);
|
||||
}
|
||||
size_t nt = t.size();
|
||||
size_t idxTsGate = std::lower_bound(t.begin(), t.end(), TsGate) - t.begin();
|
||||
size_t idxTendGate = std::lower_bound(t.begin(), t.end(), TendGate) - t.begin();
|
||||
|
||||
// Update scanData with arguments values
|
||||
scanData.CscanData.TsGate = TsGate;
|
||||
scanData.CscanData.TendGate = TendGate;
|
||||
|
||||
scanData.CscanData.X.resize(scanData.CscanData.Rows);
|
||||
std::iota(scanData.CscanData.X.begin(), scanData.CscanData.X.end(), 0);
|
||||
std::transform(scanData.CscanData.X.begin(), scanData.CscanData.X.end(), scanData.CscanData.X.begin(),
|
||||
[deltaX](double x) { return x * deltaX; });
|
||||
|
||||
std::vector<double> backWallIdxEnds = {backWallIdx.front(), backWallIdx.back()};
|
||||
double Cl = backDepth * 2000 / std::accumulate(backWallIdxEnds.begin(), backWallIdxEnds.end(), 0.0,
|
||||
[&](double sum, double idx) { return sum + scanData.timeScale[idx]; });
|
||||
scanData.CscanData.Cl = Cl;
|
||||
scanData.CscanData.Cs = 0;
|
||||
scanData.CscanData.Density = Density;
|
||||
|
||||
scanData.CscanData.Frequency = fc;
|
||||
scanData.CscanData.Bandwidth = bw;
|
||||
scanData.CscanData.WaveType = WaveType;
|
||||
scanData.CscanData.BeamAngle = BeamAngle;
|
||||
scanData.CscanData.ProbeDiameter = d;
|
||||
|
||||
// Others elements
|
||||
scanData.CscanData.MaxSdtRef = 0;
|
||||
scanData.CscanData.Y = 0;
|
||||
scanData.CscanData.Cols = 1;
|
||||
scanData.CscanData.CscanValues.resize(scanData.CscanData.Rows, std::vector<double>(scanData.CscanData.Cols, 0));
|
||||
|
||||
double c = (WaveType == 'L' || WaveType == 'l') ? scanData.CscanData.Cl : scanData.CscanData.Cs;
|
||||
scanData.CscanData.Wavelength = c / (scanData.CscanData.Frequency * 1000);
|
||||
scanData.CscanData.Nearfield = std::pow(scanData.CscanData.ProbeDiameter / 2, 2) / scanData.CscanData.Wavelength;
|
||||
scanData.CscanData.NearfieldTime = scanData.CscanData.Nearfield / (c / 2000);
|
||||
scanData.CscanData.ProbeEllipX = 0;
|
||||
scanData.CscanData.ProbeEllipY = 0;
|
||||
scanData.CscanData.TrueAngle = scanData.CscanData.BeamAngle;
|
||||
scanData.CscanData.CalValue = 0;
|
||||
|
||||
scanData.CscanData.DefectType = "empty";
|
||||
scanData.CscanData.PosX = 0;
|
||||
scanData.CscanData.PosY = 0;
|
||||
scanData.CscanData.DepthCentre = 0;
|
||||
scanData.CscanData.Diameter = 0;
|
||||
scanData.CscanData.Height = 0;
|
||||
scanData.CscanData.Tilt = 0;
|
||||
|
||||
// Adjust A-scan amplitude
|
||||
if (std::isinf(gain)) {
|
||||
double MaxSignal = 0;
|
||||
for (const auto& ascan : scanData.AscanValues) {
|
||||
MaxSignal = std::max(MaxSignal, *std::max_element(ascan.begin(), ascan.end(), [](double a, double b) { return std::abs(a) < std::abs(b); }));
|
||||
}
|
||||
for (auto& ascan : scanData.AscanValues) {
|
||||
std::transform(ascan.begin(), ascan.end(), ascan.begin(), [MaxSignal](double x) { return x / MaxSignal; });
|
||||
}
|
||||
} else {
|
||||
double gainFactor = std::pow(10, gain / 20);
|
||||
for (auto& ascan : scanData.AscanValues) {
|
||||
std::transform(ascan.begin(), ascan.end(), ascan.begin(), [gainFactor](double x) { return (0.5 / 2048 / gainFactor) * x; });
|
||||
}
|
||||
}
|
||||
|
||||
// Apply TGV
|
||||
std::vector<double> zz(scanData.timeScale.size());
|
||||
std::transform(scanData.timeScale.begin(), scanData.timeScale.end(), zz.begin(), [Cl](double t) { return t * Cl / 2000; });
|
||||
std::vector<double> ffc(zz.size());
|
||||
std::transform(zz.begin(), zz.end(), ffc.begin(), [A0, alpha](double z) { return std::max(1.0, (1 / A0) * std::exp(alpha * z)); });
|
||||
|
||||
for (auto& ascan : scanData.AscanValues) {
|
||||
std::transform(ascan.begin(), ascan.end(), ffc.begin(), ascan.begin(), std::multiplies<double>());
|
||||
}
|
||||
|
||||
// Calculate elements after the simulation session
|
||||
scanData.CscanData.MaxSignal = 0;
|
||||
for (const auto& ascan : scanData.AscanValues) {
|
||||
scanData.CscanData.MaxSignal = std::max(scanData.CscanData.MaxSignal, *std::max_element(ascan.begin(), ascan.end(), [](double a, double b) { return std::abs(a) < std::abs(b); }));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < scanData.CscanData.Rows; ++i) {
|
||||
double maxAbs = *std::max_element(scanData.AscanValues[i].begin(), scanData.AscanValues[i].end(), [](double a, double b) { return std::abs(a) < std::abs(b); });
|
||||
scanData.CscanData.CscanValues[i][0] = 10 * std::log10(maxAbs);
|
||||
}
|
||||
|
||||
return scanData;
|
||||
}
|
||||
|
73
UTSR/linterp.cpp
Normal file
73
UTSR/linterp.cpp
Normal file
@ -0,0 +1,73 @@
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
std::vector<std::vector<double>> linterp(const std::vector<double>& X, const std::vector<std::vector<double>>& V, const std::vector<std::vector<double>>& Xq) {
|
||||
// Ensure X is a column vector
|
||||
std::vector<double> X_col = X;
|
||||
|
||||
// Ensure V is a column vector if it's a 1D vector
|
||||
std::vector<std::vector<double>> V_col = V;
|
||||
if (V.size() == 1) {
|
||||
V_col = std::vector<std::vector<double>>(V[0].size(), std::vector<double>(1));
|
||||
for (size_t i = 0; i < V[0].size(); ++i) {
|
||||
V_col[i][0] = V[0][i];
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure Xq is a column vector if it's a 1D vector
|
||||
std::vector<std::vector<double>> Xq_col = Xq;
|
||||
if (Xq.size() == 1) {
|
||||
Xq_col = std::vector<std::vector<double>>(Xq[0].size(), std::vector<double>(1));
|
||||
for (size_t i = 0; i < Xq[0].size(); ++i) {
|
||||
Xq_col[i][0] = Xq[0][i];
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate output variable space
|
||||
std::vector<std::vector<double>> Vq(Xq_col.size(), std::vector<double>(Xq_col[0].size(), 0.0));
|
||||
double dX = X_col[1] - X_col[0];
|
||||
size_t N = V_col.size();
|
||||
|
||||
// Loop every Xq column
|
||||
for (size_t col = 0; col < Xq_col[0].size(); ++col) {
|
||||
// Calculate Xq shifts
|
||||
std::vector<double> f;
|
||||
std::vector<bool> fMask(Xq_col.size(), false);
|
||||
for (size_t i = 0; i < Xq_col.size(); ++i) {
|
||||
if (Xq_col[i][col] >= X_col[0] && Xq_col[i][col] <= X_col.back()) {
|
||||
f.push_back((Xq_col[i][col] - X_col[0]) / dX);
|
||||
fMask[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate Xq index
|
||||
std::vector<size_t> im(f.size());
|
||||
for (size_t i = 0; i < f.size(); ++i) {
|
||||
im[i] = static_cast<size_t>(std::floor(f[i]));
|
||||
}
|
||||
size_t im2Inval = std::count_if(im.begin(), im.end(), [N](size_t i) { return i + 2 > N; });
|
||||
|
||||
// Calculate interpolation factors
|
||||
std::vector<double> fx(f.size()), gx(f.size());
|
||||
for (size_t i = 0; i < f.size(); ++i) {
|
||||
fx[i] = f[i] - im[i];
|
||||
gx[i] = 1 - fx[i];
|
||||
}
|
||||
|
||||
// Interpolate Vq values
|
||||
size_t j = 0;
|
||||
for (size_t i = 0; i < Xq_col.size(); ++i) {
|
||||
if (fMask[i]) {
|
||||
if (im2Inval > 0 && j >= f.size() - im2Inval) {
|
||||
Vq[i][col] = gx[j] * V_col[im[j] + 1][col] + fx[j] * 0.0;
|
||||
} else {
|
||||
Vq[i][col] = gx[j] * V_col[im[j] + 1][col] + fx[j] * V_col[im[j] + 2][col];
|
||||
}
|
||||
++j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Vq;
|
||||
}
|
88
UTSR/linterpAdj.cpp
Normal file
88
UTSR/linterpAdj.cpp
Normal file
@ -0,0 +1,88 @@
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <numeric>
|
||||
|
||||
std::vector<std::vector<double>> linterpAdj(const std::vector<double>& X, const std::vector<std::vector<double>>& Xq, const std::vector<std::vector<double>>& Vq) {
|
||||
// Ensure X is a column vector
|
||||
std::vector<double> X_col = X;
|
||||
|
||||
// Ensure Vq is a column vector if it's a 1D vector
|
||||
std::vector<std::vector<double>> Vq_col = Vq;
|
||||
if (Vq.size() == 1) {
|
||||
Vq_col = std::vector<std::vector<double>>(Vq[0].size(), std::vector<double>(1));
|
||||
for (size_t i = 0; i < Vq[0].size(); ++i) {
|
||||
Vq_col[i][0] = Vq[0][i];
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure Xq is a column vector if it's a 1D vector
|
||||
std::vector<std::vector<double>> Xq_col = Xq;
|
||||
if (Xq.size() == 1) {
|
||||
Xq_col = std::vector<std::vector<double>>(Xq[0].size(), std::vector<double>(1));
|
||||
for (size_t i = 0; i < Xq[0].size(); ++i) {
|
||||
Xq_col[i][0] = Xq[0][i];
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate output variable space
|
||||
std::vector<std::vector<double>> V(X_col.size(), std::vector<double>(Xq_col[0].size(), 0.0));
|
||||
double dX = X_col[1] - X_col[0];
|
||||
size_t N = V.size();
|
||||
|
||||
// Loop every Xq column
|
||||
for (size_t col = 0; col < Xq_col[0].size(); ++col) {
|
||||
// Calculate Xq shifts
|
||||
std::vector<double> f;
|
||||
std::vector<bool> fMask;
|
||||
for (size_t i = 0; i < Xq_col.size(); ++i) {
|
||||
double shift = (Xq_col[i][col] - X_col[0]) / dX;
|
||||
if (Xq_col[i][col] >= X_col[0] && Xq_col[i][col] <= X_col.back()) {
|
||||
f.push_back(shift);
|
||||
fMask.push_back(true);
|
||||
} else {
|
||||
fMask.push_back(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate Xq index
|
||||
std::vector<size_t> im(f.size());
|
||||
for (size_t i = 0; i < f.size(); ++i) {
|
||||
im[i] = static_cast<size_t>(std::floor(f[i]));
|
||||
}
|
||||
size_t im2Inval = std::count_if(im.begin(), im.end(), [N](size_t i) { return i + 2 > N; });
|
||||
|
||||
// Calculate interpolation factors
|
||||
std::vector<double> fx(f.size()), gx(f.size());
|
||||
for (size_t i = 0; i < f.size(); ++i) {
|
||||
fx[i] = f[i] - im[i];
|
||||
gx[i] = 1 - fx[i];
|
||||
}
|
||||
|
||||
// Calculate adjoint interpolation
|
||||
std::vector<double> VqM;
|
||||
for (size_t i = 0; i < fMask.size(); ++i) {
|
||||
if (fMask[i]) {
|
||||
VqM.push_back(Vq_col[i][col]);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<double> pG(N, 0.0), pF(N, 0.0);
|
||||
for (size_t i = 0; i < im.size(); ++i) {
|
||||
pG[im[i] + 1] += gx[i] * VqM[i];
|
||||
if (im[i] + 2 <= N) {
|
||||
pF[im[i] + 2] += fx[i] * VqM[i];
|
||||
}
|
||||
}
|
||||
|
||||
pF.resize(N - im2Inval);
|
||||
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
V[i][col] = pG[i] + (i < pF.size() ? pF[i] : 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
return V;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user