SigPack 使用说明(MSYS2 Qt5 64-bit)
最后更新:2017.11.16 by L.Song
注:SigPack 基于 Armadillo,需要依赖 Armadillo、OpenBLAS 和 FFTW 支持。
一、OpenBLAS 安装和使用
安装说明:
运行【开始菜单】【MSYS2 64bit】“MSYS2 MSYS”快捷方式。
输入(这里安装的是 64-bit)
pacman -S --needed mingw-w64-x86_64-openblas
然后回车,完成安装。
使用示例:
在项目“.pro”文件中,添加
# 引用库 OpenBLAS
LIBS += -llibopenblas
LIBS += -llibpthread
LIBS += -llibgfortran
下面是关于调用 CBLAS 接口的示例,注意头文件的使用。
程序代码如下:
#include
#include
#include "OpenBLAS/cblas.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
int i=0;
double A[6] = {1.0,2.0,1.0,-3.0,4.0,-1.0};
double B[6] = {1.0,2.0,1.0,-3.0,4.0,-1.0};
double C[9] = {.5,.5,.5,.5,.5,.5,.5,.5,.5};
1
cblas_dgemm(CblasColMajor, CblasNoTrans, CblasTrans,3,3,2,1,A, 3, B,
3,2,C,3);
for(i=0; i<9; i++)
{
qDebug() << C[i];
}
qDebug() << endl;
return a.exec();
}
程序输出结果:11 -9 5 -9 21 -1 5 -1 3
二、Armadillo 安装和使用
方式(1):推荐这种做法
安装说明:
运行【开始菜单】【MSYS2 64bit】“MSYS2 MSYS”快捷方式。
输入(这里安装的是 64-bit)
pacman -S --needed mingw-w64-x86_64-armadillo
然后回车,完成安装。
【★ 提醒修改】说明:
在 Armadillo 的头文件“config.hpp”中,
一定要注释掉 #define ARMA_USE_WRAPPER
即最终效果 //#define ARMA_USE_WRAPPER
否则,无法连接使用 OpenBLAS 库。
在项目“.pro”文件中,添加
# 引用库 Armadillo + OpenBLAS
#LIBS += -llibarmadillo
LIBS += -llibopenblas
LIBS += -llibpthread
2
LIBS += -llibgfortran
或者(目前看都可以,先用着上面的吧)
# 引用库 Armadillo + OpenBLAS
LIBS += -llibarmadillo
LIBS += -llibopenblas
LIBS += -llibpthread
LIBS += -llibgfortran
方式(2):这里没有注释掉 #define ARMA_USE_WRAPPER
(不知为何,如果按照这种方式,例如产生随机数矩阵会有错误,全是 0)
(因此,不推荐这种方式)
安装说明:
运行【开始菜单】【MSYS2 64bit】“MSYS2 MSYS”快捷方式。
输入(这里安装的是 64-bit)
pacman -S --needed mingw-w64-x86_64-hdf5
pacman -S --needed mingw-w64-x86_64-armadillo
然后回车,完成安装。
说明:HDF5 是用于存储和分发科学数据的一种自我描述、多对象文件格式,
在 Armadillo 的头文件“config.hpp”中有用到。
【★ Armadillo 安装后需要修改】修改说明:
在 Armadillo 的头文件“config.hpp”中,一共有六处,
需要将文件夹 C:/building/msys64/mingw64/
修改为 D:/ProgramOther/msys64/mingw64/
这才是正确的 MSYS2 MinGW-w64 64-bit 实际安装目录。否则编译报错。
在项目“.pro”文件中,添加
# 引用库 Armadillo + OpenBLAS
LIBS += -llibarmadillo
3
LIBS += -llibhdf5
LIBS += -llibopenblas
LIBS += -llibpthread
LIBS += -llibgfortran
使用示例:(Armadillo + 依赖 OpenBLAS)
方式(1)、方式(2)采用同一个示例,注意头文件的使用。代码如下:
#include
#include
#include
using namespace std;
using namespace arma;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// Initialize the random generator
arma_rng::set_seed_random();
// Create a 4x4 random matrix and print it on the screen
Mat A = randu(4,4);
cout << "A:\n" << A << "\n";
// Multiply A with his transpose:
cout << "A * A.t() =\n";
cout << A * A.t() << "\n";
// Access/Modify rows and columns from the array:
A.row(0) = A.row(1) + A.row(3);
A.col(3).zeros();
cout << "add rows 1 and 3, store result in row 0, also fill 4th column
with zeros:\n";
cout << "A:\n" << A << "\n";
// Create a new diagonal matrix using the main diagonal of A:
MatB = diagmat(A);
cout << "B:\n" << B << "\n";
// Save matrices A and B:
4
A.save("A_mat.txt", arma_ascii);
B.save("B_mat.txt", arma_ascii);
return a.exec();
}
三、FFTW 安装和使用
安装说明:
运行【开始菜单】【MSYS2 64bit】“MSYS2 MSYS”快捷方式。
输入(这里安装的是 64-bit)
pacman -S --needed mingw-w64-x86_64-fftw
然后回车,完成安装。
使用示例:
在项目“.pro”文件中,添加
# 引用库 FFTW
LIBS += -llibfftw3
LIBS += -llibfftw3f
LIBS += -llibfftw3l
注意头文件的使用。程序代码如下:
#include
#include // 文件操作
#include // 输出调试信息
#include // 常用数学函数库
#include // 高精度(us 级)计时
#include "fftw3.h"
using namespace std;
#define PI 3.1415926535897932 // 圆周率
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
5
// 运行计时(高精度,微秒级 us)
LARGE_INTEGER litmp;
QueryPerformanceFrequency(&litmp); // 取得高精度运行计数器的频率 f,单位
是每秒多少次
double dfFreq = (double)litmp.QuadPart;
QueryPerformanceCounter(&litmp); // 取得高精度运行计数器的数值
LONGLONG qpartBegin = litmp.QuadPart; // 记录当前时钟 ---- 总的开始
int nlen = 8192; // 数据点数
double * input = (double *)fftw_malloc(sizeof(double) * nlen);
fftw_complex * output = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) *
nlen);
qreal * mag = new qreal[nlen]; // 幅值
qreal * pha = new qreal[nlen]; // 相位
// FFT 创建变换方案(fftw_plan)
fftw_plan p = fftw_plan_dft_r2c_1d(nlen, input, output, FFTW_MEASURE);
// FFT 执行变换 ---- 第一次执行,耗时较长,自动选最优方案(对应上面
FFTW_MEASURE)
fftw_execute(p);
QueryPerformanceCounter(&litmp); // 取得高精度运行计数器的数值
LONGLONG qpartInit = litmp.QuadPart; // 记录当前时钟 ---- 相当于初始化
完毕
double initMinus = (double)(qpartInit - qpartBegin); // 计算计数器值
double initTime = initMinus / dfFreq; // 获得对应时间,单位为秒
LONGLONG initCost = initTime * 1000000; // 乘以 1000000,精确到微秒级
(us)
qDebug() << "The first FFT execute (FFTW_MEASURE) cost: " << initCost << "
us (== 0.001 ms)" << endl;
// 输入信号 ---- 实数
double dx = 1.0 / nlen;
for (int i = 0; i< nlen; i++)
{
double f = 100; // 频率,Hz
double t = i * dx;
double x = 2 * PI * f * t;
6
double y = sin(x) + cos(2 * x);
input[i] = y;
}
QueryPerformanceCounter(&litmp); // 取得高精度运行计数器的数值
LONGLONG qpartStart = litmp.QuadPart; // 记录当前时钟 ---- 开始执行 FFT
变换
int nloops = 100; // 循环执行次数
LONGLONG loopCosts[100]; // 记录每次循环所需的时间
for (int loopidx = 0; loopidx < nloops; loopidx++)
{
QueryPerformanceCounter(&litmp); // 取得高精度运行计数器的数值
LONGLONG qpartFrom = litmp.QuadPart; // 记录当前时钟
// FFT 执行变换
fftw_execute(p);
QueryPerformanceCounter(&litmp); // 取得高精度运行计数器的数值
LONGLONG qpartTo = litmp.QuadPart; // 记录当前时钟
double tempMinus = (double)(qpartTo - qpartFrom); // 计算计数器值
double tempTime = tempMinus / dfFreq; // 获得对应时间,单位为秒
loopCosts[loopidx] = tempTime * 1000000; // 乘以 1000000,精确到微
秒级(us)
} // end for
QueryPerformanceCounter(&litmp); // 取得高精度运行计数器的数值
LONGLONG qpartEnd = litmp.QuadPart; // 记录当前时钟 ---- 完毕,FFT 变换
已执行
double dfMinus = (double)(qpartEnd - qpartStart); // 计算计数器值
double dfTime = dfMinus / dfFreq; // 获得对应时间,单位为秒
LONGLONG Usingtime = dfTime * 1000000; // 乘以 1000000,精确到微秒级
(us)
// 将运行计时结果保存文件
QFile fileTimecost("timecost.txt");
if (!fileTimecost.open(QIODevice::WriteOnly | QIODevice::Text))
{
qDebug() << "Can't save timecost file!" << endl;
}
7
else
{
QTextStream stream(&fileTimecost);
stream <<"Time unit: us == 0.001 ms" << endl;
stream << endl;
stream << nloops << " loops of " << nlen << " point FFT, total time
cost: " << Usingtime << endl;
stream << endl;
for (int i = 0; i < nloops; i++)
{
LONGLONG temp = loopCosts[i];
stream << "Loop " << i+1 << " : ";
stream << temp << endl;
}
stream.flush();
fileTimecost.close();
}
// 将幅值、相位的计算结果保存文件,其实也就是最后一次循环的计算结果
for (int j = 0; j < nlen; j++)
{
double real = output[j][0]; //Extract real component
double imag = output[j][1]; //Extract imaginary component
mag[j] = qSqrt((real*real) + (imag*imag)); // Calculate the
Magnitude
pha[j] = qAtan2(imag, real); // Calculate the Phase
}
QFile fileMag("mag.txt");
if (!fileMag.open(QIODevice::WriteOnly | QIODevice::Text))
{
qDebug() << "Can't save mag file!" << endl;
}
else
{
QTextStream stream(&fileMag);
for (int j = 0; j < nlen; j++)
{
double temp = mag[j];
stream << temp << endl;
}
stream.flush();
8