26#include <QRegularExpression>
44 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
45 qWarning() <<
"[FineCalibration::read] Cannot open file:" << sPath;
49 QTextStream in(&file);
51 QString line = in.readLine().trimmed();
52 if (line.isEmpty() || line.startsWith(
'#')) {
56 const QStringList parts = line.split(QRegularExpression(
"\\s+"), Qt::SkipEmptyParts);
57 if (parts.size() != 14 && parts.size() != 16) {
58 qWarning() <<
"[FineCalibration::read] Skipping malformed line:" << line;
64 entry.
chNumber = QString(parts[0]).remove(QStringLiteral(
"MEG")).toInt(&ok);
65 VectorXd values(parts.size() - 1);
66 for (
int k = 1; ok && k < parts.size(); ++k) {
67 values(k - 1) = parts[k].toDouble(&ok);
70 qWarning() <<
"[FineCalibration::read] Skipping malformed line:" << line;
74 entry.
orientation = Map<const Matrix<double, 3, 3, RowMajor>>(values.data() + 3);
75 entry.
imbalance = values.tail(values.size() - 12);
89 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
90 qWarning() <<
"[FineCalibration::write] Cannot open file for writing:" << sPath;
94 QTextStream out(&file);
95 for (
const auto& entry : m_entries) {
96 out << QString(
"%1").arg(entry.chNumber, 4, 10, QChar(
'0'));
97 const Matrix<double, 3, 3, RowMajor> axes = entry.orientation;
98 for (
const double v : {entry.position(0), entry.position(1), entry.position(2)}) {
99 out <<
' ' << QString::number(v,
'f', 6);
101 for (
int k = 0; k < 9; ++k) {
102 out <<
' ' << QString::number(axes.data()[k],
'f', 6);
104 for (Index k = 0; k < entry.imbalance.size(); ++k) {
105 out <<
' ' << QString::number(entry.imbalance(k),
'f', 6);
118 for (
const auto& e : m_entries) {
119 if (e.chNumber == chNumber) {
131 VectorXd gains = VectorXd::Ones(m_entries.size());
132 for (
int i = 0; i < m_entries.size(); ++i) {
133 if (m_entries[i].chNumber % 10 == 1) {
134 gains(i) = m_entries[i].imbalance(0);
144 MatrixXd imb = MatrixXd::Zero(m_entries.size(), 3);
145 for (
int i = 0; i < m_entries.size(); ++i) {
146 if (m_entries[i].chNumber % 10 != 1) {
147 imb.row(i).head(m_entries[i].imbalance.size()) = m_entries[i].imbalance.transpose();
Fine calibration data for SSS.
Shared utilities (I/O helpers, spectral analysis, layout management, warp algorithms).
Per-sensor fine calibration entry.
Eigen::VectorXd imbalance
Eigen::Matrix3d orientation
bool findEntry(int chNumber, FineCalEntry &entry) const
Find entry by channel number.
Eigen::MatrixXd imbalanceMatrix() const
Gradiometer imbalance terms.
bool write(const QString &sPath) const
Write fine calibration to a .dat file.
FineCalibration()=default
Eigen::VectorXd gainVector() const
Magnetometer calibration factors.
void addEntry(const FineCalEntry &entry)
Add an entry.
static FineCalibration read(const QString &sPath)
Read a fine calibration file (.dat format).