feat: AiAnalysis - 16通道AI数据UDP实时采集与分析
功能: - UDP端口监听,实时接收数据 - 解析16通道逗号分隔的ADC数据 - 实时波形绘制(支持滚轮缩放、右键拖拽、双击恢复) - 数据自动保存到 data_端口号/ 目录 - 支持打开历史CSV文件回放查看 - 16通道独立颜色,可切换显示/隐藏 - 深色主题界面
This commit is contained in:
127
datamanager.cpp
Normal file
127
datamanager.cpp
Normal file
@@ -0,0 +1,127 @@
|
||||
#include "datamanager.h"
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
|
||||
DataManager::DataManager(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_recording(false)
|
||||
, m_headerWritten(false)
|
||||
{
|
||||
}
|
||||
|
||||
DataManager::~DataManager()
|
||||
{
|
||||
stopRecording();
|
||||
}
|
||||
|
||||
bool DataManager::startRecording(const QString &dirPath)
|
||||
{
|
||||
stopRecording();
|
||||
|
||||
QDir dir(dirPath);
|
||||
if (!dir.exists()) {
|
||||
if (!dir.mkpath(".")) {
|
||||
qWarning() << "无法创建目录:" << dirPath;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
QString fileName = QDateTime::currentDateTime().toString("yyyy-MM-dd_HH-mm-ss") + ".csv";
|
||||
m_filePath = dir.filePath(fileName);
|
||||
|
||||
m_file.setFileName(m_filePath);
|
||||
if (!m_file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
qWarning() << "无法创建文件:" << m_filePath;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_stream.setDevice(&m_file);
|
||||
m_headerWritten = false;
|
||||
m_recording = true;
|
||||
|
||||
qDebug() << "开始记录数据到:" << m_filePath;
|
||||
return true;
|
||||
}
|
||||
|
||||
void DataManager::stopRecording()
|
||||
{
|
||||
if (m_recording) {
|
||||
m_stream.flush();
|
||||
m_file.close();
|
||||
m_recording = false;
|
||||
qDebug() << "停止记录, 文件:" << m_filePath;
|
||||
}
|
||||
}
|
||||
|
||||
bool DataManager::isRecording() const
|
||||
{
|
||||
return m_recording;
|
||||
}
|
||||
|
||||
QString DataManager::currentFilePath() const
|
||||
{
|
||||
return m_filePath;
|
||||
}
|
||||
|
||||
void DataManager::appendDataPoint(const QVector<int> &values)
|
||||
{
|
||||
if (!m_recording) return;
|
||||
|
||||
if (!m_headerWritten) {
|
||||
// 写入表头
|
||||
QStringList headers;
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
headers << QString("ch%1").arg(i);
|
||||
}
|
||||
m_stream << headers.join(",") << "\n";
|
||||
m_headerWritten = true;
|
||||
}
|
||||
|
||||
QStringList parts;
|
||||
for (int v : values) {
|
||||
parts << QString::number(v);
|
||||
}
|
||||
m_stream << parts.join(",") << "\n";
|
||||
}
|
||||
|
||||
QVector<QVector<double>> DataManager::loadFile(const QString &filePath, QString &error)
|
||||
{
|
||||
QVector<QVector<double>> result(16);
|
||||
|
||||
QFile file(filePath);
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
error = QString("无法打开文件: %1").arg(filePath);
|
||||
return result;
|
||||
}
|
||||
|
||||
QTextStream stream(&file);
|
||||
bool firstLine = true;
|
||||
|
||||
while (!stream.atEnd()) {
|
||||
QString line = stream.readLine().trimmed();
|
||||
if (line.isEmpty()) continue;
|
||||
|
||||
// 跳过表头
|
||||
if (firstLine) {
|
||||
firstLine = false;
|
||||
// 检查是否是表头(包含非数字字符如ch)
|
||||
if (line.contains("ch", Qt::CaseInsensitive) && !line.at(0).isDigit()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
QStringList parts = line.split(",");
|
||||
if (parts.size() < 16) continue;
|
||||
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
bool ok;
|
||||
double val = parts[i].toDouble(&ok);
|
||||
if (ok) {
|
||||
result[i].append(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
file.close();
|
||||
return result;
|
||||
}
|
||||
Reference in New Issue
Block a user