基于FPGA的实时音频信号处理与分类系统:从理论到实践

在嵌入式系统与数字信号处理领域,实现实时、高效的音频信号分析与分类是一个经典且富有挑战性的课题。本文将深入探讨一个基于Xilinx Zynq-7020 SoC平台的实时音频处理与分类系统,该系统巧妙结合了FPGA的并行计算优势与ARM处理器的灵活控制能力,实现了对语音、音乐及特定波形信号的实时识别。通过分享其设计原理、实现难点与优化策略,旨在为从事嵌入式开发、音频处理或FPGA设计的工程师提供有价值的参考。

一、系统概述与核心设计目标

本系统的核心目标在于构建一个能够实时监测并识别环境音频信号的嵌入式平台。系统以Xilinx Zynq-7020开发板为核心,该芯片集成了双核ARM Cortex-A9处理器(Processing System, PS)和可编程逻辑(Programmable Logic, PL),为软硬件协同设计提供了理想平台。系统通过麦克风采集音频信号,经过前置放大和模数转换后,送入FPGA进行高速频谱分析,最终由ARM处理器完成分类决策并通过串口在上位机显示结果。

主要技术指标包括

  • 采样率:48 kHz,满足音频带宽需求。
  • FFT点数:4096点,提供约11.7 Hz的频率分辨率。
  • 识别类型:静音、人声、纯音乐,以及正弦波、方波、锯齿波等标准波形。
  • 实时性:整体响应时间远低于1秒,FFT运算延迟仅约289微秒。

该设计最初是为一项FPGA嵌入式设计大赛所准备,虽然最终“遗憾离场”,但其完整的设计思路与实现细节具有很高的学习和参考价值。项目已开源在GitHub,欢迎交流探讨。

二、理论基础:FFT与波形频谱特征分析

快速傅里叶变换(FFT)是本系统信号处理的基石,用于将时域信号转换为频域,从而提取频率特征。然而,直接从FFT结果进行分类是远远不够的,必须深入理解目标信号的频谱特性。

对于波形识别(正弦波、方波、锯齿波),其理论频谱特征非常明确:

  • 理想正弦波:频谱中仅存在单一的基波分量,无谐波。
  • 理想方波:由基波和奇次谐波(3次、5次、7次…)构成,谐波幅度与次数成反比。
  • 理想锯齿波:包含基波和所有整数次谐波(2次、3次、4次…),幅度也与次数成反比。

因此,理论上通过检测二次谐波三次谐波的存在与否,即可区分这三种波形。例如,只有锯齿波同时包含显著的二次和三次谐波。

⚠️ 但现实远比理论复杂:扬声器失真、环境噪声以及FFT固有的“频谱泄露”现象,都会严重污染理想频谱。谐波比例可能完全失调,甚至出现谐波幅度高于基波的情况。为此,系统引入了加窗处理(海明窗)来抑制频谱泄露,并采用模糊搜索与能量归一化等算法来增强特征提取的鲁棒性。

三、硬件架构与关键模块设计

系统的硬件部分构成了信号流通的物理管道。下图展示了核心的硬件连接:

信号链如下:高灵敏度麦克风 → 前置放大电路 → 8位并行ADC模块 → Zynq-7020 PL端。在PL端,我们构建了完整的数字信号处理流水线:

  1. 时钟与采集控制:由PLL产生精确的48kHz采样时钟,驱动ADC工作。
  2. 数据缓存:使用FIFO缓冲ADC数据,解决生产(采集)和消费(FFT)速度匹配问题。
  3. 频谱计算核心:调用Xilinx官方的FFT IP核进行4096点变换。为节省资源,后续使用功率谱(平方和)而非精确幅度谱进行能量分析。

整个PL端设计的关键在于确保数据流在AXI-4 Stream总线上的顺畅传输,精确的时序控制是功能正常的前提。

module peak_find #(
    parameter THRESH  = 32'd1700,         // 功率阈值(用于即时 out_valid)
    parameter SOUND_THRESHOLD = 32'd2000, // 声音阈值:一帧最大功率超过此值认为有声音
    parameter HOLD_FRAMES = 3           // 连续无声帧数,达到此帧数才判定为无声
)(
    input  wire        clk,
    input  wire        rst_n,
    input  wire        switch_pulse,   // 状态切换脉冲,上升沿有效
    input  wire        valid_in,        // 输入数据有效
    input  wire [11:0] index_in,        // 当前点索引(递增)
    input  wire [31:0] power_in,        // 当前功率值
    output reg         out_valid,       // 阈值即时输出:有效
    output reg [11:0]  out_index,       // 阈值即时输出:索引
    output reg [31:0]  out_power,       // 阈值即时输出:功率
    // 输出:最近两帧的最大功率索引(取两帧中的最大)
    output reg         max,             // 有声音(带滞回机制)
    output reg [11:0]  index,           // 最近两帧内最大功率的索引
    output reg [7:0]   third_harmonic,  // 新增:三次谐波大小(8位,0-255)
    output reg [7:0]   second_harmonic, // 新增:二次谐波大小(8位,0-255)
    output reg         range_mode       // 新增:当前范围模式指示 0:窄范围 1:宽范围
);
    // ===== 当前帧最大值跟踪 =====
    reg [31:0] cur_max_power;
    reg [11:0] cur_max_index;
    // 新增:基波搜索相关
    reg [11:0] fundamental_idx_reg;     // 基波索引寄存器
    reg [31:0] fundamental_pwr_reg;     // 基波功率寄存器
    reg        fundamental_found;       // 基波找到标志
    // ===== 最近两帧峰值缓存 =====
    reg [31:0] frame_power [0:1];  // 保存最近2帧的最大功率
    reg [11:0] frame_index [0:1];  // 保存最近2帧的峰值索引
    reg        frame_has_voice [0:1]; // 每帧是否有声音
    reg        frame_ptr;          // 写指针:0/1
    reg [11:0] prev_index;
    // ===== 新增:即时声音检测 =====
    reg        instant_voice_detected;  // 当前帧内是否检测到即时声音
    // ===== 音频判断保持逻辑 =====
    reg [HOLD_FRAMES-1:0] silence_cnt; // 连续无声帧计数器(长度为 HOLD_FRAMES)
    reg [HOLD_FRAMES-1:0] silence_cnt_d; // 延迟版本,用于max逻辑
    // 新增:用于max判断的信号
    reg        frame_has_voice_0_d, frame_has_voice_1_d; // 延迟的帧声音标志
    reg        instant_voice_detected_d; // 延迟的即时声音检测
    reg        frame_end_pulse; // 帧结束脉冲
    reg        frame_end_pulse_d1; // 帧结束脉冲延迟1拍
    // 新增:状态切换逻辑
    reg        range_mode_reg;  // 内部范围模式寄存器
    wire       in_range;        // 范围判断信号
    reg        switch_pulse_d1, switch_pulse_d2; // 脉冲同步和边沿检测
    // ===== 新增:谐波相关信号 =====
    reg [11:0] last_fundamental_idx;   // 上一帧的基波索引
    reg [31:0] last_fundamental_pwr;   // 上一帧的基波功率
    reg        last_fundamental_valid; // 上一帧基波信息有效
    reg [11:0] target_second_harmonic_idx;  // 二次谐波目标索引
    reg [11:0] target_third_harmonic_idx;   // 三次谐波目标索引
    reg        search_harmonics;            // 谐波搜索使能
    reg        search_second;               // 搜索二次谐波标志
    reg        search_third;                // 搜索三次谐波标志
    // 分别跟踪二次和三次谐波的最大功率
    reg [31:0] cur_second_harmonic_power;  // 当前帧二次谐波功率
    reg [31:0] cur_third_harmonic_power;   // 当前帧三次谐波功率
    // 新增:输出保持相关信号
    reg [7:0]  second_harmonic_hold;  // 二次谐波保持值
    reg [7:0]  third_harmonic_hold;   // 三次谐波保持值
    reg [31:0] out_power_hold;        // 基波功率保持值
    reg        out_power_hold_valid;  // 基波功率保持有效标志
    reg        second_harmonic_hold_valid; // 二次谐波保持有效标志
    reg        third_harmonic_hold_valid;  // 三次谐波保持有效标志
    // 新增:缩放相关参数
    reg [31:0] second_harmonic_scaled;  // 二次谐波缩放后值
    reg [31:0] third_harmonic_scaled;   // 三次谐波缩放后值
    wire [31:0] second_ratio;           // 二次谐波缩放比例
    wire [31:0] third_ratio;            // 三次谐波缩放比例
    // 功率参考值,用于缩放
    parameter POWER_REF = 32'd4000;     // 参考功率值,超过此值就输出255
    integer i;
    // 根据range_mode_reg选择范围
    assign in_range = (range_mode_reg == 1'b0) ?  // 窄范围模式
                     ((index_in < 12'd100) && (index_in > 12'd5)) :  // 窄范围:5-99
                     ((index_in < 12'd430) && (index_in > 12'd5));  // 宽范围:5-1200
    // 功率缩放计算:将32位功率值缩放到0-255
    // 公式:scaled_value = (power * 255) / POWER_REF
    // 使用乘法实现
    wire [31:0] second_power_scaled = (cur_second_harmonic_power * 32'd255) / POWER_REF;
    wire [31:0] third_power_scaled = (cur_third_harmonic_power * 32'd255) / POWER_REF;
    // 限幅到0-255
    wire [7:0] second_clamped = (|second_power_scaled[31:8]) ? 8'd255 : second_power_scaled[7:0];
    wire [7:0] third_clamped = (|third_power_scaled[31:8]) ? 8'd255 : third_power_scaled[7:0];
    // switch脉冲边沿检测
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            switch_pulse_d1 <= 1'b0;
            switch_pulse_d2 <= 1'b0;
        end else begin
            switch_pulse_d1 <= switch_pulse;
            switch_pulse_d2 <= switch_pulse_d1;
        end
    end
    wire switch_rising_edge = switch_pulse_d1 && !switch_pulse_d2;
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            out_valid              <= 1'b0;
            out_index              <= 12'd0;
            out_power              <= 32'd0;
            index                  <= 12'd0;
            third_harmonic         <= 8'd0;  // 新增
            second_harmonic        <= 8'd0;  // 新增
            range_mode             <= 1'b0;  // 默认为窄范围模式
            range_mode_reg         <= 1'b0;  // 默认为窄范围模式
            cur_max_power          <= 32'd0;
            cur_max_index          <= 12'd0;
            fundamental_idx_reg    <= 12'd0;
            fundamental_pwr_reg    <= 32'd0;
            fundamental_found      <= 1'b0;
            frame_ptr              <= 1'b0;
            silence_cnt            <= {HOLD_FRAMES{1'b0}}; // 全部置零
            instant_voice_detected <= 1'b0;  // 新增
            frame_end_pulse        <= 1'b0;
            frame_end_pulse_d1     <= 1'b0;
            instant_voice_detected_d <= 1'b0;
            frame_has_voice_0_d    <= 1'b0;
            frame_has_voice_1_d    <= 1'b0;
            silence_cnt_d          <= {HOLD_FRAMES{1'b0}};
            // 新增:谐波相关初始化
            last_fundamental_idx   <= 12'd0;
            last_fundamental_pwr   <= 32'd0;
            last_fundamental_valid <= 1'b0;
            target_second_harmonic_idx <= 12'd0;
            target_third_harmonic_idx <= 12'd0;
            search_harmonics       <= 1'b0;
            search_second          <= 1'b0;
            search_third           <= 1'b0;
            cur_second_harmonic_power <= 32'd0;
            cur_third_harmonic_power <= 32'd0;
            // 新增:输出保持相关初始化
            second_harmonic_hold   <= 8'd0;
            third_harmonic_hold    <= 8'd0;
            out_power_hold         <= 32'd0;
            out_power_hold_valid   <= 1'b0;
            second_harmonic_hold_valid <= 1'b0;
            third_harmonic_hold_valid <= 1'b0;
            // 新增:缩放相关初始化
            second_harmonic_scaled <= 32'd0;
            third_harmonic_scaled  <= 32'd0;
            for (i = 0; i < 2; i = i + 1) begin
                frame_power[i] <= 32'd0;
                frame_index[i] <= 12'd0;
                frame_has_voice[i] <= 1'b0;
            end
            prev_index <= 12'd0;
        end else begin
            out_valid <= 1'b0;
            frame_end_pulse <= 1'b0;
            instant_voice_detected_d <= instant_voice_detected;
            frame_has_voice_0_d <= frame_has_voice[0];
            frame_has_voice_1_d <= frame_has_voice[1];
            silence_cnt_d <= silence_cnt;
            frame_end_pulse_d1 <= frame_end_pulse;
            // 处理状态切换
            if (switch_rising_edge) begin
                range_mode_reg <= ~range_mode_reg;  // 切换范围模式
                range_mode <= range_mode_reg;       // 输出当前模式
            end
            if (valid_in) begin
                // 帧开始检测
                if (index_in < prev_index) begin
                    // 帧结束,处理搜索逻辑
                    if (search_harmonics) begin
                        if (search_second) begin
                            // 二次谐波搜索完成
                            search_second <= 1'b0;
                            // 保存二次谐波结果(使用缩放后的值)
                            if (cur_second_harmonic_power > 32'd5) begin
                                // 使用缩放计算
                                second_harmonic_scaled <= (cur_second_harmonic_power * 32'd255) / POWER_REF;
                                // 限幅到0-255
                                if (second_harmonic_scaled > 32'd255) begin
                                    second_harmonic_hold <= 8'd255;
                                end else begin
                                    second_harmonic_hold <= second_harmonic_scaled[7:0];
                                end
                                second_harmonic_hold_valid <= 1'b1;
                            end else begin
                                second_harmonic_hold_valid <= 1'b0;
                            end
                            // 开始搜索三次谐波
                            search_third <= 1'b1;
                            cur_third_harmonic_power <= 32'd0;
                        end
                        else if (search_third) begin
                            // 三次谐波搜索完成
                            search_third <= 1'b0;
                            search_harmonics <= 1'b0;
                            // 保存基波信息
                            last_fundamental_idx <= fundamental_idx_reg;
                            last_fundamental_pwr <= fundamental_pwr_reg;
                            last_fundamental_valid <= fundamental_found;
                            // 保存三次谐波结果(使用缩放后的值)
                            if (cur_third_harmonic_power > 32'd5) begin
                                // 使用缩放计算
                                third_harmonic_scaled <= (cur_third_harmonic_power * 32'd255) / POWER_REF;
                                // 限幅到0-255
                                if (third_harmonic_scaled > 32'd255) begin
                                    third_harmonic_hold <= 8'd255;
                                end else begin
                                    third_harmonic_hold <= third_harmonic_scaled[7:0];
                                end
                                third_harmonic_hold_valid <= 1'b1;
                            end else begin
                                third_harmonic_hold_valid <= 1'b0;
                            end
                        end
                    end
                    // 重置基波搜索
                    fundamental_found <= 1'b0;
                    fundamental_pwr_reg <= 32'd0;
                end
                // 搜索基波
                if (!search_harmonics) begin
                    if (in_range && power_in > THRESH) begin
                        if (power_in > fundamental_pwr_reg) begin
                            fundamental_pwr_reg <= power_in;
                            fundamental_idx_reg <= index_in;
                            fundamental_found <= 1'b1;
                        end
                    end
                end
                // 搜索谐波
                if (search_harmonics) begin
                    // 搜索二次谐波
                    if (search_second) begin
                        if (index_in >= (target_second_harmonic_idx - 4) &&  // 扩大搜索范围
                            index_in <= (target_second_harmonic_idx + 4)) begin
                            if (power_in > cur_second_harmonic_power) begin
                                cur_second_harmonic_power <= power_in;
                            end
                        end
                    end
                    // 搜索三次谐波
                    if (search_third) begin
                        if (index_in >= (target_third_harmonic_idx - 4) &&  // 扩大搜索范围
                            index_in <= (target_third_harmonic_idx + 4)) begin
                            if (power_in > cur_third_harmonic_power) begin
                                cur_third_harmonic_power <= power_in;
                            end
                        end
                    end
                end
                // 即时阈值输出
                if (power_in > THRESH && in_range) begin
                    out_valid <= 1'b1;
                    out_index <= index_in;
                    out_power <= power_in;
                end
                // 同帧内更新最大值(用于声音检测)
                if (in_range && power_in > cur_max_power) begin
                    cur_max_power <= power_in;
                    cur_max_index <= index_in;
                end
                // 即时声音检测
                if (power_in > SOUND_THRESHOLD && in_range) begin
                    instant_voice_detected <= 1'b1;  // 标记当前帧有声音
                end
                prev_index <= index_in;
            end
            // 帧结束处理
            if (valid_in && index_in < prev_index) begin
                // 帧是否有声音 = 帧最大功率超过阈值 OR 即时检测到声音
                frame_has_voice[frame_ptr] <= (cur_max_power > SOUND_THRESHOLD) || instant_voice_detected;
                // 重置即时声音检测标志
                instant_voice_detected <= 1'b0;
                frame_power[frame_ptr] <= cur_max_power;
                frame_index[frame_ptr] <= cur_max_index;
                // 产生帧结束脉冲
                frame_end_pulse <= 1'b1;
                // —— 最近两帧取最大值输出 ——
                if (frame_power[0] >= frame_power[1]) begin
                    index <= frame_index[0];
                end else begin
                    index <= frame_index[1];
                end
                // 基波功率门限检查
                if (cur_max_power > 32'd1500) begin
                    out_power_hold <= cur_max_power;
                    out_power_hold_valid <= 1'b1;
                end else begin
                    out_power_hold_valid <= 1'b0;
                end
                // 如果找到了基波,开始谐波搜索
                if (fundamental_found && !search_harmonics) begin
                    // 计算谐波索引
                    target_second_harmonic_idx <= fundamental_idx_reg * 2;
                    target_third_harmonic_idx <= fundamental_idx_reg * 3;
                    // 检查索引是否在有效范围内
                    if (target_second_harmonic_idx < 12'd2048 && target_third_harmonic_idx < 12'd2048) begin
                        // 开始谐波搜索
                        search_harmonics <= 1'b1;
                        search_second <= 1'b1;
                        cur_second_harmonic_power <= 32'd0;
                        cur_third_harmonic_power <= 32'd0;
                    end
                end
                // —— 声音检测滞回逻辑(只用于静音检测)——
                if (frame_has_voice[0] || frame_has_voice[1]) begin
                    silence_cnt <= {HOLD_FRAMES{1'b0}};
                end else begin
                    silence_cnt <= {silence_cnt[HOLD_FRAMES-2:0], 1'b1};
                end
                // 翻转帧指针
                frame_ptr <= ~frame_ptr;
                // 初始化下一帧最大值
                if (in_range) begin
                    cur_max_power <= power_in;
                    cur_max_index <= index_in;
                end else begin
                    cur_max_power <= 32'd0;
                    cur_max_index <= 12'd0;
                end
            end
            // 输出保持逻辑
            if (out_power_hold_valid) begin
                out_power <= out_power_hold;
            end else begin
                out_power <= 32'd0;
            end
            if (second_harmonic_hold_valid && second_harmonic_hold > 8'd2) begin
                second_harmonic <= second_harmonic_hold;
            end else begin
                second_harmonic <= 8'd0;
            end
            if (third_harmonic_hold_valid && third_harmonic_hold > 8'd2) begin
                third_harmonic <= third_harmonic_hold;
            end else begin
                third_harmonic <= 8'd0;
            end
        end
    end
    // ===== 单独处理max信号的always块 =====
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            max <= 1'b0;
        end else begin
            if (instant_voice_detected_d) begin
                max <= 1'b1;
            end
            else if (frame_end_pulse_d1) begin
                if (frame_has_voice_0_d || frame_has_voice_1_d) begin
                    max <= 1'b1;
                end
                else begin
                    if (silence_cnt_d == {HOLD_FRAMES{1'b1}}) begin
                        max <= 1'b0;
                    end
                end
            end
        end
    end
endmodule

[AFFILIATE_SLOT_1]

四、核心算法实现:峰值检测与分类逻辑

得到功率谱后,如何从中提取有效信息并做出判断是算法的核心。这部分功能由PL端的find_peak模块和PS端的决策程序共同完成。

1. 静音判断与峰值搜寻:首先,系统设定一个噪声功率阈值。只有当连续多帧信号功率超过该阈值,才判定为有效信号输入,启动分析流程。find_peak模块采用滑动窗口法寻找功率谱中的全局最大值点作为基频,并同时检测其二次、三次谐波位置的能量。为了对抗频谱泄露,算法会对峰值点附近±2个频点的能量进行求和,以得到更稳定的能量值。

//配置FFT变换核
xfft_0 fft_inst (
  .aclk(aclk),
  .aresetn(aresetn),
  //配置
  .s_axis_config_tdata(s_axis_config_tdata),
  .s_axis_config_tvalid(s_axis_config_tvalid),
  .s_axis_config_tready(s_axis_config_tready),
  //数据输入input
  .s_axis_data_tdata(s_axis_data_tdata),
  //输入数据有效信号 信号input
  .s_axis_data_tvalid(s_axis_data_tvalid),
  //可以接受外来信号 信号output
  .s_axis_data_tready(s_axis_data_tready),
  //输入数据最后一个信号 信号input
  .s_axis_data_tlast(s_axis_data_tlast),
  //输出数据(0-7Re,8-15Im)
  .m_axis_data_tdata(m_axis_data_tdata),
  //输出数据索引 信号output(0-4096)
  .m_axis_data_tuser(m_axis_data_tuser),
  //输出数据有效信号 信号output
  .m_axis_data_tvalid(m_axis_data_tvalid),
  //从机可以接受信号 信号input
  .m_axis_data_tready(1'b1),
  //输出数据最后一个信号 信号output
  .m_axis_data_tlast(m_axis_data_tlast),
  //状态有效信号
  .m_axis_status_tready(1'b1),
  //其他事件信号
  .event_frame_started(fft_start),
  .event_tlast_unexpected(tlast_unexpected),
  .event_tlast_missing(tlast_missing),
  .event_status_channel_halt(status_channel_halt),
  .event_data_in_channel_halt(data_in_channel_halt),
  .event_data_out_channel_halt(data_out_channel_halt)
);

2. 语音与音乐分类:这是PS端ARM处理器的任务。语音信号能量通常集中在200Hz-2kHz,频谱相对集中;而音乐信号频谱更宽,高频成分丰富。系统设计了一个轻量级决策树模型

  • 将最近多帧检测到的主要频率点放入滑动窗口。
  • 分析窗口内频率点的分布方差、高频能量占比等特征。
  • 结合“滞回比较”和“连续帧一致”策略,避免因信号短时波动导致输出抖动,确保分类结果稳定可靠。

3. 波形识别:在确定基频后,依据二次、三次谐波的能量关系进行判断。由于实际谐波比例失真,我们采用了更务实的阈值判断法:

  • 若二次、三次谐波能量均非常微弱 → 判断为正弦波。
  • 若二次谐波能量显著,三次谐波也存在 → 优先判断为锯齿波。
  • 若三次谐波能量显著,而二次谐波微弱 → 判断为方波。

五、软硬件协同与系统集成

Zynq平台的优势在于PS与PL的高效协同。在本系统中,PL扮演了“硬件加速器”的角色,负责所有计算密集型的信号处理任务;而PS则作为“控制与决策大脑”,运行复杂的分类逻辑和人机交互程序。二者通过AXI总线进行高速数据交换。

PS端的程序使用C语言开发,在Xilinx SDK环境中完成。它不断轮询或通过中断接收来自PL端的频谱特征数据(基频、谐波能量),执行分类算法,最后将结果格式化为JSON字符串,通过UART串口发送给上位机。

#include 
#include 
#include "xparameters.h"
#include "xgpiops.h"
#include "xil_printf.h"
#include "sleep.h"
#define EMIO_FIRST_PIN     54    // EMIO起始引脚编号
#define WINDOW_SIZE        15    // 滑动窗口大小
#define SAMPLE_DELAY_US    200000 // 采样间隔(100ms)
#define MIN_VALID_SAMPLES  2
// ====== 滞回阈值 ======
#define VOICE_THRESHOLD_LOW    300
#define MUSIC_THRESHOLD_HIGH   600
#define CONFIRM_COUNT          6   // 连续满足切换条件多少次才真正切换
// ====== 你要求的两条逻辑 ======
#define START_GATE_THRESHOLD       100   // 进入窗口启动门槛:index>=200才入窗
#define FIRST_VALUE_MUSIC_PRIORITY 900   // 新段第一个入窗值>700,优先直接判音乐
// ====== 新增:谐波门限阈值 ======
#define HARMONIC_THRESHOLD     10     // 谐波存在门限(幅值>5认为存在)
// ====== 新增:频率阈值 ======
#define HIGH_FREQ_THRESHOLD    2000  // 高频阈值(Hz),高于此值应用新逻辑
#define INDEX_TO_HZ            117   // index到Hz的转换系数 (index * 117 / 10 = Hz)
// ====== 新增:二次谐波计数阈值 ======
#define SECOND_HARMONIC_COUNT_THRESHOLD 15  // 高频时需要检测到10次二次谐波
// ====== 新增:频率锁定参数 ======
#define INITIAL_FREQ_COUNT_THRESHOLD 5     // 初始频率需要出现5次才锁定
#define FREQ_DOUBLE_RATIO_LOW  1.8f        // 接近2倍的判断下限
#define FREQ_DOUBLE_RATIO_HIGH 2.2f        // 接近2倍的判断上限
#define FREQ_TRIPLE_RATIO_LOW  2.8f        // 接近3倍的判断下限
#define FREQ_TRIPLE_RATIO_HIGH 3.2f        // 接近3倍的判断上限
#define FREQ_TOLERANCE_PERCENT 10          // 频率变化容差百分比
// ====== 新增:频率辅助音乐判断窗口参数 ======
#define FREQ_MUSIC_WINDOW_SIZE 12  // 频率音乐判断窗口大小
#define FREQ_MUSIC_THRESHOLD   295 // 频率音乐判断阈值
#define FREQ_MUSIC_PERCENT     80  // 80%的样本需要大于阈值
// ====== 新增:波形类型枚举 ======
typedef enum {
    WAVE_UNKNOWN = 0,  // 未知波形
    WAVE_SINE,         // 正弦波 -> 对应数字1
    WAVE_SQUARE,       // 方波/矩形波 -> 对应数字2
    WAVE_SAWTOOTH,     // 锯齿波 -> 对应数字3
    WAVE_COMPLEX       // 复杂波形
} WaveType;
static XGpioPs gpio;
typedef struct {
    u32 voice_state;
    u32 music_state;
    u32 busy_state;
    u32 max_state;
    u32 index;
    u32 fundamental_amp;    // 基波幅度(12位)
    u32 second_harmonic_amp; // 新增:二次谐波幅度(8位)
    u32 third_harmonic_amp;  // 三次谐波幅度(8位)
} FFT_Data;
typedef struct {
    u32 buffer[WINDOW_SIZE];
    u32 count;
    u32 index;
} SlidingWindow;
static SlidingWindow index_window = {0};
static SlidingWindow busy_window  = {0};
static SlidingWindow max_window   = {0};
static SlidingWindow fundamental_amp_window = {0};   // 基波幅度窗口
static SlidingWindow second_harmonic_window = {0};   // 新增:二次谐波窗口
static SlidingWindow third_harmonic_window  = {0};   // 三次谐波窗口
// ====== 新增:频率音乐判断窗口 ======
static SlidingWindow freq_music_window = {0};
static u32 prev_max_state = 0;
static u32 prev_busy_state = 0;
// ====== 分类状态机 ======
typedef enum {
    CLASS_NONE = 0,
    CLASS_VOICE,
    CLASS_MUSIC
} AudioClass;
static AudioClass current_class = CLASS_NONE;
static u32 switch_counter = 0;
// ====== 新段/强制音乐标记 ======
static u8 new_segment   = 0;  // max 0->1 后置1:等待本段第一个"入窗index"
static u8 forced_music  = 0;  // 本段被强制判音乐(直到max变0结束)
// ====== 新增:频率辅助强制音乐标记 ======
static u8 freq_forced_music = 0;  // 频率窗口强制判音乐
// ====== 新增:锯齿波标记 ======
static u8 forced_sawtooth = 0;  // 本段被强制判锯齿波(直到max变0结束)
// ====== 新增:二次谐波计数 ======
static u32 second_harmonic_count = 0;  // 本段内检测到二次谐波的次数
// ====== 新增:频率锁定相关变量 ======
static u8 initial_freq_locked = 0;      // 初始频率是否已锁定
static u32 locked_initial_freq = 0;     // 锁定的初始频率(Hz)
static u32 locked_initial_index = 0;    // 锁定的初始index
static u32 initial_freq_count = 0;      // 当前频率出现次数
static u32 current_stable_freq = 0;     // 当前稳定的频率
static u32 current_stable_index = 0;    // 当前稳定的index
static u8 sawtooth_detected_by_freq = 0;  // 通过频率倍频检测到锯齿波
static u8 square_detected_by_freq = 0;    // 通过频率倍频检测到矩形波
// ====== 窗口函数 ======
void init_window(SlidingWindow* window) {
    window->count = 0;
    window->index = 0;
    for (int i = 0; i < window->count; i++) {
        window->buffer[i] = 0;
    }
}
static inline void add_to_window(SlidingWindow* window, u32 value) {
    window->buffer[window->index] = value;
    window->index = (window->index + 1) % WINDOW_SIZE;
    if (window->count < WINDOW_SIZE) {
        window->count++;
    }
}
u32 calculate_average(const SlidingWindow* window) {
    if (window->count == 0) return 0;
    u32 sum = 0;
    for (u32 i = 0; i < window->count; i++) {
        sum += window->buffer[i];
    }
    return sum / window->count;
}
u32 calculate_majority(const SlidingWindow* window) {
    if (window->count == 0) return 0;
    u32 ones = 0;
    for (u32 i = 0; i < window->count; i++) {
        if (window->buffer[i]) ones++;
    }
    return (ones > window->count / 2) ? 1 : 0;
}
// ====== 新增:计算频率音乐判断窗口内大于阈值的比例 ======
static u32 calculate_freq_music_ratio(const SlidingWindow* window) {
    if (window->count == 0) return 0;
    u32 high_freq_count = 0;
    for (u32 i = 0; i < window->count; i++) {
        if (window->buffer[i] > FREQ_MUSIC_THRESHOLD) {
            high_freq_count++;
        }
    }
    // 返回百分比
    return (high_freq_count * 100) / window->count;
}
// ====== 新增:检查是否应该强制判为音乐 ======
static u8 should_force_music_by_freq(const SlidingWindow* window) {
    if (window->count < FREQ_MUSIC_WINDOW_SIZE) {
        return 0;  // 窗口未满,不判断
    }
    u32 ratio = calculate_freq_music_ratio(window);
    return (ratio >= FREQ_MUSIC_PERCENT);
}
// ====== 读12bit index ======
static inline u32 read_index_bits(void) {
    u32 value = 0;
    for (int bit = 0; bit < 12; bit++) {
        u32 pin_val = XGpioPs_ReadPin(&gpio, EMIO_FIRST_PIN + 4 + bit);
        value |= (pin_val & 0x1) << bit;
    }
    return value;
}
// ====== 读12位基波幅度 (EMIO引脚78-89) ======
static inline u32 read_fundamental_amp_bits(void) {
    u32 value = 0;
    for (int bit = 0; bit < 12; bit++) {
        // EMIO引脚78-89对应fundamental_amp[11:0]
        u32 pin_val = XGpioPs_ReadPin(&gpio, EMIO_FIRST_PIN + 24 + bit);
        value |= (pin_val & 0x1) << bit;
    }
    return value;
}
// ====== 新增:读8位二次谐波幅度 (EMIO引脚90-97) ======
static inline u32 read_second_harmonic_bits(void) {
    u32 value = 0;
    for (int bit = 0; bit < 8; bit++) {
        // EMIO引脚90-97对应second_harmonic[7:0]
        u32 pin_val = XGpioPs_ReadPin(&gpio, EMIO_FIRST_PIN + 36 + bit);
        value |= (pin_val & 0x1) << bit;
    }
    return value;
}
// ====== 读8位三次谐波幅度 (EMIO引脚70-77) ======
static inline u32 read_third_harmonic_bits(void) {
    u32 value = 0;
    for (int bit = 0; bit < 8; bit++) {
        // EMIO引脚70-77对应third_harmonic[7:0]
        u32 pin_val = XGpioPs_ReadPin(&gpio, EMIO_FIRST_PIN + 16 + bit);
        value |= (pin_val & 0x1) << bit;
    }
    return value;
}
// ====== 新增:计算频率(Hz) ======
static inline u32 calculate_frequency_hz(u32 index_value) {
    return (index_value * INDEX_TO_HZ) / 10U;
}
// ====== 新增:检查频率是否接近 ======
static u8 is_frequency_close(u32 freq1, u32 freq2, float percent_tolerance) {
    if (freq1 == 0 || freq2 == 0) return 0;
    float ratio = (freq1 > freq2) ? (float)freq1 / freq2 : (float)freq2 / freq1;
    float max_ratio = 1.0f + (percent_tolerance / 100.0f);
    return (ratio <= max_ratio);
}
// ====== 新增:检查频率是否为倍频 ======
static u8 check_frequency_double(u32 freq, u32 base_freq) {
    if (base_freq == 0) return 0;
    float ratio = (float)freq / base_freq;
    return (ratio >= FREQ_DOUBLE_RATIO_LOW && ratio <= FREQ_DOUBLE_RATIO_HIGH);
}
static u8 check_frequency_triple(u32 freq, u32 base_freq) {
    if (base_freq == 0) return 0;
    float ratio = (float)freq / base_freq;
    return (ratio >= FREQ_TRIPLE_RATIO_LOW && ratio <= FREQ_TRIPLE_RATIO_HIGH);
}
// ====== 新增:波形判断函数 ======
static WaveType determine_wave_type(u32 second_harmonic, u32 third_harmonic, u32 freq_hz) {
    u8 has_second = (second_harmonic > HARMONIC_THRESHOLD);
    u8 has_third = (third_harmonic > HARMONIC_THRESHOLD);
    // 优先检查频率倍频检测结果
    if (sawtooth_detected_by_freq) {
        return WAVE_SAWTOOTH;  // 频率倍频检测到锯齿波
    } else if (square_detected_by_freq) {
        return WAVE_SQUARE;    // 频率倍频检测到矩形波
    }
    // 原有逻辑
    if (has_second && has_third) {
        return WAVE_SAWTOOTH;    // 二次、三次均有值 -> 锯齿波
    } else if (has_second) {
        return WAVE_SAWTOOTH;    // 只有二次谐波 -> 锯齿波
    } else if (has_third) {
        return WAVE_SQUARE;      // 只有三次谐波 -> 矩形波
    } else {
        return WAVE_SINE;        // 二次、三次都无值 -> 正弦波
    }
}
// ====== 滞回 + 连续确认分类器 ======
static AudioClass classify_with_hysteresis(u32 index_avg, u32 max_state) {
    if (max_state == 0) {
        current_class = CLASS_NONE;
        switch_counter = 0;
        return CLASS_NONE;
    }
    if (current_class == CLASS_NONE) {
        if (index_avg >= MUSIC_THRESHOLD_HIGH) current_class = CLASS_MUSIC;
        else if (index_avg <= VOICE_THRESHOLD_LOW) current_class = CLASS_VOICE;
        else current_class = CLASS_MUSIC;
        switch_counter = 0;
        return current_class;
    }
    if (current_class == CLASS_MUSIC) {
        if (index_avg <= VOICE_THRESHOLD_LOW) {
            switch_counter++;
            if (switch_counter >= CONFIRM_COUNT) {
                current_class = CLASS_VOICE;
                switch_counter = 0;
            }
        } else {
            switch_counter = 0;
        }
    } else if (current_class == CLASS_VOICE) {
        if (index_avg >= MUSIC_THRESHOLD_HIGH) {
            switch_counter++;
            if (switch_counter >= CONFIRM_COUNT) {
                current_class = CLASS_MUSIC;
                switch_counter = 0;
            }
        } else {
            switch_counter = 0;
        }
    }
    return current_class;
}
/*
 * 处理频率锁定逻辑
 */
static void process_frequency_locking(FFT_Data* raw_data) {
    u32 current_freq = calculate_frequency_hz(raw_data->index);
    // 只在busy=0时处理频率锁定
    if (raw_data->busy_state == 0 && raw_data->max_state == 1) {
        // 如果初始频率未锁定
        if (!initial_freq_locked) {
            // 检查频率是否稳定
            if (current_stable_freq == 0) {
                // 第一次检测到频率
                current_stable_freq = current_freq;
                current_stable_index = raw_data->index;
                initial_freq_count = 1;
            } else if (is_frequency_close(current_freq, current_stable_freq, FREQ_TOLERANCE_PERCENT)) {
                // 频率接近,增加计数
                initial_freq_count++;
                // 如果达到阈值,锁定初始频率
                if (initial_freq_count >= INITIAL_FREQ_COUNT_THRESHOLD) {
                    locked_initial_freq = current_stable_freq;
                    locked_initial_index = current_stable_index;
                    initial_freq_locked = 1;
                }
            } else {
                // 频率变化太大,重置
                current_stable_freq = current_freq;
                current_stable_index = raw_data->index;
                initial_freq_count = 1;
            }
        } else {
            // 初始频率已锁定,检查是否出现倍频
            if (current_freq > locked_initial_freq) {
                if (check_frequency_double(current_freq, locked_initial_freq)) {
                    // 检测到接近2倍频,可能是锯齿波
                    sawtooth_detected_by_freq = 1;
                    square_detected_by_freq = 0;
                } else if (check_frequency_triple(current_freq, locked_initial_freq)) {
                    // 检测到接近3倍频,可能是矩形波
                    square_detected_by_freq = 1;
                    sawtooth_detected_by_freq = 0;
                }
            }
        }
    }
}
/*
 * 处理频率音乐判断
 */
static void process_freq_music_judgment(FFT_Data* raw_data) {
    // 只在max=1时处理
    if (raw_data->max_state == 1 && raw_data->index >= START_GATE_THRESHOLD) {
        // 将当前index加入频率音乐判断窗口
        add_to_window(&freq_music_window, raw_data->index);
        // 检查是否应该强制判为音乐
        freq_forced_music = should_force_music_by_freq(&freq_music_window);
    }
}
/*
 * 读取原始PL信号 + 更新窗口
 */
FFT_Data detect_pl_signals(void) {
    FFT_Data raw_data = {0};
    raw_data.busy_state = XGpioPs_ReadPin(&gpio, EMIO_FIRST_PIN + 2);
    raw_data.max_state  = XGpioPs_ReadPin(&gpio, EMIO_FIRST_PIN + 3);
    u32 index_value = read_index_bits();
    raw_data.index = (index_value * 117U) / 10U;
    // 读取基波幅度和所有谐波幅度
    raw_data.fundamental_amp = read_fundamental_amp_bits();   // 12位
    raw_data.second_harmonic_amp = read_second_harmonic_bits(); // 新增:8位二次谐波
    raw_data.third_harmonic_amp = read_third_harmonic_bits(); // 8位三次谐波
    // 处理频率锁定逻辑
    process_frequency_locking(&raw_data);
    // 处理频率音乐判断
    process_freq_music_judgment(&raw_data);
    // 段结束:max 1->0 清空窗口+状态
    if (prev_max_state == 1 && raw_data.max_state == 0) {
        init_window(&index_window);
        init_window(&busy_window);
        init_window(&max_window);
        init_window(&fundamental_amp_window);
        init_window(&second_harmonic_window);  // 新增
        init_window(&third_harmonic_window);
        // 新增:清空频率音乐判断窗口
        init_window(&freq_music_window);
        current_class = CLASS_NONE;
        switch_counter = 0;
        new_segment = 0;
        forced_music = 0;
        freq_forced_music = 0;  // 新增:重置频率强制音乐标记
        forced_sawtooth = 0;  // 新增:重置强制锯齿波标记
        second_harmonic_count = 0;  // 新增:重置二次谐波计数
        // 新增:重置频率锁定相关状态
        initial_freq_locked = 0;
        locked_initial_freq = 0;
        locked_initial_index = 0;
        initial_freq_count = 0;
        current_stable_freq = 0;
        current_stable_index = 0;
        sawtooth_detected_by_freq = 0;
        square_detected_by_freq = 0;
    }
    // 段开始:max 0->1 标记新段(等待第一个"入窗值")
    if (prev_max_state == 0 && raw_data.max_state == 1) {
        init_window(&index_window);
        init_window(&busy_window);
        init_window(&max_window);
        init_window(&fundamental_amp_window);
        init_window(&second_harmonic_window);  // 新增
        init_window(&third_harmonic_window);
        // 新增:清空频率音乐判断窗口
        init_window(&freq_music_window);
        current_class = CLASS_NONE;
        switch_counter = 0;
        new_segment = 1;
        forced_music = 0;
        freq_forced_music = 0;  // 新增:重置频率强制音乐标记
        forced_sawtooth = 0;  // 新增:重置强制锯齿波标记
        second_harmonic_count = 0;  // 新增:重置二次谐波计数
        // 新增:重置频率锁定相关状态
        initial_freq_locked = 0;
        locked_initial_freq = 0;
        locked_initial_index = 0;
        initial_freq_count = 0;
        current_stable_freq = 0;
        current_stable_index = 0;
        sawtooth_detected_by_freq = 0;
        square_detected_by_freq = 0;
    }
    // 只在 max==1 有效期间处理
    if (raw_data.max_state == 1) {
        // 计算当前频率(Hz)
        u32 freq_hz = calculate_frequency_hz(index_value);
        // 新增:高频(>2000Hz)且检测到二次谐波,增加计数
        if (freq_hz > HIGH_FREQ_THRESHOLD && raw_data.second_harmonic_amp > HARMONIC_THRESHOLD) {
            second_harmonic_count++;  // 增加二次谐波计数
            // 当达到3次时,标记本段为锯齿波
            if (second_harmonic_count >= SECOND_HARMONIC_COUNT_THRESHOLD) {
                forced_sawtooth = 1;  // 标记本段为强制锯齿波
            }
        }
        // 进入窗口门槛:<200 直接丢弃(不进窗、不影响均值)
        if (raw_data.index < START_GATE_THRESHOLD) {
            prev_max_state = raw_data.max_state;
            return raw_data;
        }
        // 新段的第一个"入窗值">700:优先直接判定音乐(本段强制音乐)
        if (new_segment) {
            if (raw_data.index > FIRST_VALUE_MUSIC_PRIORITY) {
                forced_music = 1;
                current_class = CLASS_MUSIC;   // 直接置音乐,避免起始误判语音
                switch_counter = 0;
            }
            new_segment = 0;
        }
        // 正常入窗
        add_to_window(&index_window, raw_data.index);
        add_to_window(&busy_window,  raw_data.busy_state);
        add_to_window(&max_window,   raw_data.max_state);
        add_to_window(&fundamental_amp_window, raw_data.fundamental_amp);
        add_to_window(&second_harmonic_window, raw_data.second_harmonic_amp);  // 新增
        add_to_window(&third_harmonic_window, raw_data.third_harmonic_amp);
    }
    prev_max_state = raw_data.max_state;
    prev_busy_state = raw_data.busy_state;
    return raw_data;
}
FFT_Data get_filtered_data(const FFT_Data* raw) {
    FFT_Data filtered = {0};
    if (index_window.count == 0) {
        filtered.busy_state  = raw->busy_state;
        filtered.max_state   = raw->max_state;
        filtered.index       = raw->index;
        filtered.fundamental_amp = raw->fundamental_amp;
        filtered.second_harmonic_amp = raw->second_harmonic_amp;  // 新增
        filtered.third_harmonic_amp = raw->third_harmonic_amp;
        filtered.voice_state = 0;
        filtered.music_state = 0;
        return filtered;
    }
    filtered.busy_state = calculate_majority(&busy_window);
    filtered.max_state  = calculate_majority(&max_window);
    u32 index_avg = calculate_average(&index_window);
    // 频率锁定逻辑:如果初始频率已锁定,使用锁定频率
    if (initial_freq_locked && filtered.max_state == 1) {
        filtered.index = locked_initial_index;  // 使用锁定的index
    } else {
        filtered.index = index_avg;
    }
    // 计算基波和谐波平均值
    u32 fundamental_avg = calculate_average(&fundamental_amp_window);
    u32 second_harmonic_avg = calculate_average(&second_harmonic_window);  // 新增
    u32 third_harmonic_avg = calculate_average(&third_harmonic_window);
    filtered.fundamental_amp = fundamental_avg;
    filtered.second_harmonic_amp = second_harmonic_avg;  // 新增
    filtered.third_harmonic_amp = third_harmonic_avg;
    if (index_window.count < MIN_VALID_SAMPLES) {
        filtered.voice_state = 0;
        filtered.music_state = 0;
        return filtered;
    }
    // ====== 新增:当max=0时,清零二次和三次谐波幅度 ======
    if (filtered.max_state == 0) {
        filtered.second_harmonic_amp = 0;
        filtered.third_harmonic_amp = 0;
    }
    // ====== 新增:频率音乐判断优先 ======
    // 如果频率窗口判断为音乐,强制判为音乐
    if (freq_forced_music && filtered.max_state == 1) {
        filtered.voice_state = 0;
        filtered.music_state = 1;
        return filtered;
    }
    // ====== 你要的"优先音乐输出" ======
    // 一旦本段触发 forced_music,则本段内直接输出音乐(直到max变0段结束)
    if (forced_music && filtered.max_state == 1) {
        filtered.voice_state = 0;
        filtered.music_state = 1;
        return filtered;
    }
    // 否则走原来的 滞回+确认 逻辑(基于平均值)
    AudioClass cls = classify_with_hysteresis(index_avg, filtered.max_state);
    if (cls == CLASS_VOICE) {
        filtered.voice_state = 1;
        filtered.music_state = 0;
    } else if (cls == CLASS_MUSIC) {
        filtered.voice_state = 0;
        filtered.music_state = 1;
    } else {
        filtered.voice_state = 0;
        filtered.music_state = 0;
    }
    return filtered;
}
void output_json_data(const FFT_Data* raw, const FFT_Data* filtered) {
    // 新增:计算波形类型
    u32 freq_hz = calculate_frequency_hz(raw->index);
    WaveType wave_type = determine_wave_type(filtered->second_harmonic_amp,
                                            filtered->third_harmonic_amp,
                                            freq_hz);
    // 新增:强制锯齿波逻辑
    if (forced_sawtooth && filtered->max_state == 1) {
        wave_type = WAVE_SAWTOOTH;  // 强制覆盖为锯齿波
    }
    // 将波形类型转换为数字:1-正弦,2-矩形,3-锯齿
    u32 wave_type_number = 0;
    switch (wave_type) {
        case WAVE_SINE:     wave_type_number = 1; break;  // 正弦波 -> 1
        case WAVE_SQUARE:   wave_type_number = 2; break;  // 矩形波 -> 2
        case WAVE_SAWTOOTH: wave_type_number = 3; break;  // 锯齿波 -> 3
        default:           wave_type_number = 0; break;  // 未知波形
    }
    // 确定输出的index
    u32 output_index = raw->index;  // 默认使用原始index
    // 如果busy=0且初始频率已锁定,使用锁定的index
    if (raw->busy_state == 0 && initial_freq_locked) {
        output_index = locked_initial_index;
    }
    // 输出JSON格式
    printf("{\"voice\":%d,\"music\":%d,\"busy\":%d,\"max\":%d,"
           "\"index\":%u,\"fundamental\":%u,\"second_harmonic\":%u,\"third_harmonic\":%u,\"wave_type\":%u}\r\n",
           filtered->voice_state, filtered->music_state,
           filtered->busy_state, filtered->max_state,
           output_index,  // 使用确定的index
           raw->fundamental_amp,      // 原始基波幅度(12位)
           raw->second_harmonic_amp,  // 原始二次谐波幅度(8位)
           raw->third_harmonic_amp,   // 原始三次谐波幅度(8位)
           wave_type_number);         // 波形类型:1=正弦,2=矩形,3=锯齿
}
int main() {
    XGpioPs_Config *config;
    int status;
    config = XGpioPs_LookupConfig(XPAR_PS7_GPIO_0_DEVICE_ID);
    status = XGpioPs_CfgInitialize(&gpio, config, config->BaseAddr);
    if (status != XST_SUCCESS) {
        xil_printf("GPIO初始化失败\r\n");
        return XST_FAILURE;
    }
    // 配置 busy/max 输入
    for (int i = 2; i < 4; i++) {
        XGpioPs_SetDirectionPin(&gpio, EMIO_FIRST_PIN + i, 0);
        XGpioPs_SetOutputEnablePin(&gpio, EMIO_FIRST_PIN + i, 0);
    }
    // 配置 index 12bit 输入
    for (int i = 4; i < 16; i++) {
        XGpioPs_SetDirectionPin(&gpio, EMIO_FIRST_PIN + i, 0);
        XGpioPs_SetOutputEnablePin(&gpio, EMIO_FIRST_PIN + i, 0);
    }
    // 配置三次谐波8bit输入 (EMIO引脚70-77)
    for (int i = 16; i < 24; i++) {  // 16-23对应third_harmonic[7:0]
        XGpioPs_SetDirectionPin(&gpio, EMIO_FIRST_PIN + i, 0);
        XGpioPs_SetOutputEnablePin(&gpio, EMIO_FIRST_PIN + i, 0);
    }
    // 新增:配置二次谐波8bit输入 (EMIO引脚90-97)
    for (int i = 36; i < 44; i++) {  // 36-43对应second_harmonic[7:0]
        XGpioPs_SetDirectionPin(&gpio, EMIO_FIRST_PIN + i, 0);
        XGpioPs_SetOutputEnablePin(&gpio, EMIO_FIRST_PIN + i, 0);
    }
    // 配置基波幅度12bit输入 (EMIO引脚78-89)
    for (int i = 24; i < 36; i++) {  // 24-35对应fundamental_amp[11:0] (12位)
        XGpioPs_SetDirectionPin(&gpio, EMIO_FIRST_PIN + i, 0);
        XGpioPs_SetOutputEnablePin(&gpio, EMIO_FIRST_PIN + i, 0);
    }
    init_window(&index_window);
    init_window(&busy_window);
    init_window(&max_window);
    init_window(&fundamental_amp_window);
    init_window(&second_harmonic_window);  // 新增
    init_window(&third_harmonic_window);
    // 新增:初始化频率音乐判断窗口
    freq_music_window.count = 0;
    freq_music_window.index = 0;
    for (int i = 0; i < FREQ_MUSIC_WINDOW_SIZE; i++) {
        freq_music_window.buffer[i] = 0;
    }
    prev_max_state = 0;
    prev_busy_state = 0;
    current_class = CLASS_NONE;
    switch_counter = 0;
    new_segment = 0;
    forced_music = 0;
    freq_forced_music = 0;  // 新增
    forced_sawtooth = 0;  // 新增
    second_harmonic_count = 0;  // 新增
    initial_freq_locked = 0;
    locked_initial_freq = 0;
    locked_initial_index = 0;
    initial_freq_count = 0;
    current_stable_freq = 0;
    current_stable_index = 0;
    sawtooth_detected_by_freq = 0;
    square_detected_by_freq = 0;
    while (1) {
        FFT_Data raw = detect_pl_signals();
        FFT_Data filtered = get_filtered_data(&raw);
        output_json_data(&raw, &filtered);
        usleep(SAMPLE_DELAY_US);
    }
    return 0;
}

这种架构将算法的实时性部分(FFT)交给硬件并行处理,将灵活性部分(分类规则)交给软件,完美平衡了速度与复杂度,是嵌入式信号处理系统的典型设计范式。

[AFFILIATE_SLOT_2]

六、上位机展示与项目总结

为方便演示与调试,我们开发了一个基于Web Serial API的网页版上位机。该上位机可直接在浏览器中通过串口接收数据,并实时可视化显示分类结果、基频、谐波信息以及推断的波形动画。

✅ 网页上位机的优点:跨平台、无需安装、开发快捷、直观美观。
⚠️ 存在的挑战:高数据率下可能存在延迟,浏览器兼容性不一。对于更高要求的工业场景,采用Qt、C++或Python(如PyQt)开发本地应用是更稳定可靠的选择。

系统实物测试视频可以在此查看:

七、总结与展望

本项目成功实现了一个基于Zynq平台的实时音频处理与分类系统,验证了软硬件协同设计在实时信号处理任务中的巨大优势。通过深入应用FFT、特征提取与模式识别算法,并针对实际非理想条件(噪声、失真、频谱泄露)进行了一系列工程优化,系统达到了较高的识别准确率与实时性要求。

未来可能的优化方向包括:采用更高精度的ADC;在PL端实现更复杂的特征提取算法(如MFCC);利用PS端的Linux系统运行更先进的机器学习模型(如使用Python的scikit-learn库或C++的LibSVM进行在线分类);以及开发更稳定、功能更丰富的本地上位机软件。

无论是对于学习FPGA数字信号处理、嵌入式系统设计,还是理解音频分析的基本原理,本项目都提供了一个完整的实践案例。希望其中的设计思路和解决实际问题的经验能对读者有所启发。

posted on 2026-03-09 08:03  blfbuaa  阅读(40)  评论(0)    收藏  举报