cpp
#include "HighPassFilter.h"
HighPassFilter::HighPassFilter(int iRow, QString oStrFileName, int iStart, int iEnd, QObject* parent)
: QObject{parent}, iRow(iRow), oStrFileName(oStrFileName), iStart(iStart), iEnd(iEnd)
{
oHead = PF::readHead(oStrFileName);
times = pow(2, log10(iEnd - iStart));
}
void HighPassFilter::run()
{
QElapsedTimer time;
time.start();
QFile oFile(oStrFileName);
if( !oFile.open(QIODevice::ReadOnly) )
{
return;
}
QDataStream oStream(&oFile);
oStream.setByteOrder(QDataStream::BigEndian);
oStream.setFloatingPointPrecision(QDataStream::SinglePrecision);
oStream.skipRawData(LENGTH_178_BYTE);//作者是靠占位符来占据首行的。
for(int i = 0; i < iStart; ++i)
{
oStream.skipRawData(oHead.uiFS * LENGTH_4_BYTE);
}
oStream.startTransaction();
double value = 0;
QVector<double> adSegmentX(HIGH_PASS_FILTERED_LENGTH);
QVector<double> in(HIGH_PASS_FILTERED_LENGTH);
QVector<double> out(HIGH_PASS_FILTERED_LENGTH);
in.clear();
out.clear();
adSegmentX.clear();
in.squeeze();
out.squeeze();
adSegmentX.squeeze();
quint32 uiPercentage = PROGRESS_STEP;
for(quint64 i = oHead.uiFS * iStart; i < oHead.uiFS * iEnd; i++)
{
oStream >> value;
adSegmentX.append(oHead.iStartTimestamp + (double)i / (double)oHead.uiFS);
in.append(value);
if(in.size() == HIGH_PASS_FILTERED_LENGTH)
{
out = this->filter(in, HIGH_PASS_FILTERED_LENGTH);
this->dilution(adSegmentX, in, out);
adSegmentX.clear();
adSegmentX.squeeze();
in.clear();
in.squeeze();
out.clear();
out.squeeze();
}
float fProgress = ((float)(i) / ((float)oHead.uiFS * (iEnd - iStart))) * 100;
if(fProgress >= uiPercentage)
{
emit sigProgress(iRow, "处理中~ ", fProgress);
uiPercentage = uiPercentage + PROGRESS_STEP;
}
}
oStream.commitTransaction();
oFile.close();
emit sigProgress(iRow, "处理完毕!", 100.00);
qint64 milsec = time.elapsed();
emit sigMsg(QString("行号:%1\t加载采样点个数:%2\t耗时:%3s\t高通滤波")
.arg(iRow + 1)
.arg(oHead.uiFS * (iEnd - iStart))
.arg(QString::number(milsec / 1000.00, 'f', 3)));
}
QVector<double> HighPassFilter::filter(QVector<double> TestData, int DataCnt)
{
QVector<double> HPData(DataCnt);
for(int i = 0; i < TestData.size(); i++) //TestData是读取的原始数据,注意读取的时候的数据类型需要是duble不然会因为fLoat类型丢失精度
{
double testb = 0.0;
double testa = 0.0;
if(i < sizeB - 1)
{
for(int j = i; j >= 0; j--)
{
testb += HPcoeffB[i - j] * TestData[j];
}
}
else //作为测试,这里是写死的因为这样速度更快,暂时认为高通滤波系数为提供的固定值,后续需要更改
{
testb = HPcoeffB[0] * TestData[i] +
HPcoeffB[1] * TestData[i - 1] +
HPcoeffB[2] * TestData[i - 2] +
HPcoeffB[3] * TestData[i - 3] +
HPcoeffB[4] * TestData[i - 4] +
HPcoeffB[5] * TestData[i - 5] +
HPcoeffB[6] * TestData[i - 6] +
HPcoeffB[7] * TestData[i - 7] +
HPcoeffB[8] * TestData[i - 8] +
HPcoeffB[9] * TestData[i - 9];
}
if(i > 0)
{
if(i < sizeA - 1)
{
for(int j = i - 1; j >= 0; j--)
{
testa += HPcoeffA[i - j] * HPData[j];
}
}
else //作为测试,这里是写死的因为这样速度更快,暂时认为高通滤波系数为提供的固定值,后续需要更改
{
testa = HPcoeffA[1] * HPData[i - 1] +
HPcoeffA[2] * HPData[i - 2] +
HPcoeffA[3] * HPData[i - 3] +
HPcoeffA[4] * HPData[i - 4] +
HPcoeffA[5] * HPData[i - 5] +
HPcoeffA[6] * HPData[i - 6] +
HPcoeffA[7] * HPData[i - 7] +
HPcoeffA[8] * HPData[i - 8] +
HPcoeffA[9] * HPData[i - 9];
}
}
HPData[i] = testb - testa;
}
return HPData;
}
void HighPassFilter::dilution(QVector<double> adX, QVector<double> adY_in, QVector<double> adY_out)
{
int length = (HIGH_PASS_FILTERED_LENGTH / 1024);
for(int i = 0; i < 1024; ++i )
{
extremum( DATA_RAW,
adX.mid(i * length, length),
adY_in.mid(i * length, length));
extremum( DATA_FILTERED,
adX.mid(i * length, length),
adY_out.mid(i * length, length));
}
if(adX_raw.count() >= 1024)
{
emit sigData(iRow, DATA_RAW, adX_raw, adY_raw);
emit sigData(iRow, DATA_FILTERED, adX_hpf, adY_hpf);
adX_raw.clear();
adY_raw.clear();
adX_hpf.clear();
adY_hpf.clear();
adX_raw.squeeze();
adY_raw.squeeze();
adX_hpf.squeeze();
adY_hpf.squeeze();
}
}
void HighPassFilter::extremum(DATA_TYPE eDataType, QVector<double> x, QVector<double> y)
{
if(x.count() <= 2)
{
switch (eDataType)
{
case DATA_RAW:
adX_raw.append(x);
adY_raw.append(y);
break;
case DATA_FILTERED:
adX_hpf.append(x);
adY_hpf.append(y);
break;
default:
break;
}
}
else
{
auto max = std::max_element(std::begin(y), std::end(y));
auto min = std::min_element(std::begin(y), std::end(y));
auto positionmax = std::distance(std::begin(y), max);
auto positionmin = std::distance(std::begin(y), min);
int posmax = positionmax;
int posmin = positionmin;
if(posmin < posmax)
{
switch (eDataType)
{
case DATA_RAW:
adX_raw.append(x.at(posmin));
adY_raw.append(y.at(posmin));
adX_raw.append(x.at(posmax));
adY_raw.append(y.at(posmax));
break;
case DATA_FILTERED:
adX_hpf.append(x.at(posmin));
adY_hpf.append(y.at(posmin));
adX_hpf.append(x.at(posmax));
adY_hpf.append(y.at(posmax));
break;
default:
break;
}
}
else
{
switch (eDataType)
{
case DATA_RAW:
adX_raw.append(x.at(posmax));
adY_raw.append(y.at(posmax));
adX_raw.append(x.at(posmin));
adY_raw.append(y.at(posmin));
break;
case DATA_FILTERED:
adX_hpf.append(x.at(posmax));
adY_hpf.append(y.at(posmax));
adX_hpf.append(x.at(posmin));
adY_hpf.append(y.at(posmin));
break;
default:
break;
}
}
}
}
cpp
#ifndef HIGHPASSFILTER_H
#define HIGHPASSFILTER_H
#include "PF.h"
#include <QObject>
#include <QRunnable>
class HighPassFilter : public QObject, public QRunnable
{
Q_OBJECT
public:
explicit HighPassFilter(int iRow, QString oStrFileName, int iStart, int iEnd, QObject* parent = nullptr);
void run() override;
QVector<double> filter(QVector<double> TestData, int DataCnt);
void dilution(QVector<double> adX, QVector<double> adY_in, QVector<double> adY_out);
/* 给定的x, y数组; 返回的是一对最小值和一对最大值 */
void extremum(DATA_TYPE eDataType, QVector<double> x, QVector<double> y);
signals:
void sigData(int iRow, DATA_TYPE, QVector<double> x, QVector<double> y);
void sigProgress(int, QString, float);
void sigMsg(QString);
private:
// 使用你提供的系数
QVector<double> HPcoeffA = {1, -7.869418904996362, 27.586910329781470, -56.537228014951000, 74.643630533230250, -65.831482420294930, 38.781248457435920, -14.713983344295070, 3.262353900872095, -0.322030283384344};
QVector<double> HPcoeffB = {0.567477121463362, -5.107294093170260, 20.429176372681038, -47.668078202922420, 71.502117304383630, -71.502117304383630, 47.668078202922420, -20.429176372681038, 5.107294093170260, -0.567477121463362};
int sizeA = HPcoeffA.size();
int sizeB = HPcoeffB.size();
int iRow;
QString oStrFileName;
int iStart;//秒序列,
int iEnd;
HEAD oHead;
QVector<double> adX_raw, adY_raw;
QVector<double> adX_hpf, adY_hpf;
int times = 1;
};
#endif // HIGHPASSFILTER_H
这个有界面:
cpp
#include "FilterWidget.h"
#include "ui_FilterWidget.h"
FilterWidget::FilterWidget(int iRow, QString oStrFileName, int iStart, int iEnd, QWidget* parent) :
QWidget(parent), ui(new Ui::FilterWidget), iRow(iRow), oStrFileName(oStrFileName), iStart(iStart), iEnd(iEnd)
{
ui->setupUi(this);
ui->plot->showTracer(false);
//ui->plot->xAxis->setLabel("时间"); //X轴文字显示
ui->plot->yAxis->setLabel("振幅(mV)"); //Y轴文字显示
QSharedPointer<QCPAxisTickerDateTime> dateTicker(new QCPAxisTickerDateTime);//日期做X轴
dateTicker->setDateTimeFormat("yyyy年MM月dd日\nHH:mm:ss");//日期格式(可参考QDateTime::fromString()函数)
ui->plot->xAxis->setTicker(dateTicker);//设置X轴为时间轴
ui->plot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables | QCP::iSelectLegend | QCP::iSelectAxes);
QList<QCPAxis*> axes;
axes << ui->plot->xAxis2 << ui->plot->xAxis;
ui->plot->axisRect()->setRangeZoomAxes(axes);
ui->plot->setZoomAxis(ZOOM_X);
ui->plot->xAxis->grid()->setZeroLinePen(QPen(Qt::red)); //设置刻度为0时的网格线的画笔
ui->plot->yAxis->grid()->setZeroLinePen(QPen(Qt::red));
ui->plot->legend->setVisible(true);
ui->plot->legend->setFont(QFont("Helvetica", 12));
poGraperTD_raw = ui->plot->addGraph( ui->plot->xAxis, ui->plot->yAxis);
poGraperTD_raw->setName("Original");
QThread* poThreadRaw = new QThread;
poGraperTD_raw->setParent(nullptr);
poGraperTD_raw->moveToThread(poThreadRaw);
poGraperTD_fld = ui->plot->addGraph( ui->plot->xAxis, ui->plot->yAxis);
poGraperTD_fld->setName("High pass filtered");
QThread* poThreadFld = new QThread;
poGraperTD_fld->setParent(nullptr);
poGraperTD_fld->moveToThread(poThreadFld);
poGraperTD_fld->setPen(QPen(Qt::red, 2));
oHead = PF::readHead(oStrFileName);
ui->plot->xAxis->setRange(oHead.iStartTimestamp + iStart, oHead.iStartTimestamp + iEnd);
ui->plot->plotLayout()->insertRow(0);
QCPTextElement* m_title = new QCPTextElement(ui->plot, oStrFileName, QFont("Times", 16, QFont::Bold));
ui->plot->plotLayout()->addElement(0, 0, m_title);
}
FilterWidget::~FilterWidget()
{
delete ui;
}
void FilterWidget::recvData(int iRow, DATA_TYPE eDataType, QVector<double> x, QVector<double> y)
{
//qDebugV0() << iRow << x << y;
if(iRow != this->iRow)
{
return;
}
switch (eDataType)
{
case DATA_RAW:
poGraperTD_raw->addData(x, y);
//poGraperTD_raw->rescaleValueAxis();
break;
case DATA_FILTERED:
poGraperTD_fld->addData(x, y);
poGraperTD_fld->rescaleValueAxis();
break;
default:
break;
}
ui->plot->replot();
}
cpp
#ifndef FILTERWIDGET_H
#define FILTERWIDGET_H
#include "PF.h"
#include "QCustomPlot/qcustomplot.h"
#include <QWidget>
namespace Ui
{
class FilterWidget;
}
class FilterWidget : public QWidget
{
Q_OBJECT
public:
explicit FilterWidget(int iRow, QString oStrFileName, int iStart, int iEnd, QWidget* parent = nullptr);
~FilterWidget();
void recvData(int iRow, DATA_TYPE, QVector<double> x, QVector<double> y);
private:
Ui::FilterWidget* ui;
int iRow;
QString oStrFileName;
int iStart;
int iEnd;
HEAD oHead;
QCPGraph* poGraperTD_raw;
QCPGraph* poGraperTD_fld;
};
#endif // FILTERWIDGET_H
cpp
//高通滤波
void MainWindow::on_pushButtonHighPassFilter_clicked()
{
QList<int> aiRow = PF::getSelectedRows(ui->tableWidget);
if(aiRow.isEmpty())
{
return;
}
QTabWidget* poTabWidget = new QTabWidget;
poTabWidget->setMinimumSize(1024, 633);
poTabWidget->setWindowTitle("高通滤波");
for(int i = 0; i < aiRow.count(); ++i)
{
QString oStrFileName = ui->tableWidget->item(aiRow.at(i), TABLE_HEADER_FILE_NAME)->data(Qt::DisplayRole).toString();
QSpinBox* poSpinBoxStart = (QSpinBox*)ui->tableWidget->cellWidget(aiRow.at(i), TABLE_HEADER_START_SECOND);
QSpinBox* poSpinBoxEnd = (QSpinBox*)ui->tableWidget->cellWidget(aiRow.at(i), TABLE_HEADER_END_SECOND);
FilterWidget* poWidget = new FilterWidget(aiRow.at(i), oStrFileName, poSpinBoxStart->value(), poSpinBoxEnd->value());
poTabWidget->insertTab(i, poWidget, QString("第%1行").arg(aiRow.at(i) + 1));
HighPassFilter* poWorker = new HighPassFilter(aiRow.at(i),
oStrFileName,
poSpinBoxStart->value(),
poSpinBoxEnd->value());
poWorker->setParent(nullptr);
connect(poWorker, &HighPassFilter::sigData, poWidget, &FilterWidget::recvData);
connect(poWorker, &HighPassFilter::sigProgress, this, &MainWindow::recvProgress);
connect(poWorker, &HighPassFilter::sigMsg, this, &MainWindow::recvMsg);
QThreadPool::globalInstance()->start(poWorker);
}
poTabWidget->show();
PF::scrollToRigth(ui->tableWidget);
}
关键代码来源于小周老师。有个问题,不同的长度,结果有差异。