Qt C++ 数据预处理笔记(4)——高通滤波

发布时间:2023年12月28日

#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;
            }
        }
    }
}

#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

这个有界面:

#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();
}
#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
//高通滤波
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);
}

关键代码来源于小周老师。有个问题,不同的长度,结果有差异。

文章来源:https://blog.csdn.net/tadpole_java/article/details/135238540
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。