LAMPCAE/src/LAMPTool/SARImage/FEKOBaseToolClass.cpp

1041 lines
32 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "SARImage/FEKOBaseToolClass.h"
#include <math.h>
#include "BaseToolLib/BaseConstVariable.h"
#include <QMessageBox>
#include <math.h>
#include <complex>
#include "BaseToollib/ImageOperatorBase.h"
#include <SARBaseToolLib/SARImageBase.h>
#include "SARBaseToolLib/SARBaseTool.h"
#include "BaseToollib/FileOperator.h"
#include <QtXml/qdom.h>
QString FEKOBase::FEKOImageModeenumToString(FEKOBase::FEKOImageMode mode)
{
switch (mode) {
case Strip:
return "STRIP";
case Scane:
return "SCANE";
case ISAR:
return "ISAR";
case CircleSAR:
return "CircleSAR";
}
// 如果枚举值不匹配任何字符串,则返回一个默认值,或者抛出异常
return "UNKNOW"; // 默认返回Unknown
}
FEKOBase::FEKOCoordinateSystem FEKOBase::FEKOCoordinateSystemString2Enum(QString str)
{
if (str.toUpper() == "SPHERICAL") { return FEKOBase::Spherical; }
else if (str.toUpper() == "CARTESIAN") { return FEKOBase::Cartesian; }
else {
return FEKOBase::UNKONWFEKOCOORDINATESYSTEM;
}
}
QString FEKOBase::QString2FEKOCoordinateSystem(FEKOBase::FEKOCoordinateSystem mode)
{
switch (mode) {
case FEKOBase::Spherical:
return "SPHERICAL";
case FEKOBase::Cartesian:
return "CARTESIAN";
default:
return "UNKONWFEKOCOORDINATESYSTEM";
}
}
FEKOBase::FEKOImageMode FEKOBase::FEKOImageModeString2Enum(QString str)
{
if (str.toUpper() == "STRIP") {
return FEKOBase::FEKOImageMode::Strip;
}
else if (str.toUpper() == "SCANE") {
return FEKOBase::FEKOImageMode::Scane;
}
else if (str.toUpper() == "ISAR") {
return FEKOBase::FEKOImageMode::ISAR;
}
else if (str.toUpper() == "CIRCLESAR") {
return FEKOBase::FEKOImageMode::CircleSAR;
}
// 如果输入的字符串不匹配任何枚举值,则返回一个默认值,或者抛出异常
return FEKOBase::FEKOImageMode::UNKNOW; // 默认返回UNKNOW
}
FEKOBase::freqParams FEKOBase::getFreqSetting(double centerFreq, double resolution, double bandWidth, double scenceRange, bool isResolution) {
FEKOBase::freqParams result{ 0,0,0 };
{
if (isResolution) {
bandWidth = 0.299792458 / 2 / resolution; // 计算带宽
}
else {
resolution = 0.299792458 / 2 / bandWidth; // 计算分辨率
}
}
size_t samplePoint = std::ceil((scenceRange) / resolution) + 1;
result.startfreqs = centerFreq - 0.5 * bandWidth;
result.endfreqs = centerFreq + 0.5 * bandWidth;
result.freqpoint = samplePoint;
return result;
}
FEKOBase::FEKOSatelliteParams FEKOBase::createFEKOSatelliteParams(double Px, double Py, double Pz, double Vx, double Vy, double Vz, double incidenceAngle, double AzAngle, double theta, double phi, bool isRight, size_t PRFIdx)
{
FEKOBase::FEKOSatelliteParams result{
PRFIdx,
FEKOBase::SatelliteState{
FEKOBase::SatellitePosition{Px,Py,Pz},
FEKOBase::SatelliteVelocity{Vx,Vy,Vz}
},
incidenceAngle,AzAngle,
FEKOBase::FEKOantPitionDirect{Px,Py,Pz,theta,phi},
isRight
};
return result;
}
FEKOBase::FEKOSatelliteParams FEKOBase::createFEKOSatelliteParams(SatelliteState pose, double incidenceAngle, double AzAngle, FEKOantPitionDirect antpos, size_t PRFIdx)
{
FEKOBase::FEKOSatelliteParams result{
PRFIdx,pose,incidenceAngle,AzAngle,antpos
};
return result;
}
FEKOBase::SatelliteState FEKOBase::FEKOSatelliteParams2SatelliteState(FEKOSatelliteParams parmas)
{
return parmas.pose;
}
FEKOBase::FEKOantPitionDirect FEKOBase::FEKOSatelliteParams2FEKOantPitionDirect(FEKOSatelliteParams parmas)
{
return parmas.antpos;
}
TopoDS_Shape FEKOBase::SatellitePos2FEKOAntPos(SatelliteState satepos, double incidenceAngle, double AzAngle, bool isRIGHT, FEKOantPitionDirect* antposition_Direct, TopoDS_Shape antModel)
{
incidenceAngle = incidenceAngle * M_PI / 180; // 转换为弧度
AzAngle = AzAngle * M_PI / 180; // 扫描角度转换为弧度
TopoDS_Shape tempShape;
if (!antModel.IsNull()) {
// 创建一个复制
BRepBuilderAPI_Copy copyBuilder(antModel);
tempShape = copyBuilder.Shape();
}
double Sx = satepos.pos.Px;
double Sy = satepos.pos.Py;
double Sz = satepos.pos.Pz;
double Vx = satepos.vel.Vx;
double Vy = satepos.vel.Vy;
double Vz = satepos.vel.Vz;
//qDebug() << u8"// 0. 卫星状态矢量";
gp_Vec SateVelocity(gp_Pnt(0, 0, 0), gp_Pnt(Vx, Vy, Vz)); // 卫星速度矢量
gp_Vec SatePosition(gp_Pnt(0, 0, 0), gp_Pnt(Sx, Sy, Sz)); // 卫星位置矢量
gp_Vec sch_X(gp_Pnt(0, 0, 0), gp_Pnt(1.0, 0.0, 0.0));
gp_Vec sch_Y(gp_Pnt(0, 0, 0), gp_Pnt(0.0, 1.0, 0.0)); // 飞行方向 y
gp_Vec sch_Z(gp_Pnt(0, 0, 0), gp_Pnt(0.0, 0.0, 1.0)); // 雷达照射方向
// qDebug() << u8"// 1. 卫星坐标系 sch -->飞行坐标系 fly 保证Z轴指向不变化";
gp_Vec sch_X_fly;
gp_Vec sch_Y_fly; // 飞行向
gp_Vec sch_Z_fly;
{
CartesianCoordinates Sp_car{ sch_Y.X(),sch_Y.Y(), sch_Y.Z() };
CartesianCoordinates tp_car{ SateVelocity.X(),SateVelocity.Y(), SateVelocity.Z() };
SphericalCoordinates sp_sph = cartesianToSpherical(Sp_car);
SphericalCoordinates tp_sph = cartesianToSpherical(tp_car);
// 计算
double delta_theta = tp_sph.theta - sp_sph.theta;
double delta_phi = tp_sph.phi - sp_sph.phi;
gp_Trsf rotationTransform_theta;
rotationTransform_theta.SetRotation(gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(0, 1, 0)), delta_theta); // 绕 y 轴旋转
sch_X_fly = sch_X.Transformed(rotationTransform_theta);
sch_Y_fly = sch_Y.Transformed(rotationTransform_theta);
sch_Z_fly = sch_Z.Transformed(rotationTransform_theta);
gp_Trsf rotationTransform_phi;
rotationTransform_phi.SetRotation(gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), delta_phi); // 绕 z 轴旋转
sch_X_fly = sch_X_fly.Transformed(rotationTransform_phi);
sch_Y_fly = sch_Y_fly.Transformed(rotationTransform_phi);
sch_Z_fly = sch_Z_fly.Transformed(rotationTransform_phi);
if (!tempShape.IsNull()) {
BRepBuilderAPI_Transform shapeTransform_theta(tempShape, rotationTransform_theta);
tempShape = shapeTransform_theta.Shape();
BRepBuilderAPI_Transform shapeTransform_phi(tempShape, rotationTransform_phi);
tempShape = shapeTransform_phi.Shape();
}
}
// qDebug() << u8"// 2. 根据方位角与俯仰角,调整雷达姿态 --- 此步确定 Y 轴已经调整完毕 ";
// qDebug() << u8"// 2. a 根据 incidenceAngle 调整 Z 的指向,需要先根据左右视判断出雷达照射方向";
{ // 按照 Y 轴进行计算
incidenceAngle = M_PI - incidenceAngle; // 下Z轴
Standard_Real ZRotation_angle = 0;
if (isRIGHT) { // 右视 +
ZRotation_angle = incidenceAngle;
}
else { // 左视 -
ZRotation_angle = -1 * incidenceAngle;
}
gp_Trsf fly_incidence_trsf;
fly_incidence_trsf.SetRotation(gp_Ax1(gp_Pnt(0, 0, 0), sch_Y_fly), ZRotation_angle); // 计算入射角
sch_X_fly = sch_X_fly.Transformed(fly_incidence_trsf);
sch_Y_fly = sch_Y_fly.Transformed(fly_incidence_trsf);
sch_Z_fly = sch_Z_fly.Transformed(fly_incidence_trsf); // 此时获取雷达的照射方向
if (!tempShape.IsNull()) {
BRepBuilderAPI_Transform shapeTransform_incidence(tempShape, fly_incidence_trsf); // fly_Z --> incidenceAngle
tempShape = shapeTransform_incidence.Shape();
}
}
// qDebug() << u8"// 2.b 根据 AzAngle 调整 Z 的指向 ";
// qDebug() << u8"// Az 应该变化在 YoZ 也就是绕 X 轴 旋转;";
{ // 沿Z 轴进行计算
gp_Trsf fly_AZ_trsf;
fly_AZ_trsf.SetRotation(gp_Ax1(gp_Pnt(0, 0, 0), sch_X_fly), AzAngle); // 计算方位角变化
sch_X_fly = sch_X_fly.Transformed(fly_AZ_trsf);
sch_Y_fly = sch_Y_fly.Transformed(fly_AZ_trsf);
sch_Z_fly = sch_Z_fly.Transformed(fly_AZ_trsf); // 此时获取雷达的照射方向
if (!tempShape.IsNull()) {
BRepBuilderAPI_Transform shapeTransform_AZ(tempShape, fly_AZ_trsf); // fly_Z --> incidenceAngle
tempShape = shapeTransform_AZ.Shape(); // 旋转卫星模型
}
}
// qDebug() << u8"// 2.c 参数记录 ";
{
CartesianCoordinates Sp_car{ 0,0,1 };
CartesianCoordinates tp_car{ sch_Z_fly.X(),sch_Z_fly.Y(), sch_Z_fly.Z() };
SphericalCoordinates sp_sph = cartesianToSpherical(Sp_car);
SphericalCoordinates tp_sph = cartesianToSpherical(tp_car); // 计算phi角度
double delta_theta = tp_sph.theta - sp_sph.theta;
double delta_phi = tp_sph.phi - sp_sph.phi;
antposition_Direct->x = Sx; //-- FEKO 设置
antposition_Direct->y = Sy; //-- FEKO 设置
antposition_Direct->z = Sz; //-- FEKO 设置
antposition_Direct->theta = delta_theta / M_PI * 180; //-- FEKO 设置 theta
antposition_Direct->phi = delta_phi / M_PI * 180;//--- FEKO 设置 phi
}
// qDebug() << u8"//3. 执行模型平移";
{
if (!tempShape.IsNull()) {
gp_Trsf fly_move_trsf;
fly_move_trsf.SetTranslation(SatePosition);
BRepBuilderAPI_Transform shapeTransform_move(tempShape, fly_move_trsf); // fly_Z --> incidenceAngle
tempShape = shapeTransform_move.Shape(); // 平移卫星模型
}
}
qDebug() << QString(u8"雷达坐标与姿态X,Y,Z,theta,phi): %1,%2,%3,%4,%5)").arg(antposition_Direct->x)
.arg(antposition_Direct->y)
.arg(antposition_Direct->z)
.arg(antposition_Direct->theta)
.arg(antposition_Direct->phi);
return tempShape;
}
bool FEKOBase::compareElectricFieldDataInFreq(const ElectricFieldData& a, const ElectricFieldData& b)
{
return a.frequency < b.frequency;
}
bool FEKOBase::comparePRFPluseDataInPRFIdx(const PRFPluseData& a, const PRFPluseData& b)
{
return a.prfidx < b.prfidx;
}
FEKOBase::NearFieldEchoCSVParser::NearFieldEchoCSVParser()
{
}
FEKOBase::NearFieldEchoCSVParser::~NearFieldEchoCSVParser()
{
}
bool FEKOBase::NearFieldEchoCSVParser::checkPRFModel()
{
qDebug() << u8"正在检查是否可以采用脉冲计数模式 configuration Name PRF_{脉冲计数}";
QRegExp regex("(\\d+)");
// 判断是否需要按照脉冲次序排序
bool usePRFbool = true;
QMap<QString, size_t> configName_prfidx;
// 使用迭代器遍历 QMap
QMap<QString, std::vector<ElectricFieldData>>::const_iterator it;
for (it = this->electricFieldDataList.constBegin(); it != this->electricFieldDataList.constEnd(); ++it) {
for (size_t i = 0; i < this->electricFieldDataList[it.key()].size(); i++) {
QString value = this->electricFieldDataList[it.key()][i].configurationName;
if (value.indexOf("PRF") != -1) {
if (regex.indexIn(value) != -1) {
// 提取匹配到的部分
QString matchedText = regex.cap(1);
size_t PRFidx = matchedText.toInt(&usePRFbool);
if (usePRFbool) {
configName_prfidx.insert(this->electricFieldDataList[it.key()][i].configurationName, PRFidx);
}
else {
qDebug() << u8"不能采用脉冲计数模型";
QMessageBox::information(nullptr, u8"警告", u8"无法根据Configuration Name识别脉冲顺序按照读取顺序计数PRF", QMessageBox::Ok);
this->usePRFCountMode = false;
return false;
}
}
}
else {
qDebug() << u8"不能采用脉冲计数模型";
QMessageBox::information(nullptr, u8"警告", u8"无法根据Configuration Name识别脉冲顺序按照读取顺序计数PRF", QMessageBox::Ok);
this->usePRFCountMode = false;
return false;
}
}
}
// 更新prfidx
for (it = this->electricFieldDataList.constBegin(); it != this->electricFieldDataList.constEnd(); ++it) {
if (!(this->electricFieldDataList[it.key()].size() > 0)) {
QMessageBox::warning(nullptr, u8"错误", u8"发现空脉冲:" + it.key());
qWarning() << u8"发现空脉冲:" + it.key();
return false;
}
else {}
QString value = this->electricFieldDataList[it.key()][0].configurationName;
for (size_t i = 0; i < this->electricFieldDataList[it.key()].size(); i++) {
if (value != this->electricFieldDataList[it.key()][0].configurationName) {
QMessageBox::warning(nullptr, u8"错误", u8"脉冲解析错误,名称不一致:" + it.key() + " | " + value);
qWarning() << u8"脉冲解析错误,名称不一致:" + it.key() + " | " + value;
}
else {}
size_t tempprfidx = configName_prfidx[value];
this->electricFieldDataList[it.key()][i].prfidx = tempprfidx;
}
}
qDebug() << u8"结束检查是否可以采用脉冲计数模式 configuration Name PRF_{脉冲计数}";
return true;
}
bool FEKOBase::NearFieldEchoCSVParser::resizePRFPluse()
{
qDebug() << u8"根据数据文件,重新整理成脉冲形式";
QMap<QString, PRFPluseData> prfPluseMap; // 采用字典映射方式
qDebug() << u8"QMap<QString, std::vector<ElectricFieldData>> ==> QMap<QString, PRFPluseData>";
double px; // 2. 计算姿态,近场点坐标
double py;
double pz;
double R;
double theta; // x0y
double phi; // y0z
size_t PRFidx;
for (QMap<QString, std::vector<ElectricFieldData>>::const_iterator it = this->electricFieldDataList.constBegin(); it != this->electricFieldDataList.constEnd(); ++it) {
PRFPluseData temp;
std::vector<ElectricFieldData> tempData = this->electricFieldDataList[it.key()]; // 脉冲已经排序号
std::sort(tempData.begin(), tempData.end(), compareElectricFieldDataInFreq);
temp.electricFieldDataList = tempData; // 按照脉冲排序
temp.freqstart = tempData[0].frequency; // 1. 频率
temp.freqend = tempData[tempData.size() - 1].frequency;
temp.freqpoints = tempData.size();
px = tempData[0].origin.x; // 2. 近场接收点计算姿态,近场点坐标
py = tempData[0].origin.y;
pz = tempData[0].origin.z;
R = tempData[0].radius;
theta = tempData[0].theta; // x0y
phi = tempData[0].phi; // y0z
PRFidx = tempData[0].prfidx;
qDebug() << u8"分析姿态:" + it.key();
for (size_t i = 0; i < tempData.size(); i++) {
if (abs(px - tempData[i].origin.x) > 0.001 || abs(py - tempData[i].origin.y) > 0.001 ||
abs(pz - tempData[i].origin.z) > 0.001 || abs(R - tempData[i].radius) > 0.001 ||
abs(theta - tempData[i].theta) > 0.001 || abs(phi - tempData[i].phi) > 0.001)
{
qDebug() << u8"发现 configuration Name:" + it.key() + u8" , 发现问题,请检查";
QMessageBox::warning(nullptr, u8"警告", u8"发现 configuration Name:" + it.key() + u8" , 发现问题,请检查");
return false;
}
else {}
}
// 计算增量 R, theta, phi ==> delta_R,delta_theta,delta_phi
theta = theta * M_PI / 180;
phi = phi * M_PI / 180;
px = px + R * std::sin(theta) * std::cos(phi);
py = py + R * std::sin(theta) * std::sin(phi);
pz = pz + R * std::cos(theta);
temp.px = px;
temp.py = py;
temp.pz = pz;
temp.prfidx = PRFidx;
prfPluseMap.insert(it.key(), temp);
}
qDebug() << u8"判断是所有回波均一性";
this->prfData = std::vector<PRFPluseData>(0);
size_t freqpointnum = prfPluseMap.first().freqpoints;
for (QMap<QString, PRFPluseData>::const_iterator it = prfPluseMap.constBegin(); it != prfPluseMap.constEnd(); ++it) {
if (it.value().freqpoints != freqpointnum) {
qDebug() << u8"回波数据频点数不一致,无法进行脉冲计数";
QMessageBox::information(nullptr, u8"警告", u8"回波数据频点数不一致,无法进行脉冲计数", QMessageBox::Ok);
this->usePRFCountMode = false;
return false;
}
this->prfData.push_back(it.value());
}
this->freqPoints = freqpointnum;
std::sort(this->prfData.begin(), this->prfData.end(), comparePRFPluseDataInPRFIdx);
this->freqStart = this->prfData[0].freqstart;
this->freqEnd = this->prfData[0].freqend;
qDebug() << u8"根据数据文件,结束整理成脉冲形式";
return true;
}
bool FEKOBase::NearFieldEchoCSVParser::parseCSV(const QString& filePath)
{
std::vector<ElectricFieldData> dataList;
QFile file(filePath);
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
QTextStream in(&file);
// 读取标题行
QString headerLine = in.readLine();
QStringList headers = headerLine.split(QRegularExpression(",(?!\\s)"));
while (!in.atEnd()) {
QString line = in.readLine();
QStringList fields = line.split(QRegularExpression(",(?!\\s)"));
ElectricFieldData data;
// 解析数据根据列名
for (int i = 0; i < headers.size(); ++i) {
QString header = headers[i].trimmed();
QString value = fields[i];// .trimmed();
if (header == "File Type") {
data.fileType = value;
}
else if (header == "File Format") {
data.fileFormat = value;
}
else if (header == "Source") {
data.source = value;
}
else if (header == "Date") {
data.date = value;
}
else if (header == "Radius") { // 半径
data.radius = value.toDouble();
}
else if (header == "Theta") { // theta 角
data.theta = value.toDouble();
}
else if (header == "Phi") {// phi 角
data.phi = value.toDouble();
}
else if (header == "Re(Er)") {
data.reEr = value.toDouble();
}
else if (header == "Im(Er)") {
data.imEr = value.toDouble();
}
else if (header == "Re(Etheta)") {
data.reEtheta = value.toDouble();
}
else if (header == "Im(Etheta)") {
data.imEtheta = value.toDouble();
}
else if (header == "Re(Ephi)") {
data.reEphi = value.toDouble();
}
else if (header == "Im(Ephi)") {
data.imEphi = value.toDouble();
}
else if (header == "Configuration Name") { // 脉冲次序名称
data.configurationName = value.trimmed();
}
else if (header == "Request Name") {
data.requestName = value.trimmed();
}
else if (header == "Frequency") {
data.frequency = value.toDouble();
}
else if (header == "Coordinate System") {
data.coordinateSystem = value;
}
else if (header == "Origin") { // 坐标参考原点
QStringList vls = value.replace("\"", "").replace("(", "").replace(")", "").split(",");
if (vls.length() < 3) {
qDebug() << "******************** ERROR INFO ******************************************";
qDebug() << "origin point has error ," << value;
qDebug() << "line: " << line;
qDebug() << "head: " << header;
qDebug() << "***************************************************************************";
QMessageBox::information(nullptr, u8"警告", u8"无法解析Origin 参数,请检查", QMessageBox::Ok);
return false;
}
data.origin = Point_3d{ vls.at(0).toDouble(),
vls.at(1).toDouble(),
vls.at(2).toDouble() };
}
else if (header == "Num Radius Samples") {
data.numRadiusSamples = value.toInt();
}
else if (header == "Num Theta Samples") {
data.numThetaSamples = value.toInt();
}
else if (header == "Num Phi Samples") {
data.numPhiSamples = value.toInt();
}
else if (header == "Result Type") {
data.resultType = value;
}
else if (header == "Num Header Lines") {
data.numHeaderLines = value.toInt();
}
// 添加其他字段的解析...
}
dataList.push_back(data);
}
file.close();
}
else {
qDebug() << "Failed to open the file:" << file.errorString();
return false;
}
//this->electricFieldDataList = dataList;
qDebug() << u8"文件读取结果,对文件结果进行重新整理与检查";
//获取脉冲最小值,最大值,如果是 使用软件生产的 configname 应该为 PRF_1 PRF_2 这里通过判断 1,2 来确定脉冲序号
QSet<QString> configNameSet;
size_t curPRF = 0;
for (int i = 0; i < dataList.size(); i++) {
if (!configNameSet.contains(dataList[i].configurationName)) {
curPRF = curPRF + 1;
}
dataList[i].prfidx = curPRF;
configNameSet.insert(dataList[i].configurationName);
}
// 初始化
for (const QString& elementconfigName : configNameSet) {
this->electricFieldDataList.insert(elementconfigName, std::vector<ElectricFieldData>(0));
}
// 数据初始化
for (size_t i = 0; i < dataList.size(); i++) {
this->electricFieldDataList[dataList[i].configurationName].push_back(dataList[i]);
}
// 每个Pluse 进行排序,按照频率: 小 -> 大,
QMap<QString, std::vector<ElectricFieldData>>::const_iterator it;
for (it = this->electricFieldDataList.constBegin(); it != this->electricFieldDataList.constEnd(); ++it) {
std::sort(this->electricFieldDataList[it.key()].begin(), this->electricFieldDataList[it.key()].end(), compareElectricFieldDataInFreq);
}
// 检查每个electricFieldDataList 是否按照频率进行排序
for (it = this->electricFieldDataList.constBegin(); it != this->electricFieldDataList.constEnd(); ++it) {
for (size_t i = 0; i < this->electricFieldDataList[it.key()].size() - 1; i++) {
if (this->electricFieldDataList[it.key()][i].frequency > this->electricFieldDataList[it.key()][i + 1].frequency) {
qDebug() << u8"发现 configuration Name:" + it.key() + u8" , 发现问题,请检查";
QMessageBox::warning(nullptr, u8"警告", u8"发现 configuration Name:" + it.key() + u8" , 发现问题,请检查");
return false;
}
}
}
if (!this->checkPRFModel() || !this->resizePRFPluse()) {
return false;
}
return true;
}
void FEKOBase::NearFieldEchoCSVParser::toThetapolar(const QString& filePath)
{
this->toEchoData(filePath, 2);
}
void FEKOBase::NearFieldEchoCSVParser::toPhiPolar(const QString& filePath)
{
this->toEchoData(filePath, 1);
}
void FEKOBase::NearFieldEchoCSVParser::toRPolar(const QString& filePath)
{
this->toEchoData(filePath, 0);
}
void FEKOBase::NearFieldEchoCSVParser::saveCSV(const QString& filePath)
{
}
/// <summary>
/// 输出脉冲回波文件
/// </summary>
/// <param name="filePath">文件路径</param>
/// <param name="outDataName">0: R,1: phi,2: theta</param>
void FEKOBase::NearFieldEchoCSVParser::toEchoData(const QString& filePath, size_t outDataName)
{
// 脉冲整理
Eigen::MatrixXcd echoData = Eigen::MatrixXcd::Zero(this->prfData.size(), this->freqPoints);
Eigen::MatrixXd antpos = Eigen::MatrixXd::Zero(this->prfData.size(), 5); //x,y,z,theta,phi"
for (size_t i = 0; i < this->prfData.size(); i++) {
antpos(i, 0) = this->prfData[i].px;
antpos(i, 1) = this->prfData[i].py;
antpos(i, 2) = this->prfData[i].pz;
antpos(i, 3) = this->prfData[i].electricFieldDataList[0].theta;
antpos(i, 4) = this->prfData[i].electricFieldDataList[0].phi;
for (size_t j = 0; j < this->freqPoints; j++) {
if (outDataName == 0) {
echoData(i, j) = std::complex<double>(this->prfData[i].electricFieldDataList[j].reEr, this->prfData[i].electricFieldDataList[j].imEr);
}
else if (outDataName == 1) {
echoData(i, j) = std::complex<double>(this->prfData[i].electricFieldDataList[j].reEphi, this->prfData[i].electricFieldDataList[j].imEphi);
}
else {
echoData(i, j) = std::complex<double>(this->prfData[i].electricFieldDataList[j].reEtheta, this->prfData[i].electricFieldDataList[j].imEtheta);
}
}
}
EchoDataClass echodataTemp;
echodataTemp.setAntPos(antpos);
echodataTemp.setFreqStart(this->freqStart);
echodataTemp.setFreqEnd(this->freqEnd);
echodataTemp.setFreqpoints(this->freqPoints);
echodataTemp.setEchoData(echoData);
echodataTemp.SaveEchoData(filePath);
}
FEKOBase::EchoDataClass::EchoDataClass(const FEKOBase::EchoDataClass& inecho)
{
this->echoData = inecho.getEchoData();
this->antPos = inecho.getAntPos();
this->freqStart = inecho.getFreqStart();
this->freqEnd = inecho.getFreqEnd();
this->freqpoints = inecho.getFreqpoints();
}
FEKOBase::EchoDataClass::EchoDataClass()
{
}
FEKOBase::EchoDataClass::~EchoDataClass()
{
}
void FEKOBase::EchoDataClass::setEchoData(Eigen::MatrixXcd echoData)
{
this->echoData = echoData;
}
Eigen::MatrixXcd FEKOBase::EchoDataClass::getEchoData() const
{
return this->echoData;
}
void FEKOBase::EchoDataClass::setAntPos(Eigen::MatrixXd antPos)
{
this->antPos = antPos;
}
Eigen::MatrixXd FEKOBase::EchoDataClass::getAntPos() const
{
return this->antPos;
}
void FEKOBase::EchoDataClass::setFreqStart(double freqStart)
{
this->freqStart = freqStart;
}
double FEKOBase::EchoDataClass::getFreqStart() const
{
return this->freqStart;
}
void FEKOBase::EchoDataClass::setFreqEnd(double freqEnd)
{
this->freqEnd = freqEnd;
}
double FEKOBase::EchoDataClass::getFreqEnd() const
{
return this->freqEnd;
}
void FEKOBase::EchoDataClass::setFreqpoints(int freqpoints)
{
this->freqpoints = freqpoints;
}
int FEKOBase::EchoDataClass::getFreqpoints() const
{
return this->freqpoints;
}
void FEKOBase::EchoDataClass::loadEchoData(const QString& filePath)
{
std::ifstream file(reinterpret_cast<const wchar_t*>(filePath.utf16()), std::ios::binary);
if (file.is_open()) {
// 保存频率变量
INT32 PRFRow = 0;
INT32 freqCol = 0;
// 读取其他成员变量
file.read(reinterpret_cast<char*>(&freqStart), sizeof(double));
file.read(reinterpret_cast<char*>(&freqEnd), sizeof(double));
file.read(reinterpret_cast<char*>(&freqpoints), sizeof(INT32));
file.read(reinterpret_cast<char*>(&PRFRow), sizeof(INT32));
file.read(reinterpret_cast<char*>(&freqCol), sizeof(INT32));
echoData = Eigen::MatrixXcd::Zero(PRFRow, freqCol); // 重新分配内存
antPos = Eigen::MatrixXd::Zero(PRFRow, 5);
file.read(reinterpret_cast<char*>(antPos.data()), sizeof(double) * PRFRow * 5); // 保存天线位置
file.read(reinterpret_cast<char*>(echoData.data()), sizeof(std::complex<double>) * PRFRow * freqCol); // 保存回波数据
file.close(); // 关闭文件
this->freqStart = freqStart;
this->freqEnd = freqEnd;
this->freqpoints = freqpoints;
this->echoData = echoData;
this->antPos = antPos;
qDebug() << u8"回波数据加载完成";
}
else {
qWarning() << "Error: Unable to open file for reading.";
}
}
void FEKOBase::EchoDataClass::SaveEchoData(const QString& filePath)
{
if (echoData.rows() != antPos.rows() || antPos.cols() != 5) {
qDebug() << "Error: antPos.size()!=echoData.rows()*5"
+ QString::number(echoData.rows()) + u8"!=" + QString::number(antPos.rows())
+ QString::number(antPos.cols()) + u8"!=5";
return;
}
else {}
std::ofstream file(reinterpret_cast<const wchar_t*>(filePath.utf16()), std::ios::binary);
qDebug() << "===================================================================";
qDebug() << u8"回波脉冲文件格式说明:";
qDebug() << u8"|freqStart(double)freqEnd(double)freqpoints(int)|PRFROW(int),PRFCol(int)|antPos|echodata|";
qDebug() << u8"其中antPos: PRFrow*3 double x,y,z,incidence,azangle,theta,phi";
qDebug() << u8"其中echodata: PRFrow*PRFCol complex<double> ";
qDebug() << "===================================================================";
if (file.is_open()) {
INT32 PRFRow = echoData.rows();
INT32 freqCol = echoData.cols();
file.write(reinterpret_cast<const char*>(&freqStart), sizeof(double)); // 保存频率变量
file.write(reinterpret_cast<const char*>(&freqEnd), sizeof(double));
file.write(reinterpret_cast<const char*>(&freqpoints), sizeof(INT32));
file.write(reinterpret_cast<const char*>(&PRFRow), sizeof(INT32));
file.write(reinterpret_cast<const char*>(&freqCol), sizeof(INT32));
file.write(reinterpret_cast<const char*>(antPos.data()), sizeof(double) * antPos.size()); // 保存天线位置
file.write(reinterpret_cast<const char*>(echoData.data()), sizeof(std::complex<double>) * echoData.size()); // 保存回波数据
file.close(); // 关闭文件
}
else {
qDebug() << "Error: Unable to open file for writing.";
}
}
Eigen::MatrixXd FEKOBase::WINDOWFun(Eigen::MatrixXcd& echo, ImageAlgWindowFun winfun)
{
size_t Nxa = echo.rows();
size_t Nf = echo.cols();
Eigen::MatrixXd normw = Eigen::MatrixXd::Zero(Nxa, Nf); // 归一化窗函数
if (winfun == ImageAlgWindowFun::HANMMING) {
normw = Hanning(Nf, Nxa);
echo = echo.array() * normw.array();
}
else {
normw = normw.array() * 0 + 1 / (Nxa * Nf);
}
return normw;
}
QList<QString> FEKOBase::getFEKOImageAlgorithmList()
{
QList<QString> list;
FEKOImageAlgorithm alg;
for (alg = FEKOImageAlgorithm::TBP_TIME; alg < FEKOImageAlgorithm::UNKONW; alg = (FEKOImageAlgorithm)(alg + 1)) {
list.append(FEKOImageAlgorithm2String(alg));
}
return list;
}
FEKOBase::FEKOImageAlgorithm FEKOBase::String2FEKOImageAlgorithm(QString str)
{
FEKOImageAlgorithm alg;
for (alg = FEKOImageAlgorithm::TBP_TIME; alg < FEKOImageAlgorithm::UNKONW; alg = (FEKOImageAlgorithm)(alg + 1)) {
if (str == FEKOImageAlgorithm2String(alg)) {
return alg;
}
else {}
}
return alg;
}
QString FEKOBase::FEKOImageAlgorithm2String(FEKOImageAlgorithm alg)
{
// 将FEKOImageAlgorithm 枚举转换为字符串
switch (alg)
{
case FEKOBase::TBP_TIME:
return u8"TBP_TIME";
case FEKOBase::TBP_FREQ:
return u8"TBP_FREQ";
default:
return u8"UNKONW";
}
}
// 请仿照FEKOImageAlgorithm枚举的写法构建QString 与 ImageAlgWindowFun 的转换函数
QList<QString> FEKOBase::getImageAlgWindowFunList()
{
QList<QString> list;
ImageAlgWindowFun alg;
for (alg = ImageAlgWindowFun::NOWINDOWS; alg < ImageAlgWindowFun::UNKONWWINDOW; alg = (ImageAlgWindowFun)(alg + 1)) {
list.append(ImageAlgWindowFun2String(alg));
}
return list;
}
FEKOBase::ImageAlgWindowFun FEKOBase::String2ImageAlgWindowFun(QString str)
{
ImageAlgWindowFun alg;
for (alg = ImageAlgWindowFun::UNKONWWINDOW; alg < ImageAlgWindowFun::UNKONWWINDOW; alg = (ImageAlgWindowFun)(alg + 1)) {
if (str == ImageAlgWindowFun2String(alg)) {
return alg;
}
else {}
}
return alg;
}
QString FEKOBase::ImageAlgWindowFun2String(FEKOBase::ImageAlgWindowFun alg)
{
switch (alg)
{
case FEKOBase::NOWINDOWS:
return u8"NOWINDOWS";
case FEKOBase::HANMMING:
return u8"HANMMING";
default:
return u8"UNKONWWINDOW";
}
}
bool FEKOBase::BPImage_TIME(QString& restiffpath, Eigen::MatrixXcd& echoData, Eigen::MatrixXd& antPos, Eigen::MatrixXd& freqmatrix, Eigen::MatrixXd& X, Eigen::MatrixXd& Y, Eigen::MatrixXd& Z, ImageAlgWindowFun winfun)
{
// BP成像算法
const double c = 0.299792458; // 光速
return true;
}
bool FEKOBase::FBPImage_FREQ(QString& restiffpath, Eigen::MatrixXcd& echoData, Eigen::MatrixXd& antPos, Eigen::MatrixXd& freqmatrix, Eigen::MatrixXd& X, Eigen::MatrixXd& Y, Eigen::MatrixXd& Z, ImageAlgWindowFun winfun)
{
// BP成像算法
const double c = 0.299792458; // 光速
const std::complex<double> j(0, 1); // 虚数单位
const size_t image_height = X.rows();
const size_t image_width = X.cols();
const size_t PRFCount = echoData.rows();
const size_t frepoints = echoData.cols();
Eigen::MatrixXcd factorj = Eigen::MatrixXcd::Zero(1, echoData.cols()); // 1 , freqs
factorj = freqmatrix.array().cast<std::complex<double>>().array() * j * 4 * M_PI / c; // 声明校正矩阵
Eigen::MatrixXcd im_final = Eigen::MatrixXcd::Zero(image_height, image_width);
#ifdef __SHOWPROCESS // 进度条展示
QProgressDialog progressDialog(u8"BP_FREQ成像进度", u8"终止", 0, image_height);
progressDialog.setWindowTitle(u8"成像中");
progressDialog.setWindowModality(Qt::WindowModal);
progressDialog.setAutoClose(true);
progressDialog.setValue(0);
progressDialog.setMaximum(image_height);
progressDialog.setMinimum(0);
progressDialog.show();
#endif // __SHOWPROCESS
#ifdef __SHOWIMAGEPROCESSRESULT // 加窗处理
Eigen::MatrixXd normw = WINDOWFun(echoData, winfun);
#endif
#ifdef __IMAGEPARALLEL
#pragma omp parallel for
for (long ii = 0; ii < image_height; ii++)
{
Eigen::MatrixXd im_R = Eigen::MatrixXd::Zero(PRFCount, 1);// 图像到脉冲矩阵 prf*1
Eigen::MatrixXcd term_R = Eigen::MatrixXcd::Zero(1, frepoints);
Eigen::MatrixXcd pluse_R = Eigen::MatrixXcd::Zero(PRFCount, 1);
for (size_t jj = 0; jj < image_width; jj++) {
im_R.col(0) = ((antPos.col(0).array() - X(ii, jj)).array().pow(2) +
(antPos.col(1).array() - Y(ii, jj)).array().pow(2) +
(antPos.col(2).array() - Z(ii, jj)).array().pow(2))
.array().sqrt().array(); // 获取目标到天线矩阵 计算 ok
// im_R PRF_count x 1
for (size_t tt = 0; tt < PRFCount; tt++) {
term_R = (im_R(tt, 0) * factorj.array()).array().exp(); // ok
pluse_R(tt, 0) = (echoData.row(tt).array() * term_R.array()).sum(); // 对每个脉冲校正求和
}
im_final(ii, jj) = pluse_R.array().sum(); // 计算图像
}
}
#else
Eigen::MatrixXd im_R = Eigen::MatrixXd::Zero(PRFCount, 1);// 图像到脉冲矩阵 prf*1
Eigen::MatrixXcd term_R = Eigen::MatrixXcd::Zero(1, frepoints);
Eigen::MatrixXcd pluse_R = Eigen::MatrixXcd::Zero(PRFCount, 1);
for (long ii = 0; ii < image_height; ii++)
{
for (size_t jj = 0; jj < image_width; jj++) {
im_R.col(0) = ((antPos.col(0).array() - X(ii, jj)).array().pow(2) +
(antPos.col(1).array() - Y(ii, jj)).array().pow(2) +
(antPos.col(2).array() - Z(ii, jj)).array().pow(2))
.array().sqrt().array(); // 获取目标到天线矩阵 计算 ok
// im_R PRF_count x 1
for (size_t tt = 0; tt < PRFCount; tt++) {
term_R = (im_R(tt, 0) * factorj.array()).array().exp(); // ok
pluse_R(tt, 0) = (echoData.row(tt).array() * term_R.array()).sum(); // 对每个脉冲校正求和
}
im_final(ii, jj) = pluse_R.array().sum(); // 计算图像
}
#ifdef __SHOWPROCESS
progressDialog.setValue(ii);
#endif
}
#endif
#ifdef __SHOWIMAGEPROCESSRESULT // 加窗处理
im_final = im_final.array() / (normw.array().sum());
#endif
// 3. 保存图像
QString newrestiffpath = restiffpath;
Eigen::MatrixXd gt = Eigen::MatrixXd::Zero(2,3);
gt(0, 0) = X(0, 0);
gt(0, 1) = X(0, 1) - X(0, 0);
gt(0, 2) = 0;
gt(1, 0) = Y(0, 0);
gt(1, 1) = 0;
gt(1, 2) = Y(0, 0) - Y(1, 0);
std::cout << gt << std::endl;
gdalImageComplex im_final_gdal = CreategdalImageComplex(restiffpath,im_final.rows(),im_final.cols(),1,gt, QString(u8""), true,true);
im_final_gdal.setData(im_final);
im_final_gdal.saveImage();
qDebug() << QString(u8"保存文件地址:" + restiffpath);
#ifdef __SHOWPROCESS
progressDialog.setWindowTitle(u8"保存文件:" + restiffpath);
progressDialog.setValue(image_height);
progressDialog.close();
#endif
// 绘制图像
#ifdef __SHOWIMAGEPROCESSRESULT
// 将复数矩阵的幅度转换为实数矩阵
matplot::figure();
matplot::vector_2d amplitude_im_final(im_final.rows(), matplot::vector_1d(im_final.cols()));
for (int i = 0; i < im_final.rows(); ++i) {
for (int j = 0; j < im_final.cols(); ++j) {
amplitude_im_final[i][j] = std::abs(im_final(i, j));
}
}
matplot::imagesc(amplitude_im_final);
matplot::colorbar();
matplot::show();
#endif // __SHOWMATPLOTLIBCPP
return true;
}