汉宁窗口介绍以及计算方法

发布时间:2023年12月26日

汉宁窗口介绍

汉宁窗口(Hanning Window)的起源:

汉宁窗口是一种在信号处理和频谱分析中常用的窗口函数。它的名字来自于发明者之一的Julius von Hann(也写作Hanning)。Hann是奥地利的物理学家,他于1928年发表了一篇题为《über die Verwendung von Fensterfunktionen bei der Fourier-Analyse von Zeitabh?ngigen Messungen》(关于在傅里叶分析中使用窗口函数进行时间相关测量的论文)的文章,介绍了这个窗口函数的概念。

汉宁窗口计算公式

汉宁窗口(Hanning Window)的计算公式如下:

其中:

  • ( w(n) ) 是窗口函数在位置 ( n ) 处的值。
  • ( n ) 是窗口中的样本点索引,从 0 开始。
  • ( N ) 是窗口的长度(样本点的数量)。

这个公式描述了汉宁窗口函数在离散样本点上的取值。窗口的特点是在两端有较小的幅度,中心区域的振幅相对较高。这有助于减小截断信号产生的频谱泄漏,提高频谱分析的准确性。

应用场景

汉宁窗口的应用场景:

在信号处理中,窗口函数用于限制从无穷信号中选择的有限片段,以便在频域中进行傅里叶变换。窗口函数有助于减小截断信号产生的频谱泄漏(spectral leakage)现象,提高频谱分析的准确性。

汉宁窗口的主要特点是在窗口内信号的两端降低幅度,以减小边界效应,同时保持中心区域的振幅不变。

C++实现一个示例并用用OpenCV绘制

用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可以改变窗口的大小。在绘制过程中,窗口函数的值被映射到图像的纵轴上,形成了窗口函数的曲线。

用C++实现一个类似于科学计算库scipy中实现的hann窗口函数

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