智能音箱工作原理全解析——从唤醒词检测到大模型对话的完整技术链路

前言

去年接了个智能音箱的项目,从麦克风阵列选型到唤醒词训练,再到对接云端大模型,整个链路走了一遍。说实话,之前觉得智能音箱就是个"语音识别+音响"的组合,真正做下来才发现里面的技术细节相当多。

今天把智能音箱的完整工作原理整理出来,从硬件到软件,从本地唤醒到云端对话,希望能帮到对这块感兴趣的朋友。

智能音箱整体架构

工作流程概览

复制代码
┌─────────────────────────────────────────────────────────────────────────────┐
│                        智能音箱完整工作流程                                   │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   用户: "小爱同学,今天天气怎么样?"                                          │
│                      │                                                      │
│                      ▼                                                      │
│   ┌─────────────────────────────────────┐                                  │
│   │  ① 麦克风阵列采集                    │  ← 多麦克风拾音                   │
│   │     - 远场拾音 (3-5米)               │                                  │
│   │     - 回声消除 (AEC)                 │                                  │
│   │     - 噪声抑制 (NS)                  │                                  │
│   │     - 波束形成 (Beamforming)         │                                  │
│   └─────────────────┬───────────────────┘                                  │
│                     │ 增强后的音频                                          │
│                     ▼                                                      │
│   ┌─────────────────────────────────────┐                                  │
│   │  ② 本地唤醒词检测 (KWS)              │  ← 低功耗DSP持续运行             │
│   │     - 特征提取 (MFCC/FBank)          │                                  │
│   │     - 小型神经网络推理               │                                  │
│   │     - 检测到"小爱同学"               │                                  │
│   └─────────────────┬───────────────────┘                                  │
│                     │ 唤醒成功,触发主系统                                   │
│                     ▼                                                      │
│   ┌─────────────────────────────────────┐                                  │
│   │  ③ 语音端点检测 (VAD)                │  ← 确定语音起止                   │
│   │     - 检测用户说话开始               │                                  │
│   │     - 检测用户说话结束               │                                  │
│   │     - 录制完整指令音频               │                                  │
│   └─────────────────┬───────────────────┘                                  │
│                     │ 完整语音数据                                          │
│                     ▼                                                      │
│   ┌─────────────────────────────────────┐                                  │
│   │  ④ 音频编码 & 上传                   │  ← 压缩传输                      │
│   │     - Opus/Speex编码                 │                                  │
│   │     - WebSocket/HTTP2传输            │                                  │
│   └─────────────────┬───────────────────┘                                  │
│                     │                                                      │
│          ══════════════════════════════════  网络边界                       │
│                     │                                                      │
│                     ▼                                                      │
│   ┌─────────────────────────────────────┐                                  │
│   │  ⑤ 云端ASR语音识别                   │  ← 云端服务器                    │
│   │     - 声学模型 (AM)                  │                                  │
│   │     - 语言模型 (LM)                  │                                  │
│   │     - 输出: "今天天气怎么样"          │                                  │
│   └─────────────────┬───────────────────┘                                  │
│                     │ 文本                                                  │
│                     ▼                                                      │
│   ┌─────────────────────────────────────┐                                  │
│   │  ⑥ 大模型/NLU理解与生成              │  ← LLM处理                       │
│   │     - 意图识别                       │                                  │
│   │     - 槽位填充 (城市=当前位置)        │                                  │
│   │     - 调用天气API                    │                                  │
│   │     - 生成回答文本                   │                                  │
│   └─────────────────┬───────────────────┘                                  │
│                     │ 回答文本                                              │
│                     ▼                                                      │
│   ┌─────────────────────────────────────┐                                  │
│   │  ⑦ TTS语音合成                       │  ← 文本转语音                    │
│   │     - 文本前端处理                   │                                  │
│   │     - 声学模型生成频谱               │                                  │
│   │     - 声码器生成波形                 │                                  │
│   └─────────────────┬───────────────────┘                                  │
│                     │                                                      │
│          ══════════════════════════════════  网络边界                       │
│                     │ 音频流                                                │
│                     ▼                                                      │
│   ┌─────────────────────────────────────┐                                  │
│   │  ⑧ 本地播放                          │                                  │
│   │     - 音频解码                       │                                  │
│   │     - 功放驱动                       │                                  │
│   │     - 扬声器输出                     │                                  │
│   └─────────────────────────────────────┘                                  │
│                     │                                                      │
│                     ▼                                                      │
│   音箱: "今天北京天气晴,气温15到23度,空气质量良好"                          │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

延迟分解(典型值):
- 唤醒检测: ~200ms
- VAD结束检测: ~300ms
- 网络传输: ~100ms
- ASR识别: ~300ms
- LLM生成: ~500ms-2s
- TTS合成: ~200ms
- 总延迟: 1.5-3.5秒

硬件架构

复制代码
┌─────────────────────────────────────────────────────────────────────────────┐
│                         智能音箱硬件架构                                      │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   ┌───────────────────────────────────────────────────────────────────┐    │
│   │                        麦克风阵列 (顶部)                           │    │
│   │   ┌─────┐   ┌─────┐   ┌─────┐   ┌─────┐   ┌─────┐   ┌─────┐     │    │
│   │   │MIC1 │   │MIC2 │   │MIC3 │   │MIC4 │   │MIC5 │   │MIC6 │     │    │
│   │   └──┬──┘   └──┬──┘   └──┬──┘   └──┬──┘   └──┬──┘   └──┬──┘     │    │
│   │      │         │         │         │         │         │         │    │
│   │      └─────────┴─────────┴────┬────┴─────────┴─────────┘         │    │
│   └───────────────────────────────┼─────────────────────────────────────┘    │
│                                   │ I2S/PDM                                 │
│                                   ▼                                         │
│   ┌───────────────────────────────────────────────────────────────────┐    │
│   │                     音频前端处理 (Audio Codec/DSP)                  │    │
│   │                                                                   │    │
│   │   ┌─────────────┐  ┌─────────────┐  ┌─────────────┐              │    │
│   │   │  ADC转换    │→│  AEC/NS/BF  │→│  特征提取   │              │    │
│   │   │  (多通道)   │  │  (DSP处理)  │  │  (MFCC)    │              │    │
│   │   └─────────────┘  └─────────────┘  └──────┬──────┘              │    │
│   │                                            │                      │    │
│   └────────────────────────────────────────────┼──────────────────────┘    │
│                                                │                           │
│        ┌───────────────────────────────────────┼───────────────────┐       │
│        │                                       │                   │       │
│        ▼                                       ▼                   │       │
│   ┌─────────────┐                    ┌─────────────────────┐       │       │
│   │  KWS芯片    │                    │   主控SoC           │       │       │
│   │  (低功耗)   │─────唤醒信号──────→│   (AP)              │       │       │
│   │             │                    │                     │       │       │
│   │ - 专用NPU   │                    │ - CPU (Cortex-A)    │       │       │
│   │ - <1mW功耗  │                    │ - NPU/GPU           │       │       │
│   │ - 始终运行  │                    │ - WiFi/BT           │       │       │
│   └─────────────┘                    │ - Linux/Android     │       │       │
│                                      └──────────┬──────────┘       │       │
│                                                 │                   │       │
│                          ┌──────────────────────┼──────────────────┤       │
│                          │                      │                  │       │
│                          ▼                      ▼                  ▼       │
│                   ┌───────────┐          ┌───────────┐      ┌─────────┐   │
│                   │  Flash    │          │   DRAM    │      │  eMMC   │   │
│                   │ (固件)    │          │  (运行)   │      │ (存储)  │   │
│                   └───────────┘          └───────────┘      └─────────┘   │
│                                                                            │
│   ┌───────────────────────────────────────────────────────────────────┐   │
│   │                        音频输出 (底部)                             │   │
│   │                                                                   │   │
│   │   ┌─────────────┐      ┌─────────────┐      ┌─────────────┐      │   │
│   │   │   DAC       │─────→│   功放(D类) │─────→│   扬声器    │      │   │
│   │   │             │      │   (10-20W)  │      │  (全频/低音)│      │   │
│   │   └─────────────┘      └─────────────┘      └─────────────┘      │   │
│   │                                                                   │   │
│   └───────────────────────────────────────────────────────────────────┘   │
│                                                                            │
│   ┌────────────────┐  ┌────────────────┐  ┌────────────────┐              │
│   │   LED环形灯    │  │   触摸按键     │  │   电源管理     │              │
│   │   (状态指示)   │  │   (音量/静音)  │  │   (PMU)       │              │
│   └────────────────┘  └────────────────┘  └────────────────┘              │
│                                                                            │
└─────────────────────────────────────────────────────────────────────────────┘

麦克风阵列与音频前端

麦克风阵列设计

c 复制代码
/**
 * 麦克风阵列配置
 * 常见配置:2麦、4麦、6麦、8麦
 */

// 典型的6麦圆形阵列布局
/*
            MIC1 (0°)
              ●
           /     \
    MIC6 ●         ● MIC2 (60°)
    (300°)         
         |         |
         |    ●    |    ← 中心可能有参考麦克风
         |  (ref)  |
    MIC5 ●         ● MIC3 (120°)
    (240°)  \     /
              ●
           MIC4 (180°)
           
    阵列半径: 通常 30-50mm
*/

typedef struct {
    int num_mics;           // 麦克风数量
    float radius_mm;        // 阵列半径
    float mic_angles[8];    // 各麦克风角度
    int sample_rate;        // 采样率
    int bit_depth;          // 位深
} mic_array_config_t;

// 6麦克风配置示例
static const mic_array_config_t mic_config_6ch = {
    .num_mics = 6,
    .radius_mm = 35.0f,
    .mic_angles = {0, 60, 120, 180, 240, 300},  // 均匀分布
    .sample_rate = 16000,   // 16kHz采样率
    .bit_depth = 16         // 16位
};

/**
 * 常见麦克风芯片
 * - 模拟: Knowles SPH0645, InvenSense ICS-43434
 * - 数字PDM: ST MP34DT01, Knowles SPK0838HT4H
 */

音频前端处理 (AFE)

音频前端处理是智能音箱的关键,包括回声消除、噪声抑制、波束形成等:

c 复制代码
/**
 * 音频前端处理流程
 */

/*
┌─────────────────────────────────────────────────────────────────┐
│                    AFE (Audio Front-End) 处理流程                │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   多路麦克风输入                      扬声器参考信号             │
│   [MIC1][MIC2]...[MIC6]                  [REF]                  │
│         │                                  │                    │
│         ▼                                  │                    │
│   ┌───────────────┐                        │                    │
│   │  高通滤波     │  去除直流和低频噪声    │                    │
│   │  (HPF)       │                        │                    │
│   └───────┬───────┘                        │                    │
│           │                                │                    │
│           ▼                                │                    │
│   ┌───────────────────────────────────────┴───┐                │
│   │              回声消除 (AEC)                │                │
│   │                                           │                │
│   │   扬声器播放的声音会被麦克风拾取,         │                │
│   │   需要从麦克风信号中减去这部分回声          │                │
│   │                                           │                │
│   │   d(n) = x(n) + s(n) + v(n)              │                │
│   │   其中: x=期望信号, s=回声, v=噪声         │                │
│   │   目标: 估计s(n)并消除                    │                │
│   └───────────────┬───────────────────────────┘                │
│                   │                                             │
│                   ▼                                             │
│   ┌───────────────────────────────────────────┐                │
│   │            波束形成 (Beamforming)          │                │
│   │                                           │                │
│   │   利用多麦克风的空间信息,增强特定方向的    │                │
│   │   声音,抑制其他方向的干扰                 │                │
│   │                                           │                │
│   │   常用算法:                               │                │
│   │   - 延迟求和 (Delay-and-Sum)              │                │
│   │   - MVDR (最小方差无失真响应)             │                │
│   │   - GEV (广义特征值)                      │                │
│   └───────────────┬───────────────────────────┘                │
│                   │                                             │
│                   ▼                                             │
│   ┌───────────────────────────────────────────┐                │
│   │            噪声抑制 (NS)                   │                │
│   │                                           │                │
│   │   去除环境噪声(空调、风扇、背景人声等)    │                │
│   │                                           │                │
│   │   常用算法:                               │                │
│   │   - 谱减法                                │                │
│   │   - Wiener滤波                           │                │
│   │   - 神经网络降噪 (RNNoise)                │                │
│   └───────────────┬───────────────────────────┘                │
│                   │                                             │
│                   ▼                                             │
│   ┌───────────────────────────────────────────┐                │
│   │            自动增益控制 (AGC)              │                │
│   │                                           │                │
│   │   归一化音量,适应不同说话距离和音量        │                │
│   └───────────────┬───────────────────────────┘                │
│                   │                                             │
│                   ▼                                             │
│              增强后的单路音频                                    │
│              (送入KWS/ASR)                                      │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
*/

/**
 * 回声消除 (AEC) 简化实现
 * 使用自适应滤波器估计回声路径
 */
typedef struct {
    float *filter_coeffs;   // 滤波器系数
    float *ref_buffer;      // 参考信号缓冲
    int filter_len;         // 滤波器长度
    float mu;               // 自适应步长
} aec_state_t;

/**
 * NLMS自适应滤波算法
 */
float aec_process_sample(aec_state_t *aec, float mic_in, float ref_in)
{
    // 更新参考缓冲
    memmove(&aec->ref_buffer[1], &aec->ref_buffer[0], 
            (aec->filter_len - 1) * sizeof(float));
    aec->ref_buffer[0] = ref_in;
    
    // 估计回声: y_hat = w^T * x
    float echo_estimate = 0;
    for (int i = 0; i < aec->filter_len; i++) {
        echo_estimate += aec->filter_coeffs[i] * aec->ref_buffer[i];
    }
    
    // 误差(残余信号)
    float error = mic_in - echo_estimate;
    
    // 计算参考信号能量
    float energy = 0;
    for (int i = 0; i < aec->filter_len; i++) {
        energy += aec->ref_buffer[i] * aec->ref_buffer[i];
    }
    
    // NLMS更新: w = w + mu * e * x / (||x||^2 + eps)
    float norm_factor = aec->mu / (energy + 1e-8f);
    for (int i = 0; i < aec->filter_len; i++) {
        aec->filter_coeffs[i] += norm_factor * error * aec->ref_buffer[i];
    }
    
    return error;  // 返回消除回声后的信号
}

/**
 * 延迟求和波束形成 (Delay-and-Sum Beamforming)
 */
typedef struct {
    int num_mics;
    float *delays;          // 各麦克风延迟(采样点)
    float **delay_buffers;  // 延迟缓冲区
    int buffer_len;
} beamformer_t;

/**
 * 计算指向特定方向的延迟
 * @param angle_deg  目标方向角度
 * @param mic_angles 各麦克风角度
 * @param radius_m   阵列半径
 * @param sample_rate 采样率
 */
void calc_steering_delays(beamformer_t *bf, float angle_deg, 
                          float *mic_angles, float radius_m, int sample_rate)
{
    float c = 343.0f;  // 声速 m/s
    float angle_rad = angle_deg * M_PI / 180.0f;
    
    for (int i = 0; i < bf->num_mics; i++) {
        float mic_rad = mic_angles[i] * M_PI / 180.0f;
        // 计算声程差
        float path_diff = radius_m * cosf(angle_rad - mic_rad);
        // 转换为采样点延迟
        bf->delays[i] = path_diff / c * sample_rate;
    }
}

/**
 * 波束形成处理
 */
float beamform_process(beamformer_t *bf, float *mic_samples)
{
    float output = 0;
    
    for (int i = 0; i < bf->num_mics; i++) {
        // 将新样本加入延迟缓冲
        memmove(&bf->delay_buffers[i][1], &bf->delay_buffers[i][0],
                (bf->buffer_len - 1) * sizeof(float));
        bf->delay_buffers[i][0] = mic_samples[i];
        
        // 插值获取延迟后的样本
        int delay_int = (int)bf->delays[i];
        float delay_frac = bf->delays[i] - delay_int;
        
        if (delay_int < bf->buffer_len - 1) {
            float sample = bf->delay_buffers[i][delay_int] * (1 - delay_frac) +
                          bf->delay_buffers[i][delay_int + 1] * delay_frac;
            output += sample;
        }
    }
    
    return output / bf->num_mics;  // 平均
}

声源定位 (DOA)

c 复制代码
/**
 * 声源定位 - GCC-PHAT算法
 * 通过估计麦克风对之间的时延差来定位声源
 */

#include <fftw3.h>
#include <complex.h>

typedef struct {
    int fft_size;
    fftwf_complex *fft_buf1;
    fftwf_complex *fft_buf2;
    fftwf_complex *gcc_buf;
    float *gcc_result;
    fftwf_plan fft_plan1;
    fftwf_plan fft_plan2;
    fftwf_plan ifft_plan;
} gcc_phat_t;

/**
 * GCC-PHAT计算两路信号的时延
 */
float gcc_phat_tdoa(gcc_phat_t *gcc, float *sig1, float *sig2, int len)
{
    // FFT
    memset(gcc->fft_buf1, 0, gcc->fft_size * sizeof(fftwf_complex));
    memset(gcc->fft_buf2, 0, gcc->fft_size * sizeof(fftwf_complex));
    
    for (int i = 0; i < len; i++) {
        gcc->fft_buf1[i] = sig1[i];
        gcc->fft_buf2[i] = sig2[i];
    }
    
    fftwf_execute(gcc->fft_plan1);
    fftwf_execute(gcc->fft_plan2);
    
    // 计算互功率谱密度并归一化(PHAT加权)
    for (int i = 0; i < gcc->fft_size; i++) {
        fftwf_complex cross = gcc->fft_buf1[i] * conjf(gcc->fft_buf2[i]);
        float mag = cabsf(cross);
        
        if (mag > 1e-10f) {
            gcc->gcc_buf[i] = cross / mag;  // PHAT加权
        } else {
            gcc->gcc_buf[i] = 0;
        }
    }
    
    // IFFT得到广义互相关函数
    fftwf_execute(gcc->ifft_plan);
    
    // 找峰值位置
    int max_idx = 0;
    float max_val = 0;
    int half = gcc->fft_size / 2;
    
    for (int i = 0; i < gcc->fft_size; i++) {
        if (gcc->gcc_result[i] > max_val) {
            max_val = gcc->gcc_result[i];
            max_idx = i;
        }
    }
    
    // 转换为时延(支持正负延迟)
    int tdoa_samples = (max_idx <= half) ? max_idx : (max_idx - gcc->fft_size);
    
    return (float)tdoa_samples;
}

/**
 * 基于TDOA的声源定位
 * 使用多对麦克风的时延估计声源方向
 */
float estimate_doa(float *mic_signals[], int num_mics, int frame_len,
                   float *mic_angles, float radius_m, int sample_rate)
{
    gcc_phat_t gcc;
    // ... 初始化gcc
    
    float c = 343.0f;
    float best_angle = 0;
    float best_score = -1e9f;
    
    // 搜索360度
    for (int angle = 0; angle < 360; angle += 5) {
        float score = 0;
        float angle_rad = angle * M_PI / 180.0f;
        
        // 对每对麦克风
        for (int i = 0; i < num_mics; i++) {
            for (int j = i + 1; j < num_mics; j++) {
                // 预期时延
                float mic_i_rad = mic_angles[i] * M_PI / 180.0f;
                float mic_j_rad = mic_angles[j] * M_PI / 180.0f;
                
                float expected_tdoa = (radius_m / c) * sample_rate *
                    (cosf(angle_rad - mic_i_rad) - cosf(angle_rad - mic_j_rad));
                
                // 实测时延
                float measured_tdoa = gcc_phat_tdoa(&gcc, mic_signals[i], 
                                                     mic_signals[j], frame_len);
                
                // 评分(时延越接近,分数越高)
                score -= fabsf(expected_tdoa - measured_tdoa);
            }
        }
        
        if (score > best_score) {
            best_score = score;
            best_angle = angle;
        }
    }
    
    return best_angle;
}

唤醒词检测 (KWS)

KWS系统架构

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                    唤醒词检测 (KWS) 系统                         │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│                     增强后的音频流                               │
│                          │                                      │
│                          ▼                                      │
│   ┌─────────────────────────────────────────────────────────┐  │
│   │                    特征提取                              │  │
│   │                                                         │  │
│   │   音频帧 ──→ 预加重 ──→ 分帧 ──→ 加窗 ──→ FFT          │  │
│   │      │                                                  │  │
│   │      └──→ Mel滤波器组 ──→ 对数 ──→ DCT ──→ MFCC       │  │
│   │                               或                        │  │
│   │      └──→ Mel滤波器组 ──→ 对数 ──→ FBank特征           │  │
│   │                                                         │  │
│   │   输出: 每帧 40维 FBank 或 13维 MFCC + Δ + ΔΔ          │  │
│   └───────────────────────────┬─────────────────────────────┘  │
│                               │ [Batch × Time × Features]      │
│                               ▼                                 │
│   ┌─────────────────────────────────────────────────────────┐  │
│   │                    神经网络模型                          │  │
│   │                                                         │  │
│   │   方案1: DNN (全连接)                                   │  │
│   │   [输入层] → [隐藏层×3] → [输出层(唤醒词+非唤醒词)]     │  │
│   │   优点: 简单,计算量小                                  │  │
│   │   缺点: 不能建模时序                                    │  │
│   │                                                         │  │
│   │   方案2: CNN (卷积)                                     │  │
│   │   [输入] → [Conv2D×N] → [Pool] → [FC] → [Softmax]      │  │
│   │   优点: 参数少,适合频谱特征                            │  │
│   │                                                         │  │
│   │   方案3: RNN/LSTM/GRU                                   │  │
│   │   [输入] → [LSTM×2] → [FC] → [Softmax]                 │  │
│   │   优点: 建模时序,效果好                                │  │
│   │   缺点: 计算量较大                                      │  │
│   │                                                         │  │
│   │   方案4: DS-CNN (Depthwise Separable CNN) ★推荐        │  │
│   │   [输入] → [DS-Conv×4] → [Avg Pool] → [FC]             │  │
│   │   优点: 参数少,效果好,适合嵌入式                      │  │
│   │                                                         │  │
│   │   方案5: Attention-based                                │  │
│   │   使用Self-Attention建模全局依赖                        │  │
│   │                                                         │  │
│   └───────────────────────────┬─────────────────────────────┘  │
│                               │                                 │
│                               ▼                                 │
│   ┌─────────────────────────────────────────────────────────┐  │
│   │                    后处理                                │  │
│   │                                                         │  │
│   │   - 平滑: 滑动窗口平均,减少抖动                        │  │
│   │   - 阈值: 置信度 > threshold 才触发                     │  │
│   │   - 去抖: 连续N帧高于阈值才确认                         │  │
│   │   - 冷却: 触发后一段时间不再响应                        │  │
│   │                                                         │  │
│   └───────────────────────────┬─────────────────────────────┘  │
│                               │                                 │
│                               ▼                                 │
│                          唤醒事件                               │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

MFCC特征提取

c 复制代码
/**
 * MFCC特征提取完整实现
 */

#include <math.h>
#include <string.h>

#define SAMPLE_RATE     16000
#define FRAME_SIZE      400     // 25ms @ 16kHz
#define FRAME_SHIFT     160     // 10ms
#define FFT_SIZE        512
#define NUM_MEL_BINS    40
#define NUM_MFCC        13

/**
 * 预加重滤波器
 * y[n] = x[n] - α * x[n-1]
 */
void preemphasis(float *signal, int len, float alpha)
{
    for (int i = len - 1; i > 0; i--) {
        signal[i] -= alpha * signal[i - 1];
    }
    signal[0] *= (1 - alpha);
}

/**
 * 汉明窗
 */
void hamming_window(float *frame, int len)
{
    for (int i = 0; i < len; i++) {
        float window = 0.54f - 0.46f * cosf(2 * M_PI * i / (len - 1));
        frame[i] *= window;
    }
}

/**
 * Hz到Mel的转换
 */
float hz_to_mel(float hz)
{
    return 2595.0f * log10f(1.0f + hz / 700.0f);
}

/**
 * Mel到Hz的转换
 */
float mel_to_hz(float mel)
{
    return 700.0f * (powf(10.0f, mel / 2595.0f) - 1.0f);
}

/**
 * Mel滤波器组
 */
typedef struct {
    int num_bins;
    int fft_size;
    int sample_rate;
    float **filters;    // [num_bins][fft_size/2+1]
} mel_filterbank_t;

void init_mel_filterbank(mel_filterbank_t *fb, int num_bins, int fft_size, int sample_rate)
{
    fb->num_bins = num_bins;
    fb->fft_size = fft_size;
    fb->sample_rate = sample_rate;
    
    int num_fft_bins = fft_size / 2 + 1;
    
    // 分配滤波器
    fb->filters = malloc(num_bins * sizeof(float *));
    for (int i = 0; i < num_bins; i++) {
        fb->filters[i] = calloc(num_fft_bins, sizeof(float));
    }
    
    // 计算Mel频率点
    float mel_low = hz_to_mel(0);
    float mel_high = hz_to_mel(sample_rate / 2.0f);
    
    float *mel_points = malloc((num_bins + 2) * sizeof(float));
    float *hz_points = malloc((num_bins + 2) * sizeof(float));
    int *bin_points = malloc((num_bins + 2) * sizeof(int));
    
    for (int i = 0; i < num_bins + 2; i++) {
        mel_points[i] = mel_low + (mel_high - mel_low) * i / (num_bins + 1);
        hz_points[i] = mel_to_hz(mel_points[i]);
        bin_points[i] = (int)floorf((fft_size + 1) * hz_points[i] / sample_rate);
    }
    
    // 构建三角滤波器
    for (int m = 0; m < num_bins; m++) {
        for (int k = bin_points[m]; k < bin_points[m + 1]; k++) {
            fb->filters[m][k] = (float)(k - bin_points[m]) / 
                                (bin_points[m + 1] - bin_points[m]);
        }
        for (int k = bin_points[m + 1]; k < bin_points[m + 2]; k++) {
            fb->filters[m][k] = (float)(bin_points[m + 2] - k) / 
                                (bin_points[m + 2] - bin_points[m + 1]);
        }
    }
    
    free(mel_points);
    free(hz_points);
    free(bin_points);
}

/**
 * 应用Mel滤波器组
 */
void apply_mel_filterbank(mel_filterbank_t *fb, float *power_spectrum, float *mel_energies)
{
    int num_fft_bins = fb->fft_size / 2 + 1;
    
    for (int m = 0; m < fb->num_bins; m++) {
        mel_energies[m] = 0;
        for (int k = 0; k < num_fft_bins; k++) {
            mel_energies[m] += power_spectrum[k] * fb->filters[m][k];
        }
        // 取对数(加小值防止log(0))
        mel_energies[m] = logf(mel_energies[m] + 1e-10f);
    }
}

/**
 * DCT-II变换(用于从FBank得到MFCC)
 */
void dct(float *input, float *output, int input_len, int output_len)
{
    for (int k = 0; k < output_len; k++) {
        output[k] = 0;
        for (int n = 0; n < input_len; n++) {
            output[k] += input[n] * cosf(M_PI * k * (n + 0.5f) / input_len);
        }
        // 归一化
        output[k] *= sqrtf(2.0f / input_len);
    }
}

/**
 * 完整的MFCC提取
 */
typedef struct {
    mel_filterbank_t mel_fb;
    float *frame_buffer;
    float *fft_buffer;
    float *power_spectrum;
    float *mel_energies;
    float *mfcc;
    // FFT相关
    // ... (使用kiss_fft或其他库)
} mfcc_extractor_t;

void extract_mfcc(mfcc_extractor_t *ext, float *audio_frame, float *features)
{
    // 1. 复制帧数据
    memcpy(ext->frame_buffer, audio_frame, FRAME_SIZE * sizeof(float));
    
    // 2. 预加重
    preemphasis(ext->frame_buffer, FRAME_SIZE, 0.97f);
    
    // 3. 加窗
    hamming_window(ext->frame_buffer, FRAME_SIZE);
    
    // 4. 零填充到FFT大小
    memset(&ext->frame_buffer[FRAME_SIZE], 0, 
           (FFT_SIZE - FRAME_SIZE) * sizeof(float));
    
    // 5. FFT
    // fft_forward(ext->frame_buffer, ext->fft_buffer, FFT_SIZE);
    
    // 6. 计算功率谱
    for (int i = 0; i <= FFT_SIZE / 2; i++) {
        float real = ext->fft_buffer[2 * i];
        float imag = ext->fft_buffer[2 * i + 1];
        ext->power_spectrum[i] = real * real + imag * imag;
    }
    
    // 7. Mel滤波
    apply_mel_filterbank(&ext->mel_fb, ext->power_spectrum, ext->mel_energies);
    
    // 8. DCT得到MFCC(如果需要)
    dct(ext->mel_energies, ext->mfcc, NUM_MEL_BINS, NUM_MFCC);
    
    // 输出FBank特征或MFCC
    memcpy(features, ext->mel_energies, NUM_MEL_BINS * sizeof(float));
    // 或: memcpy(features, ext->mfcc, NUM_MFCC * sizeof(float));
}

KWS神经网络模型

c 复制代码
/**
 * DS-CNN (Depthwise Separable CNN) 唤醒词模型
 * 适合嵌入式部署,参数量小,效果好
 */

/**
 * 模型结构(PyTorch定义,用于训练)
 */
/*
class DS_CNN(nn.Module):
    def __init__(self, num_classes=2):  # 唤醒词 + 非唤醒词
        super().__init__()
        
        # 输入: [Batch, 1, Time, Freq] = [B, 1, 98, 40]
        # 98帧 × 40维FBank,约1秒音频
        
        self.conv1 = nn.Conv2d(1, 64, kernel_size=(10, 4), stride=(2, 2), padding=(4, 1))
        self.bn1 = nn.BatchNorm2d(64)
        
        # 4个DS-Conv块
        self.ds_blocks = nn.Sequential(
            DSConvBlock(64, 64),
            DSConvBlock(64, 64),
            DSConvBlock(64, 64),
            DSConvBlock(64, 64),
        )
        
        self.avg_pool = nn.AdaptiveAvgPool2d(1)
        self.fc = nn.Linear(64, num_classes)
        
    def forward(self, x):
        x = F.relu(self.bn1(self.conv1(x)))
        x = self.ds_blocks(x)
        x = self.avg_pool(x)
        x = x.view(x.size(0), -1)
        x = self.fc(x)
        return x

class DSConvBlock(nn.Module):
    """深度可分离卷积块"""
    def __init__(self, in_ch, out_ch):
        super().__init__()
        # Depthwise卷积
        self.dw_conv = nn.Conv2d(in_ch, in_ch, kernel_size=3, padding=1, groups=in_ch)
        self.bn1 = nn.BatchNorm2d(in_ch)
        # Pointwise卷积
        self.pw_conv = nn.Conv2d(in_ch, out_ch, kernel_size=1)
        self.bn2 = nn.BatchNorm2d(out_ch)
        
    def forward(self, x):
        x = F.relu(self.bn1(self.dw_conv(x)))
        x = F.relu(self.bn2(self.pw_conv(x)))
        return x
*/

/**
 * C语言推理实现(量化INT8版本)
 */

// 模型参数(量化后)
typedef struct {
    // Conv1: 1→64, kernel 10×4
    int8_t conv1_weight[64][1][10][4];
    int32_t conv1_bias[64];
    float conv1_scale;
    
    // DS-Conv blocks
    struct {
        int8_t dw_weight[64][1][3][3];
        int32_t dw_bias[64];
        float dw_scale;
        int8_t pw_weight[64][64][1][1];
        int32_t pw_bias[64];
        float pw_scale;
    } ds_blocks[4];
    
    // FC: 64 → 2
    int8_t fc_weight[2][64];
    int32_t fc_bias[2];
    float fc_scale;
    
    // 输入输出scale
    float input_scale;
    int8_t input_zero_point;
} kws_model_t;

/**
 * 量化推理
 */
typedef struct {
    kws_model_t *model;
    int8_t *feature_buffer;     // 输入特征
    int8_t *conv_buffer[2];     // 中间计算缓冲
    int current_buf;
} kws_inference_t;

/**
 * 运行KWS推理
 * @param features  输入特征 [98帧 × 40维]
 * @return 唤醒词置信度 (0.0 - 1.0)
 */
float kws_inference(kws_inference_t *kws, float *features)
{
    // 1. 量化输入
    for (int i = 0; i < 98 * 40; i++) {
        int32_t q = (int32_t)roundf(features[i] / kws->model->input_scale) + 
                    kws->model->input_zero_point;
        kws->feature_buffer[i] = (int8_t)CLAMP(q, -128, 127);
    }
    
    // 2. Conv1
    conv2d_int8(kws->feature_buffer, kws->conv_buffer[0],
                98, 40, 1,    // 输入: H, W, C
                64,           // 输出通道
                10, 4,        // kernel
                2, 2,         // stride
                kws->model->conv1_weight,
                kws->model->conv1_bias,
                kws->model->conv1_scale);
    
    // 3. DS-Conv blocks
    int h = 49, w = 19, c = 64;  // Conv1后的尺寸
    
    for (int b = 0; b < 4; b++) {
        // Depthwise Conv
        depthwise_conv2d_int8(
            kws->conv_buffer[kws->current_buf],
            kws->conv_buffer[1 - kws->current_buf],
            h, w, c,
            3, 3, 1, 1,  // kernel, stride
            kws->model->ds_blocks[b].dw_weight,
            kws->model->ds_blocks[b].dw_bias,
            kws->model->ds_blocks[b].dw_scale);
        
        kws->current_buf = 1 - kws->current_buf;
        
        // Pointwise Conv
        pointwise_conv2d_int8(
            kws->conv_buffer[kws->current_buf],
            kws->conv_buffer[1 - kws->current_buf],
            h, w, c, c,
            kws->model->ds_blocks[b].pw_weight,
            kws->model->ds_blocks[b].pw_bias,
            kws->model->ds_blocks[b].pw_scale);
        
        kws->current_buf = 1 - kws->current_buf;
    }
    
    // 4. Global Average Pooling
    float pooled[64];
    for (int ch = 0; ch < 64; ch++) {
        int32_t sum = 0;
        for (int i = 0; i < h * w; i++) {
            sum += kws->conv_buffer[kws->current_buf][i * c + ch];
        }
        pooled[ch] = (float)sum / (h * w);
    }
    
    // 5. FC层
    float logits[2];
    for (int i = 0; i < 2; i++) {
        int32_t sum = kws->model->fc_bias[i];
        for (int j = 0; j < 64; j++) {
            sum += (int32_t)kws->model->fc_weight[i][j] * (int32_t)roundf(pooled[j]);
        }
        logits[i] = sum * kws->model->fc_scale;
    }
    
    // 6. Softmax
    float exp0 = expf(logits[0]);
    float exp1 = expf(logits[1]);
    float confidence = exp1 / (exp0 + exp1);  // 唤醒词概率
    
    return confidence;
}

/**
 * 唤醒词检测主循环
 */
typedef struct {
    kws_inference_t kws;
    mfcc_extractor_t mfcc;
    
    float confidence_threshold;     // 置信度阈值
    int smooth_window;              // 平滑窗口
    float *confidence_history;      // 置信度历史
    int history_idx;
    
    int trigger_count;              // 连续触发计数
    int trigger_threshold;          // 触发阈值
    uint32_t last_trigger_time;     // 上次触发时间
    uint32_t cooldown_ms;           // 冷却时间
} kws_detector_t;

/**
 * 处理一帧音频
 * @return 1=检测到唤醒词, 0=未检测到
 */
int kws_process_frame(kws_detector_t *det, float *audio_frame)
{
    // 1. 提取特征
    float features[NUM_MEL_BINS];
    extract_mfcc(&det->mfcc, audio_frame, features);
    
    // 2. 更新特征缓冲(滑动窗口)
    // 将新特征加入缓冲...
    
    // 3. 每隔N帧运行一次推理
    static int frame_count = 0;
    if (++frame_count < 5) return 0;  // 每5帧推理一次
    frame_count = 0;
    
    // 4. 推理
    float confidence = kws_inference(&det->kws, det->feature_buffer);
    
    // 5. 平滑
    det->confidence_history[det->history_idx] = confidence;
    det->history_idx = (det->history_idx + 1) % det->smooth_window;
    
    float avg_confidence = 0;
    for (int i = 0; i < det->smooth_window; i++) {
        avg_confidence += det->confidence_history[i];
    }
    avg_confidence /= det->smooth_window;
    
    // 6. 阈值判断
    if (avg_confidence > det->confidence_threshold) {
        det->trigger_count++;
    } else {
        det->trigger_count = 0;
    }
    
    // 7. 去抖 & 冷却
    uint32_t now = get_time_ms();
    
    if (det->trigger_count >= det->trigger_threshold) {
        if (now - det->last_trigger_time > det->cooldown_ms) {
            det->last_trigger_time = now;
            det->trigger_count = 0;
            return 1;  // 检测到唤醒词!
        }
    }
    
    return 0;
}

常见KWS芯片

c 复制代码
/**
 * 常见的KWS专用芯片
 */

/*
┌──────────────────────────────────────────────────────────────────────────────┐
│                        KWS芯片选型对比                                        │
├────────────────┬─────────────┬────────────┬────────────┬────────────────────┤
│     芯片        │   厂商      │  功耗      │   特点      │      适用场景       │
├────────────────┼─────────────┼────────────┼────────────┼────────────────────┤
│ 杭州国芯       │             │            │            │                    │
│ GX8002         │  国芯科技    │  <1mW      │ 本土方案    │ 智能音箱/家电      │
│                │             │            │ 低功耗NPU   │                    │
├────────────────┼─────────────┼────────────┼────────────┼────────────────────┤
│ 探境科技       │             │            │            │                    │
│ SH1001         │  探境科技    │  <2mW      │ 存算一体    │ TWS耳机/音箱       │
│                │             │            │ 超低功耗    │                    │
├────────────────┼─────────────┼────────────┼────────────┼────────────────────┤
│ 知存科技       │             │            │            │                    │
│ WTM2101        │  知存科技    │  <1mW      │ 存内计算    │ 可穿戴/IoT        │
│                │             │            │ 模拟计算    │                    │
├────────────────┼─────────────┼────────────┼────────────┼────────────────────┤
│ Syntiant       │             │            │            │                    │
│ NDP101/120     │  Syntiant   │  <1mW      │ 神经决策    │ 高端TWS耳机        │
│                │             │            │ 处理器     │                    │
├────────────────┼─────────────┼────────────┼────────────┼────────────────────┤
│ Google         │             │            │            │                    │
│ Edge TPU       │  Google     │  ~2W       │ 高性能     │ 智能音箱/显示器     │
│                │             │            │ 多功能     │                    │
├────────────────┼─────────────┼────────────┼────────────┼────────────────────┤
│ 全志           │             │            │            │                    │
│ R328/R329      │  全志科技    │  ~100mW    │ 带NPU的AP  │ 带屏智能音箱       │
│                │             │            │ Linux支持  │                    │
├────────────────┼─────────────┼────────────┼────────────┼────────────────────┤
│ 瑞芯微         │             │            │            │                    │
│ RK3308/RV1109  │  瑞芯微     │  ~200mW    │ 多核+NPU   │ 智能音箱/门铃      │
│                │             │            │ 接口丰富   │                    │
└────────────────┴─────────────┴────────────┴────────────┴────────────────────┘

典型方案组合:
1. 低成本方案: GX8002(KWS) + RK3308(主控)
2. 中端方案: 内置NPU的SoC(如R329)一体化
3. 高端方案: 独立NPU + 高性能AP
*/

语音端点检测 (VAD)

唤醒后需要确定用户说话的起止点:

c 复制代码
/**
 * VAD (Voice Activity Detection) 实现
 */

typedef enum {
    VAD_STATE_SILENCE,      // 静音
    VAD_STATE_SPEECH,       // 语音
    VAD_STATE_HANGOVER      // 挂起(语音结束后的缓冲期)
} vad_state_t;

typedef struct {
    vad_state_t state;
    
    // 能量检测
    float energy_threshold;
    float noise_floor;          // 噪声基底
    float noise_adapt_rate;     // 噪声自适应速率
    
    // 过零率
    float zcr_threshold;
    
    // 帧计数
    int speech_frames;
    int silence_frames;
    int hangover_frames;
    
    // 阈值
    int min_speech_frames;      // 最小语音帧数
    int min_silence_frames;     // 最小静音帧数
    int hangover_threshold;     // 挂起阈值
    
    // 录音控制
    int is_recording;
    float *record_buffer;
    int record_len;
    int max_record_len;
} vad_detector_t;

/**
 * 计算帧能量(dB)
 */
float calc_frame_energy_db(float *frame, int len)
{
    float sum = 0;
    for (int i = 0; i < len; i++) {
        sum += frame[i] * frame[i];
    }
    return 10 * log10f(sum / len + 1e-10f);
}

/**
 * 计算过零率
 */
float calc_zcr(float *frame, int len)
{
    int crossings = 0;
    for (int i = 1; i < len; i++) {
        if ((frame[i] >= 0 && frame[i-1] < 0) ||
            (frame[i] < 0 && frame[i-1] >= 0)) {
            crossings++;
        }
    }
    return (float)crossings / (len - 1);
}

/**
 * VAD处理一帧
 * @return 1=语音结束(可以发送到ASR),0=继续
 */
int vad_process_frame(vad_detector_t *vad, float *frame, int len)
{
    float energy = calc_frame_energy_db(frame, len);
    float zcr = calc_zcr(frame, len);
    
    // 动态更新噪声基底
    if (vad->state == VAD_STATE_SILENCE) {
        vad->noise_floor = vad->noise_floor * (1 - vad->noise_adapt_rate) +
                           energy * vad->noise_adapt_rate;
    }
    
    // 判断是否有语音
    float threshold = vad->noise_floor + vad->energy_threshold;
    int is_speech = (energy > threshold) || (zcr > vad->zcr_threshold);
    
    // 状态机
    switch (vad->state) {
    case VAD_STATE_SILENCE:
        if (is_speech) {
            vad->speech_frames++;
            if (vad->speech_frames >= vad->min_speech_frames) {
                // 开始录音
                vad->state = VAD_STATE_SPEECH;
                vad->is_recording = 1;
                vad->record_len = 0;
                vad->silence_frames = 0;
            }
        } else {
            vad->speech_frames = 0;
        }
        break;
        
    case VAD_STATE_SPEECH:
        // 录制
        if (vad->is_recording && vad->record_len < vad->max_record_len) {
            memcpy(&vad->record_buffer[vad->record_len], frame, len * sizeof(float));
            vad->record_len += len;
        }
        
        if (!is_speech) {
            vad->silence_frames++;
            if (vad->silence_frames >= vad->min_silence_frames) {
                vad->state = VAD_STATE_HANGOVER;
                vad->hangover_frames = 0;
            }
        } else {
            vad->silence_frames = 0;
        }
        break;
        
    case VAD_STATE_HANGOVER:
        // 继续录制挂起期间的音频
        if (vad->is_recording && vad->record_len < vad->max_record_len) {
            memcpy(&vad->record_buffer[vad->record_len], frame, len * sizeof(float));
            vad->record_len += len;
        }
        
        if (is_speech) {
            // 语音恢复
            vad->state = VAD_STATE_SPEECH;
            vad->silence_frames = 0;
        } else {
            vad->hangover_frames++;
            if (vad->hangover_frames >= vad->hangover_threshold) {
                // 语音结束
                vad->state = VAD_STATE_SILENCE;
                vad->is_recording = 0;
                vad->speech_frames = 0;
                return 1;  // 语音结束,可以发送
            }
        }
        break;
    }
    
    return 0;
}

/**
 * 初始化VAD
 */
void vad_init(vad_detector_t *vad, float sample_rate)
{
    vad->state = VAD_STATE_SILENCE;
    vad->energy_threshold = 10.0f;      // 比噪声高10dB
    vad->noise_floor = -60.0f;          // 初始噪声估计
    vad->noise_adapt_rate = 0.01f;
    vad->zcr_threshold = 0.15f;
    
    // 帧数阈值(假设10ms帧移)
    vad->min_speech_frames = 10;        // 100ms确认语音开始
    vad->min_silence_frames = 20;       // 200ms开始结束检测
    vad->hangover_threshold = 50;       // 500ms静音确认结束
    
    vad->is_recording = 0;
    vad->record_len = 0;
    vad->max_record_len = 16000 * 10;   // 最长10秒
    vad->record_buffer = malloc(vad->max_record_len * sizeof(float));
}

云端通信与ASR

音频上传协议

c 复制代码
/**
 * 与云端通信的协议实现
 */

#include <websocket.h>
#include <opus.h>

/**
 * 音频编码(Opus)
 */
typedef struct {
    OpusEncoder *encoder;
    int sample_rate;
    int channels;
    int bitrate;
} audio_encoder_t;

void audio_encoder_init(audio_encoder_t *enc)
{
    int error;
    enc->sample_rate = 16000;
    enc->channels = 1;
    enc->bitrate = 16000;  // 16kbps
    
    enc->encoder = opus_encoder_create(enc->sample_rate, enc->channels,
                                        OPUS_APPLICATION_VOIP, &error);
    opus_encoder_ctl(enc->encoder, OPUS_SET_BITRATE(enc->bitrate));
    opus_encoder_ctl(enc->encoder, OPUS_SET_COMPLEXITY(5));
}

/**
 * 编码一帧
 */
int audio_encode_frame(audio_encoder_t *enc, int16_t *pcm, int frame_size,
                        uint8_t *output, int max_output)
{
    return opus_encode(enc->encoder, pcm, frame_size, output, max_output);
}

/**
 * WebSocket客户端
 */
typedef struct {
    ws_client_t *ws;
    audio_encoder_t encoder;
    
    char *server_url;
    char *auth_token;
    
    // 回调
    void (*on_asr_result)(const char *text);
    void (*on_llm_response)(const char *text);
    void (*on_tts_audio)(const uint8_t *data, int len);
} cloud_client_t;

/**
 * 消息类型定义
 */
#define MSG_TYPE_AUDIO      0x01
#define MSG_TYPE_ASR_RESULT 0x02
#define MSG_TYPE_LLM_QUERY  0x03
#define MSG_TYPE_LLM_RESP   0x04
#define MSG_TYPE_TTS_AUDIO  0x05
#define MSG_TYPE_CONTROL    0x06

/**
 * 上传音频数据
 */
void cloud_upload_audio(cloud_client_t *client, float *audio, int len)
{
    // 1. 转换为16位整数
    int16_t *pcm = malloc(len * sizeof(int16_t));
    for (int i = 0; i < len; i++) {
        pcm[i] = (int16_t)(audio[i] * 32767);
    }
    
    // 2. 分帧编码上传
    int frame_size = 320;  // 20ms @ 16kHz
    uint8_t opus_buf[512];
    
    for (int offset = 0; offset < len; offset += frame_size) {
        int frame_len = (offset + frame_size <= len) ? frame_size : (len - offset);
        
        // 编码
        int encoded_len = audio_encode_frame(&client->encoder, 
                                              &pcm[offset], frame_len,
                                              opus_buf, sizeof(opus_buf));
        
        if (encoded_len > 0) {
            // 构建消息
            uint8_t msg[520];
            msg[0] = MSG_TYPE_AUDIO;
            msg[1] = (encoded_len >> 8) & 0xFF;
            msg[2] = encoded_len & 0xFF;
            memcpy(&msg[3], opus_buf, encoded_len);
            
            // 发送
            ws_send_binary(client->ws, msg, 3 + encoded_len);
        }
    }
    
    // 3. 发送结束标志
    uint8_t end_msg[] = {MSG_TYPE_AUDIO, 0, 0};
    ws_send_binary(client->ws, end_msg, 3);
    
    free(pcm);
}

/**
 * 处理云端响应
 */
void cloud_on_message(cloud_client_t *client, uint8_t *data, int len)
{
    uint8_t msg_type = data[0];
    
    switch (msg_type) {
    case MSG_TYPE_ASR_RESULT: {
        // ASR识别结果
        char text[256];
        int text_len = (data[1] << 8) | data[2];
        memcpy(text, &data[3], text_len);
        text[text_len] = '\0';
        
        if (client->on_asr_result) {
            client->on_asr_result(text);
        }
        break;
    }
    
    case MSG_TYPE_LLM_RESP: {
        // LLM回答(流式)
        char text[1024];
        int text_len = (data[1] << 8) | data[2];
        memcpy(text, &data[3], text_len);
        text[text_len] = '\0';
        
        if (client->on_llm_response) {
            client->on_llm_response(text);
        }
        break;
    }
    
    case MSG_TYPE_TTS_AUDIO: {
        // TTS音频流
        int audio_len = (data[1] << 8) | data[2];
        if (client->on_tts_audio) {
            client->on_tts_audio(&data[3], audio_len);
        }
        break;
    }
    }
}

/**
 * 完整的一次对话流程
 */
void do_conversation(cloud_client_t *client, float *audio, int audio_len)
{
    printf("上传音频...\n");
    cloud_upload_audio(client, audio, audio_len);
    
    // 等待并处理响应(在回调中处理)
    // ASR结果 -> 显示识别文字
    // LLM响应 -> 同时发给TTS
    // TTS音频 -> 播放
}

云端服务架构

复制代码
┌─────────────────────────────────────────────────────────────────────────────┐
│                          云端服务架构                                        │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   设备侧                              │             云端                    │
│                                       │                                     │
│   ┌─────────────┐                    │    ┌─────────────────────────────┐ │
│   │  智能音箱   │                    │    │       负载均衡器             │ │
│   │             │──WebSocket/HTTP2──→│    │    (Nginx/HAProxy)          │ │
│   └─────────────┘                    │    └────────────┬────────────────┘ │
│                                       │                 │                  │
│                                       │    ┌────────────┴────────────┐    │
│                                       │    │                         │    │
│                                       │    ▼                         ▼    │
│                                       │  ┌───────────┐         ┌───────────┐
│                                       │  │  接入网关  │         │  接入网关  │
│                                       │  │  Gateway  │         │  Gateway  │
│                                       │  └─────┬─────┘         └─────┬─────┘
│                                       │        │                     │     │
│                                       │        │    消息队列          │     │
│                                       │        └──────┬──────────────┘     │
│                                       │               │                    │
│                                       │               ▼                    │
│                                       │    ┌─────────────────────────────┐│
│                                       │    │        Kafka/RabbitMQ       ││
│                                       │    └────────────┬────────────────┘│
│                                       │                 │                  │
│                                       │    ┌────────────┼────────────┐    │
│                                       │    │            │            │    │
│                                       │    ▼            ▼            ▼    │
│                                       │ ┌──────┐   ┌──────┐    ┌──────┐  │
│                                       │ │ ASR  │   │ NLU/ │    │ TTS  │  │
│                                       │ │Service│   │ LLM  │    │Service│  │
│                                       │ │      │   │Service│    │      │  │
│                                       │ └──────┘   └──────┘    └──────┘  │
│                                       │     │          │           │      │
│                                       │     │          │           │      │
│                                       │     └──────────┼───────────┘      │
│                                       │                │                  │
│                                       │                ▼                  │
│                                       │    ┌─────────────────────────────┐│
│                                       │    │      Redis / Database       ││
│                                       │    │    (会话状态/用户数据)       ││
│                                       │    └─────────────────────────────┘│
│                                       │                                    │
└───────────────────────────────────────┴────────────────────────────────────┘

大模型集成

LLM调用流程

c 复制代码
/**
 * 大模型调用接口
 */

// 对话历史
typedef struct {
    char role[16];      // "user" 或 "assistant"
    char content[1024];
} chat_message_t;

typedef struct {
    chat_message_t messages[20];
    int message_count;
} chat_history_t;

/**
 * LLM请求(以OpenAI格式为例,国内大模型类似)
 */
typedef struct {
    const char *model;          // 模型名称
    chat_history_t *history;    // 对话历史
    float temperature;          // 随机性
    int max_tokens;             // 最大输出长度
    int stream;                 // 是否流式输出
} llm_request_t;

/**
 * 构建LLM请求JSON
 */
char* build_llm_request(llm_request_t *req)
{
    // 使用cJSON构建
    cJSON *root = cJSON_CreateObject();
    cJSON_AddStringToObject(root, "model", req->model);
    cJSON_AddNumberToObject(root, "temperature", req->temperature);
    cJSON_AddNumberToObject(root, "max_tokens", req->max_tokens);
    cJSON_AddBoolToObject(root, "stream", req->stream);
    
    // 添加消息数组
    cJSON *messages = cJSON_CreateArray();
    
    // 系统提示
    cJSON *system_msg = cJSON_CreateObject();
    cJSON_AddStringToObject(system_msg, "role", "system");
    cJSON_AddStringToObject(system_msg, "content", 
        "你是一个智能音箱助手,回答要简洁,适合语音播报。");
    cJSON_AddItemToArray(messages, system_msg);
    
    // 对话历史
    for (int i = 0; i < req->history->message_count; i++) {
        cJSON *msg = cJSON_CreateObject();
        cJSON_AddStringToObject(msg, "role", req->history->messages[i].role);
        cJSON_AddStringToObject(msg, "content", req->history->messages[i].content);
        cJSON_AddItemToArray(messages, msg);
    }
    
    cJSON_AddItemToObject(root, "messages", messages);
    
    char *json_str = cJSON_PrintUnformatted(root);
    cJSON_Delete(root);
    
    return json_str;
}

/**
 * 流式解析LLM响应
 * SSE (Server-Sent Events) 格式
 */
typedef struct {
    char *buffer;
    int buffer_len;
    void (*on_token)(const char *token);
    void (*on_complete)(const char *full_text);
} llm_stream_parser_t;

void parse_llm_stream_chunk(llm_stream_parser_t *parser, const char *chunk)
{
    // SSE格式: data: {...}\n\n
    if (strncmp(chunk, "data: ", 6) != 0) return;
    
    const char *json_str = chunk + 6;
    
    // 检查是否结束
    if (strcmp(json_str, "[DONE]") == 0) {
        if (parser->on_complete) {
            parser->on_complete(parser->buffer);
        }
        return;
    }
    
    // 解析JSON
    cJSON *root = cJSON_Parse(json_str);
    if (!root) return;
    
    cJSON *choices = cJSON_GetObjectItem(root, "choices");
    if (choices && cJSON_GetArraySize(choices) > 0) {
        cJSON *choice = cJSON_GetArrayItem(choices, 0);
        cJSON *delta = cJSON_GetObjectItem(choice, "delta");
        if (delta) {
            cJSON *content = cJSON_GetObjectItem(delta, "content");
            if (content && content->valuestring) {
                // 获取新token
                const char *token = content->valuestring;
                
                // 累积到buffer
                int token_len = strlen(token);
                if (parser->buffer_len + token_len < 4096) {
                    strcat(parser->buffer, token);
                    parser->buffer_len += token_len;
                }
                
                // 回调
                if (parser->on_token) {
                    parser->on_token(token);
                }
            }
        }
    }
    
    cJSON_Delete(root);
}

/**
 * 意图识别与槽位填充
 * 对于简单指令,可以不经过LLM
 */
typedef enum {
    INTENT_UNKNOWN,
    INTENT_WEATHER,         // 天气查询
    INTENT_TIME,            // 时间查询
    INTENT_MUSIC,           // 播放音乐
    INTENT_ALARM,           // 设置闹钟
    INTENT_REMINDER,        // 设置提醒
    INTENT_SMART_HOME,      // 智能家居控制
    INTENT_GENERAL_CHAT     // 通用聊天(走LLM)
} intent_type_t;

typedef struct {
    intent_type_t intent;
    char slots[10][2][64];  // [slot_name, slot_value]
    int slot_count;
} nlu_result_t;

/**
 * 简单规则NLU
 */
nlu_result_t* simple_nlu(const char *text)
{
    nlu_result_t *result = malloc(sizeof(nlu_result_t));
    result->intent = INTENT_UNKNOWN;
    result->slot_count = 0;
    
    // 天气查询
    if (strstr(text, "天气") != NULL) {
        result->intent = INTENT_WEATHER;
        
        // 提取城市
        char *city_keywords[] = {"北京", "上海", "广州", "深圳", "杭州"};
        for (int i = 0; i < 5; i++) {
            if (strstr(text, city_keywords[i])) {
                strcpy(result->slots[0][0], "city");
                strcpy(result->slots[0][1], city_keywords[i]);
                result->slot_count = 1;
                break;
            }
        }
        return result;
    }
    
    // 时间查询
    if (strstr(text, "几点") || strstr(text, "时间")) {
        result->intent = INTENT_TIME;
        return result;
    }
    
    // 播放音乐
    if (strstr(text, "播放") || strstr(text, "放一首")) {
        result->intent = INTENT_MUSIC;
        // 提取歌名...
        return result;
    }
    
    // 默认走LLM
    result->intent = INTENT_GENERAL_CHAT;
    return result;
}

/**
 * 处理意图
 */
char* handle_intent(nlu_result_t *nlu, const char *original_text)
{
    char *response = malloc(1024);
    
    switch (nlu->intent) {
    case INTENT_WEATHER: {
        // 调用天气API
        const char *city = (nlu->slot_count > 0) ? nlu->slots[0][1] : "北京";
        // weather_api_query(city, response, 1024);
        snprintf(response, 1024, "%s今天晴,气温15到23度。", city);
        break;
    }
    
    case INTENT_TIME: {
        time_t now = time(NULL);
        struct tm *tm = localtime(&now);
        snprintf(response, 1024, "现在是%d点%d分。", tm->tm_hour, tm->tm_min);
        break;
    }
    
    case INTENT_GENERAL_CHAT: {
        // 调用LLM
        free(response);
        return NULL;  // 返回NULL表示需要走LLM
    }
    
    default:
        snprintf(response, 1024, "抱歉,我不太明白。");
        break;
    }
    
    return response;
}

TTS语音合成

TTS流程

c 复制代码
/**
 * TTS (Text-to-Speech) 处理
 */

/*
TTS流程:

    输入文本: "今天天气晴,气温15到23度"
              │
              ▼
    ┌─────────────────────────────────────┐
    │  文本前端 (Text Frontend)            │
    │                                     │
    │  - 文本正则化                        │
    │    "15到23度" → "十五到二十三度"      │
    │                                     │
    │  - 分词/词性标注                     │
    │                                     │
    │  - 多音字处理                        │
    │    "了" → liǎo/le                   │
    │                                     │
    │  - 韵律预测                          │
    │    插入停顿、重音标记                 │
    │                                     │
    └─────────────────┬───────────────────┘
                      │ 音素序列 + 韵律标记
                      ▼
    ┌─────────────────────────────────────┐
    │  声学模型 (Acoustic Model)           │
    │                                     │
    │  常见模型:                           │
    │  - Tacotron2                        │
    │  - FastSpeech2                      │
    │  - VITS                             │
    │                                     │
    │  输入: 音素序列                       │
    │  输出: Mel频谱                        │
    │                                     │
    └─────────────────┬───────────────────┘
                      │ Mel频谱
                      ▼
    ┌─────────────────────────────────────┐
    │  声码器 (Vocoder)                    │
    │                                     │
    │  常见模型:                           │
    │  - WaveNet (高质量但慢)              │
    │  - WaveRNN                          │
    │  - HiFi-GAN ★ (快+好)               │
    │  - MelGAN                           │
    │                                     │
    │  输入: Mel频谱                        │
    │  输出: 音频波形                       │
    │                                     │
    └─────────────────┬───────────────────┘
                      │ 音频数据
                      ▼
                 播放 / 下发
*/

/**
 * 文本正则化示例
 */
typedef struct {
    const char *pattern;
    const char *replacement;
} normalize_rule_t;

// 数字转文字
char* normalize_number(const char *num_str)
{
    static const char *digits[] = {
        "零", "一", "二", "三", "四", "五", "六", "七", "八", "九"
    };
    
    // 简化实现...
    int num = atoi(num_str);
    char *result = malloc(64);
    
    if (num < 10) {
        strcpy(result, digits[num]);
    } else if (num < 100) {
        sprintf(result, "%s十%s", 
                (num / 10 > 1) ? digits[num / 10] : "",
                (num % 10 > 0) ? digits[num % 10] : "");
    }
    // ... 更多处理
    
    return result;
}

/**
 * 本地TTS(离线方案,使用轻量级模型)
 */
typedef struct {
    // FastSpeech2模型
    void *fs2_model;
    // HiFi-GAN声码器
    void *vocoder_model;
    // 音素字典
    void *phoneme_dict;
} local_tts_t;

/**
 * 云端TTS(质量更好)
 * 大多数智能音箱使用云端TTS
 */
typedef struct {
    const char *api_url;
    const char *api_key;
    const char *voice;          // 音色
    float speed;                // 语速
    float pitch;                // 音调
} cloud_tts_config_t;

/**
 * 请求云端TTS
 */
int request_cloud_tts(cloud_tts_config_t *config, const char *text,
                       void (*on_audio)(const uint8_t *data, int len))
{
    // 构建请求
    cJSON *root = cJSON_CreateObject();
    cJSON_AddStringToObject(root, "text", text);
    cJSON_AddStringToObject(root, "voice", config->voice);
    cJSON_AddNumberToObject(root, "speed", config->speed);
    cJSON_AddNumberToObject(root, "pitch", config->pitch);
    cJSON_AddStringToObject(root, "format", "mp3");
    cJSON_AddBoolToObject(root, "stream", 1);  // 流式返回
    
    char *json_str = cJSON_PrintUnformatted(root);
    
    // HTTP POST请求,流式接收音频数据
    // 每收到一块数据就调用 on_audio 回调
    // ...
    
    cJSON_Delete(root);
    free(json_str);
    
    return 0;
}

完整系统集成

主控程序框架

c 复制代码
/**
 * 智能音箱主控程序
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>

/**
 * 系统状态
 */
typedef enum {
    STATE_IDLE,             // 待机,低功耗监听唤醒词
    STATE_LISTENING,        // 唤醒后,录制用户语音
    STATE_PROCESSING,       // 处理中,等待云端响应
    STATE_SPEAKING,         // 播放回答
    STATE_ERROR             // 错误状态
} system_state_t;

/**
 * 系统上下文
 */
typedef struct {
    system_state_t state;
    
    // 音频前端
    mic_array_config_t mic_config;
    aec_state_t aec;
    beamformer_t beamformer;
    
    // 唤醒检测
    kws_detector_t kws;
    
    // VAD
    vad_detector_t vad;
    
    // 云端通信
    cloud_client_t cloud;
    
    // 音频播放
    audio_player_t player;
    
    // 对话历史
    chat_history_t chat_history;
    
    // LED控制
    led_controller_t led;
    
    // 线程
    pthread_t audio_thread;
    pthread_t network_thread;
    
    volatile int running;
} smart_speaker_t;

static smart_speaker_t g_speaker;

/**
 * 音频处理线程
 */
void* audio_thread_func(void *arg)
{
    smart_speaker_t *speaker = (smart_speaker_t *)arg;
    
    // 音频缓冲区
    float mic_samples[6][FRAME_SIZE];       // 6麦克风
    float enhanced_audio[FRAME_SIZE];        // 增强后
    float ref_signal[FRAME_SIZE];            // 参考信号
    
    while (speaker->running) {
        // 1. 读取麦克风数据
        audio_capture_read(mic_samples);
        
        // 2. 读取扬声器参考信号(用于AEC)
        audio_get_playback_ref(ref_signal);
        
        // 3. 音频前端处理
        // AEC
        for (int i = 0; i < FRAME_SIZE; i++) {
            float aec_out = aec_process_sample(&speaker->aec, 
                                                mic_samples[0][i], 
                                                ref_signal[i]);
            enhanced_audio[i] = aec_out;
        }
        
        // 波束形成(如果有DOA信息)
        float beam_out[FRAME_SIZE];
        for (int i = 0; i < FRAME_SIZE; i++) {
            float mics[6];
            for (int m = 0; m < 6; m++) {
                mics[m] = mic_samples[m][i];
            }
            beam_out[i] = beamform_process(&speaker->beamformer, mics);
        }
        
        // 4. 根据状态处理
        switch (speaker->state) {
        case STATE_IDLE:
            // 运行唤醒词检测
            if (kws_process_frame(&speaker->kws, enhanced_audio)) {
                printf("唤醒词检测到!\n");
                speaker->state = STATE_LISTENING;
                led_set_mode(&speaker->led, LED_MODE_LISTENING);
                vad_reset(&speaker->vad);
                play_wakeup_sound();
            }
            break;
            
        case STATE_LISTENING:
            // VAD检测,录制用户语音
            if (vad_process_frame(&speaker->vad, enhanced_audio)) {
                printf("语音结束,开始处理\n");
                speaker->state = STATE_PROCESSING;
                led_set_mode(&speaker->led, LED_MODE_PROCESSING);
                
                // 发送到云端
                cloud_upload_audio(&speaker->cloud, 
                                   speaker->vad.record_buffer,
                                   speaker->vad.record_len);
            }
            break;
            
        case STATE_PROCESSING:
            // 等待云端响应(在network线程处理)
            break;
            
        case STATE_SPEAKING:
            // 播放中,继续监听打断词
            // 可选:支持"停"等打断指令
            break;
            
        default:
            break;
        }
    }
    
    return NULL;
}

/**
 * ASR结果回调
 */
void on_asr_result(const char *text)
{
    printf("ASR: %s\n", text);
    
    // 添加到对话历史
    chat_history_t *history = &g_speaker.chat_history;
    strcpy(history->messages[history->message_count].role, "user");
    strcpy(history->messages[history->message_count].content, text);
    history->message_count++;
    
    // 尝试本地NLU处理
    nlu_result_t *nlu = simple_nlu(text);
    char *response = handle_intent(nlu, text);
    
    if (response) {
        // 本地处理成功,直接TTS
        printf("本地回答: %s\n", response);
        request_cloud_tts(&g_speaker.cloud.tts_config, response, on_tts_audio);
        free(response);
    } else {
        // 需要LLM处理
        printf("发送到LLM...\n");
        // LLM请求在cloud模块中处理
    }
    
    free(nlu);
}

/**
 * LLM响应回调(流式)
 */
void on_llm_response(const char *text)
{
    printf("LLM: %s", text);
    
    // 流式TTS:可以边生成边合成播放
    // 或者等完整回答后再合成
}

/**
 * TTS音频回调
 */
void on_tts_audio(const uint8_t *data, int len)
{
    // 送入播放器
    audio_player_write(&g_speaker.player, data, len);
    
    if (g_speaker.state != STATE_SPEAKING) {
        g_speaker.state = STATE_SPEAKING;
        led_set_mode(&g_speaker.led, LED_MODE_SPEAKING);
    }
}

/**
 * 播放完成回调
 */
void on_playback_complete(void)
{
    printf("播放完成\n");
    g_speaker.state = STATE_IDLE;
    led_set_mode(&g_speaker.led, LED_MODE_IDLE);
}

/**
 * 初始化
 */
int smart_speaker_init(void)
{
    memset(&g_speaker, 0, sizeof(g_speaker));
    g_speaker.state = STATE_IDLE;
    g_speaker.running = 1;
    
    // 初始化各模块
    audio_capture_init(&g_speaker.mic_config);
    aec_init(&g_speaker.aec);
    beamformer_init(&g_speaker.beamformer, &g_speaker.mic_config);
    kws_init(&g_speaker.kws);
    vad_init(&g_speaker.vad, 16000);
    
    // 云端客户端
    g_speaker.cloud.server_url = "wss://api.example.com/voice";
    g_speaker.cloud.on_asr_result = on_asr_result;
    g_speaker.cloud.on_llm_response = on_llm_response;
    g_speaker.cloud.on_tts_audio = on_tts_audio;
    cloud_client_connect(&g_speaker.cloud);
    
    // 音频播放
    audio_player_init(&g_speaker.player);
    g_speaker.player.on_complete = on_playback_complete;
    
    // LED
    led_init(&g_speaker.led);
    led_set_mode(&g_speaker.led, LED_MODE_IDLE);
    
    // 启动线程
    pthread_create(&g_speaker.audio_thread, NULL, audio_thread_func, &g_speaker);
    
    printf("智能音箱初始化完成\n");
    return 0;
}

/**
 * 主函数
 */
int main(int argc, char *argv[])
{
    printf("===================================\n");
    printf("     智能音箱系统启动\n");
    printf("===================================\n");
    
    if (smart_speaker_init() != 0) {
        fprintf(stderr, "初始化失败\n");
        return 1;
    }
    
    // 主循环
    while (g_speaker.running) {
        // 处理按键、网络事件等
        sleep(1);
        
        // 状态监控
        printf("状态: %d, 对话轮数: %d\n", 
               g_speaker.state, 
               g_speaker.chat_history.message_count);
    }
    
    // 清理
    g_speaker.running = 0;
    pthread_join(g_speaker.audio_thread, NULL);
    
    return 0;
}

LED状态指示

c 复制代码
/**
 * LED状态指示
 * 智能音箱通常有环形LED显示状态
 */

typedef enum {
    LED_MODE_OFF,           // 关闭
    LED_MODE_IDLE,          // 待机(呼吸灯或关闭)
    LED_MODE_LISTENING,     // 监听中(蓝色渐变)
    LED_MODE_PROCESSING,    // 处理中(蓝色旋转)
    LED_MODE_SPEAKING,      // 说话中(绿色)
    LED_MODE_ERROR,         // 错误(红色)
    LED_MODE_MUTED,         // 静音(红色常亮)
    LED_MODE_VOLUME         // 音量调节
} led_mode_t;

typedef struct {
    int num_leds;           // LED数量(如12颗)
    uint8_t brightness;     // 亮度
    led_mode_t mode;
    float animation_phase;
    pthread_t anim_thread;
    volatile int running;
} led_controller_t;

/**
 * LED动画线程
 */
void* led_animation_thread(void *arg)
{
    led_controller_t *led = (led_controller_t *)arg;
    
    while (led->running) {
        switch (led->mode) {
        case LED_MODE_IDLE:
            // 呼吸灯效果
            {
                float b = (sinf(led->animation_phase) + 1) / 2;
                for (int i = 0; i < led->num_leds; i++) {
                    led_set_rgb(i, 0, 0, (int)(b * 50));  // 淡蓝色
                }
            }
            break;
            
        case LED_MODE_LISTENING:
            // 蓝色从一点扩散
            {
                for (int i = 0; i < led->num_leds; i++) {
                    float dist = fabsf(i - led->animation_phase * led->num_leds);
                    if (dist > led->num_leds / 2) {
                        dist = led->num_leds - dist;
                    }
                    int b = 255 - (int)(dist * 50);
                    if (b < 0) b = 0;
                    led_set_rgb(i, 0, 0, b);
                }
            }
            break;
            
        case LED_MODE_PROCESSING:
            // 旋转效果
            {
                int head = (int)(led->animation_phase * led->num_leds) % led->num_leds;
                for (int i = 0; i < led->num_leds; i++) {
                    int dist = (head - i + led->num_leds) % led->num_leds;
                    int b = 255 - dist * 40;
                    if (b < 0) b = 0;
                    led_set_rgb(i, 0, 0, b);
                }
            }
            break;
            
        case LED_MODE_SPEAKING:
            // 绿色常亮
            for (int i = 0; i < led->num_leds; i++) {
                led_set_rgb(i, 0, 200, 0);
            }
            break;
            
        case LED_MODE_ERROR:
            // 红色闪烁
            {
                int on = ((int)(led->animation_phase * 4)) % 2;
                for (int i = 0; i < led->num_leds; i++) {
                    led_set_rgb(i, on ? 255 : 0, 0, 0);
                }
            }
            break;
            
        default:
            break;
        }
        
        led->animation_phase += 0.05f;
        if (led->animation_phase > 1.0f) {
            led->animation_phase -= 1.0f;
        }
        
        usleep(20000);  // 50fps
    }
    
    return NULL;
}

关键性能指标

c 复制代码
/**
 * 智能音箱关键性能指标
 */

/*
┌────────────────────────────────────────────────────────────────────────────┐
│                         性能指标参考值                                      │
├────────────────────────┬─────────────────┬─────────────────────────────────┤
│        指标            │     典型值      │            说明                 │
├────────────────────────┼─────────────────┼─────────────────────────────────┤
│ 唤醒率 (Wake Rate)     │     > 95%       │ 正确唤醒次数 / 总唤醒尝试次数   │
├────────────────────────┼─────────────────┼─────────────────────────────────┤
│ 误唤醒率 (FAR)         │  < 1次/24小时   │ 非唤醒词触发的次数               │
├────────────────────────┼─────────────────┼─────────────────────────────────┤
│ 唤醒距离               │     3-5米       │ 在安静环境下的有效唤醒距离       │
├────────────────────────┼─────────────────┼─────────────────────────────────┤
│ ASR准确率              │     > 95%       │ 字错误率 (WER) < 5%             │
├────────────────────────┼─────────────────┼─────────────────────────────────┤
│ 端到端延迟             │     1-3秒       │ 从说完话到开始播放回答           │
├────────────────────────┼─────────────────┼─────────────────────────────────┤
│ KWS功耗                │     < 2mW       │ 待机状态唤醒检测功耗             │
├────────────────────────┼─────────────────┼─────────────────────────────────┤
│ 系统待机功耗           │     < 2W        │ WiFi保持连接的待机功耗           │
├────────────────────────┼─────────────────┼─────────────────────────────────┤
│ 信噪比要求             │     > 5dB       │ 能正常工作的最低信噪比           │
├────────────────────────┼─────────────────┼─────────────────────────────────┤
│ 回声消除效果           │     > 40dB      │ ERLE (Echo Return Loss Enh.)    │
└────────────────────────┴─────────────────┴─────────────────────────────────┘
*/

总结

智能音箱的核心技术链路:

模块 关键技术
麦克风阵列 多麦拾音、阵列布局设计
音频前端 AEC回声消除、波束形成、噪声抑制
唤醒检测 MFCC特征、轻量级神经网络、低功耗芯片
VAD 能量/过零率检测、端点判断
云端通信 WebSocket、Opus编码、流式传输
ASR 声学模型、语言模型、端到端模型
NLU/LLM 意图识别、槽位填充、大模型生成
TTS 文本前端、声学模型、声码器

芯片选型建议:

场景 方案
低成本 单独KWS芯片 + 低端AP
中端 带NPU的SoC一体方案
高端 独立DSP + 高性能AP

整个智能音箱的技术栈跨度很大,从模拟电路到深度学习都有涉及。本文把主要的技术点都覆盖了,代码可以作为参考框架使用。

有问题欢迎评论区交流~


参考资料:

  • 《语音信号处理》
  • Kaldi/ESPnet语音识别工具包
  • Google Speech Commands数据集
  • Alexa/小爱同学技术博客
相关推荐
Nautiluss6 天前
一起调试XVF3800麦克风阵列(三)
linux·人工智能·嵌入式硬件·音频·语音识别·dsp开发·智能音箱
SPFFC1893803305318 天前
抗干扰磁环排线 | Magnetic Ring Flat Cable - 高磁导率EMI抑制解决方案
服务器·数码相机·车载系统·机器人·音频·智能音箱·智能电视
Nautiluss23 天前
一起玩XVF3800麦克风阵列(五)
嵌入式硬件·音频·语音识别·智能音箱
cooldream20091 个月前
小智 AI 智能音箱深度体验全解析:人设、音色、记忆与多场景玩法的全面指南
人工智能·嵌入式硬件·智能音箱
IT·陈寒1 个月前
小智 AI 智能音箱 MCP 开发实战:从环境搭建到自定义语音技能完整指南
人工智能·语音识别·智能音箱
沐欣工作室_lvyiyi1 个月前
基于单片机的居家智能音箱系统(论文+源码)
stm32·单片机·嵌入式硬件·毕业设计·智能音箱
2501_923840897 个月前
618期间应该买什么?618好物分享指南
智能手机·电脑·智能音箱·智能手表·智能电视
路溪非溪8 个月前
AI系列:智能音箱技术简析
人工智能·智能音箱
Cynthia AI8 个月前
射频前端模组芯片(PA)三伍微电子GSR2337 兼容替代SKY85337, RTC7646, KCT8247HE
物联网·智能手机·智能路由器·智能音箱·射频开关芯片