汉宁窗口(Hanning Window)的起源:
汉宁窗口是一种在信号处理和频谱分析中常用的窗口函数。它的名字来自于发明者之一的Julius von Hann(也写作Hanning)。Hann是奥地利的物理学家,他于1928年发表了一篇题为《über die Verwendung von Fensterfunktionen bei der Fourier-Analyse von Zeitabh?ngigen Messungen》(关于在傅里叶分析中使用窗口函数进行时间相关测量的论文)的文章,介绍了这个窗口函数的概念。
汉宁窗口(Hanning Window)的计算公式如下:
其中:
这个公式描述了汉宁窗口函数在离散样本点上的取值。窗口的特点是在两端有较小的幅度,中心区域的振幅相对较高。这有助于减小截断信号产生的频谱泄漏,提高频谱分析的准确性。
汉宁窗口的应用场景:
在信号处理中,窗口函数用于限制从无穷信号中选择的有限片段,以便在频域中进行傅里叶变换。窗口函数有助于减小截断信号产生的频谱泄漏(spectral leakage)现象,提高频谱分析的准确性。
汉宁窗口的主要特点是在窗口内信号的两端降低幅度,以减小边界效应,同时保持中心区域的振幅不变。
用C++计算汉宁窗口数组并用OpenCV展示曲线:
下面是一个使用C++和OpenCV的简单示例代码,计算汉宁窗口数组并绘制其曲线:
#include <iostream>
#include <cmath>
#include <opencv2/opencv.hpp>
int main() {
// 设置窗口大小
int windowSize = 100;
// 计算汉宁窗口数组
cv::Mat hanningWindow = cv::Mat::zeros(1, windowSize, CV_64F);
for (int i = 0; i < windowSize; ++i) {
hanningWindow.at<double>(0, i) = 0.5 * (1 - std::cos(2 * CV_PI * i / (windowSize - 1)));
}
// 设置窗口背景颜色
cv::Scalar backgroundColor(255, 255, 255); // 白色背景
// 显示汉宁窗口曲线
cv::Mat plot = cv::Mat::ones(400, windowSize, CV_8UC3) * 255;
plot.setTo(backgroundColor);
for (int i = 0; i < windowSize - 1; ++i) {
cv::line(plot, cv::Point(i, 200 - hanningWindow.at<double>(0, i) * 200),
cv::Point(i + 1, 200 - hanningWindow.at<double>(0, i + 1) * 200),
cv::Scalar(0, 0, 0), 2, cv::LINE_AA);
}
// 显示图像
cv::imshow("Hanning Window", plot);
cv::waitKey(0);
return 0;
}
这个程序首先计算了汉宁窗口数组,然后使用OpenCV绘制了窗口函数的曲线。通过调整windowSize
可以改变窗口的大小。在绘制过程中,窗口函数的值被映射到图像的纵轴上,形成了窗口函数的曲线。
scipy中直接调用
win = scipy.signal.windows.hann(N_win, sym=False)
C++代码具体实现
bool len_guards(int M) {
if (M < 0) {
throw std::invalid_argument("Window length M must be a non-negative integer");
}
return M <= 1;
}
std::pair<int, bool> extend(int M, bool sym) {
if (!sym) {
return std::make_pair(M + 1, true);
} else {
return std::make_pair(M, false);
}
}
std::vector<double> truncate(std::vector<double>& w, bool needed) {
if (needed) {
w.pop_back();
}
return w;
}
std::vector<double> general_cosine(int M, std::vector<double> alpha, bool sym) {
if (len_guards(M)) {
return std::vector<double>(M, 1.0);
}
auto [M_ext, needs_trunc] = extend(M, sym);
double pi = std::acos(-1);
std::vector<double> fac(M_ext);
for (int i = 0; i < M_ext; ++i) {
fac[i] = -pi + 2.0 * pi * i / (M_ext - 1);
}
std::vector<double> w(M_ext, 0.0);
for (int k = 0; k < alpha.size(); ++k) {
for (int i = 0; i < M_ext; ++i) {
w[i] += alpha[k] * std::cos(k * fac[i]);
}
}
return truncate(w, needs_trunc);
}
std::vector<double> general_hamming(int M, double alpha, bool sym=true) {
return general_cosine(M, {alpha, 1.0 - alpha}, sym);
}
std::vector<double> hann(int M, bool sym=true) {
return general_hamming(M, 0.5, sym);
}
std::vector<double> sqrtHann(int M, bool sym=true){
auto arr = general_hamming(M, 0.5, sym);
for(auto& a : arr){
a = std::sqrt(a);
}
return arr;
}