news 2026/5/3 14:21:07

算法系列之 基于Linux Alsa的AVAS实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
算法系列之 基于Linux Alsa的AVAS实现

目录

1.概述

1.1 AVAS简介

1.2 AVAS出现的原因

2.实现方案

2.1 方案简介

2.2 技术要求

2.3方案架构

3. 关键代码实现

3.1 Avas_core文件

3.1.1数据结构

3.1.2 计算频率

3.2 audio_engine代码

3.2.1 引擎关键结构

3.2.2 产生波形

3.2.3 初始化引擎

3.2.4 播放线程:

3.3 主函数调用


1.概述

1.1 AVAS简介

AVAS(Acoustic Vehicle Alerting System,声学车辆警报系统)是一种用于电动汽车和混合动力汽车的声音警报系统。由于这些车辆在低速行驶时几乎没有发动机噪音,可能对行人(特别是视障人士)构成安全隐患,AVAS的作用就是在车辆低速行驶时发出可识别的声音。

1.2 AVAS出现的原因

  • 行人安全: 在低速行驶时,电动汽车几乎无声,行人难以察觉
  • 盲人辅助: 视力障碍者依赖听觉判断车辆位置和速度
  • 法规要求: 多国已立法要求电动汽车安装AVAS系统
  • 事故预防: 降低因车辆无声造成的交通事故

对于AVAS,有相应的国标,最新的是GBT 371532018 电动汽车低速提示音》, 从2024年慢慢开始变成强制性要求。

2.实现方案

2.1 方案简介

本文实现一个AVAS简单算法,算法对应相应的demo,可以在linux系统下运行,基于Linux的ALSA接口。

  • 完全符合国标: 严格遵循GBT 371532018标准
  • 两种音色: 提供未来科技、正弦波音色
  • 智能调节: 声音随车速智能变化
  • 自动验证: 内置国标合规性检查
  • 可视化分析: 完整的频谱和波形分析工具

2.2 技术要求

1)适用范围

标准适用于最高车速大于20 km/h的电动汽车,要求在车速不大于20 km/h时发出提示音。

2) 速度范围

激活速度: 车速 ≤ 20 km/h

系统响应: 车速变化时声音特性应相应变化

3) 声压级要求

| 测量位置 | 最小声压级 | 最大声压级 |

| 车辆前方2m处 | 56 dB(A) | 75 dB(A) |

| 车辆侧方2m处 | 56 dB(A) | 75 dB(A) |

4) 频率要求

总体频率范围: 160 Hz ~ 5000 Hz

主要频率成分: 至少包含2个1/3倍频程

频率分布: 应包含多个频率成分,避免单一纯音

5) 声音特性要求

  • 可识别性: 声音应易于识别为车辆声音
  • 方向性: 行人应能判断车辆方向和运动趋势
  • 连续性: 车辆行驶时应连续发声
  • 变化性: 声音特性应随车速变化

2.3方案架构

AVAS架构如下:

图1 AVAS系统架构

这里AVAS系统比较简单,包括AVAS控制器 AvasController,音频生成器AvasCore以及音频调度引擎AudioEngine。AvasController是总控,根据输入信号,生成音频后,通过音频接口发声。

以下为类图和序列图:

图2 类图

图3序列图

代码文件结构如下:

图4 代码结构

avas_core是核心算法类,audio_engine产生波形,并调用linux alsa接口完成播放

3. 关键代码实现

3.1 Avas_core文件

3.1.1数据结构

/* 常量定义 */ #define AVAS_MAX_SPEED_KMH 20.0f /* AVAS触发的最大车速 (km/h) */ #define AVAS_MIN_FREQ_HZ 315.0f /* 最小频率 (Hz) */ #define AVAS_MAX_FREQ_HZ 5000.0f /* 最大频率 (Hz) */ #define AVAS_MIN_DB 56.0f /* 最小声压级 (dB) */ #define AVAS_MAX_DB 75.0f /* 最大声压级 (dB) */ /** * @brief AVAS状态结构体 */ typedef struct { float speed_kmh; /* 当前车速 (km/h) */ float frequency_hz; /* 当前提示音频率 (Hz) */ float volume_db; /* 当前音量 (dB) */ bool is_active; /* AVAS系统是否激活 */ } avas_state_t;

3.1.2 计算频率

/** * @brief 计算提示音频率(随车速线性增加) * @param speed_kmh 车速 (km/h) * @return 频率 (Hz) */ static float calculate_frequency(float speed_kmh) { if (speed_kmh <= 0.0f) { return AVAS_MIN_FREQ_HZ; } /* 频率随车速线性增加: 0 km/h -> 315 Hz, 20 km/h -> 2000 Hz */ float freq = AVAS_MIN_FREQ_HZ + (speed_kmh / AVAS_MAX_SPEED_KMH) * (2000.0f - AVAS_MIN_FREQ_HZ); /* 限制在标准范围内 */ if (freq < AVAS_MIN_FREQ_HZ) freq = AVAS_MIN_FREQ_HZ; if (freq > AVAS_MAX_FREQ_HZ) freq = AVAS_MAX_FREQ_HZ; return freq; }

3.1.3 计算音量

** * @brief 计算音量(随车速变化) * @param speed_kmh 车速 (km/h) * @return 音量 (dB) */ static float calculate_volume(float speed_kmh) { /* 音量随速度略微增加: 0 km/h -> 60 dB, 20 km/h -> 70 dB */ float volume = 60.0f + (speed_kmh / AVAS_MAX_SPEED_KMH) * 10.0f; /* 限制在标准范围内 */ if (volume < AVAS_MIN_DB) volume = AVAS_MIN_DB; if (volume > AVAS_MAX_DB) volume = AVAS_MAX_DB; return volume; }

3.1.4 更新状态

/** * @brief 更新AVAS系统状态 */ bool avas_update(avas_state_t *state, float speed_kmh) { if (state == NULL) return false; /* 确保速度非负 */ if (speed_kmh < 0.0f) speed_kmh = 0.0f; state->speed_kmh = speed_kmh; /* GB/T 37153-2018: 车速 <= 20 km/h 时激活AVAS */ if (speed_kmh <= AVAS_MAX_SPEED_KMH) { state->is_active = true; state->frequency_hz = calculate_frequency(speed_kmh); state->volume_db = calculate_volume(speed_kmh); } else { state->is_active = false; state->frequency_hz = 0.0f; state->volume_db = 0.0f; } return state->is_active; }

3.2 audio_engine代码

3.2.1 引擎关键结构

/* 音效风格 */ typedef enum { SOUND_STYLE_SINE = 0, /* 正弦波(平滑科技感) */ SOUND_STYLE_FUTURISTIC = 1 /* 未来感(带谐波) */ } sound_style_t; /** * @brief 音频引擎状态 */ typedef struct { void *alsa_handle; /* ALSA设备句柄 */ sound_style_t style; /* 当前音效风格 */ float current_freq; /* 当前频率 */ float current_volume; /* 当前音量 */ bool is_playing; /* 是否正在播放 */ uint32_t sample_rate; /* 采样率 */ double phase; /* 波形相位 */ } audio_engine_t;

3.2.2 产生波形

/** * @brief 生成正弦波音效 */ static void generate_sine_wave(int16_t *buffer, int frames, audio_engine_t *engine) { float amplitude = db_to_amplitude(engine->current_volume); float freq = engine->current_freq; for (int i = 0; i < frames; i++) { float sample = amplitude * sinf(2.0f * M_PI * engine->phase); buffer[i] = (int16_t)(sample * 32767.0f); engine->phase += freq / SAMPLE_RATE; if (engine->phase >= 1.0) engine->phase -= 1.0; } }
/** * @brief 生成未来感音效(基础频率+谐波) */ static void generate_futuristic_sound(int16_t *buffer, int frames, audio_engine_t *engine) { float amplitude = db_to_amplitude(engine->current_volume); float freq = engine->current_freq; for (int i = 0; i < frames; i++) { /* 基础频率 */ float sample = 0.6f * sinf(2.0f * M_PI * engine->phase); /* 添加三次谐波(增加科技感) */ sample += 0.25f * sinf(2.0f * M_PI * engine->phase * 3.0f); /* 添加五次谐波(增加丰富度) */ sample += 0.15f * sinf(2.0f * M_PI * engine->phase * 5.0f); buffer[i] = (int16_t)(sample * amplitude * 32767.0f); engine->phase += freq / SAMPLE_RATE; if (engine->phase >= 1.0) engine->phase -= 1.0; } }

3.2.3 初始化引擎

/** * @brief 初始化音频引擎 */ int audio_engine_init(audio_engine_t *engine, sound_style_t style) { if (engine == NULL) return -1; memset(engine, 0, sizeof(audio_engine_t)); engine->style = style; engine->sample_rate = SAMPLE_RATE; engine->phase = 0.0; /* 打开ALSA设备 */ snd_pcm_t *pcm_handle; int err = snd_pcm_open(&pcm_handle, "default", SND_PCM_STREAM_PLAYBACK, 0); if (err < 0) { return -1; } /* 配置ALSA参数 */ snd_pcm_hw_params_t *params; snd_pcm_hw_params_alloca(&params); snd_pcm_hw_params_any(pcm_handle, params); snd_pcm_hw_params_set_access(pcm_handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); snd_pcm_hw_params_set_format(pcm_handle, params, SND_PCM_FORMAT_S16_LE); snd_pcm_hw_params_set_channels(pcm_handle, params, CHANNELS); snd_pcm_hw_params_set_rate_near(pcm_handle, params, &engine->sample_rate, 0); err = snd_pcm_hw_params(pcm_handle, params); if (err < 0) { snd_pcm_close(pcm_handle); return -1; } snd_pcm_prepare(pcm_handle); /* 启动播放线程 */ g_audio_data.pcm_handle = pcm_handle; g_audio_data.engine = engine; g_audio_data.running = true; if (pthread_create(&g_audio_data.thread, NULL, audio_playback_thread, &g_audio_data) != 0) { snd_pcm_close(pcm_handle); return -1; } engine->alsa_handle = pcm_handle; return 0; }

3.2.4 播放线程:

/** * @brief 音频播放线程 */ static void *audio_playback_thread(void *arg) { audio_thread_data_t *data = (audio_thread_data_t *)arg; int16_t buffer[BUFFER_FRAMES]; while (data->running) { if (data->engine->is_playing) { /* 根据风格生成音频 */ if (data->engine->style == SOUND_STYLE_SINE) { generate_sine_wave(buffer, BUFFER_FRAMES, style="margin-left:0px; margin-right:0px">3.3 主函数调用
int main() { ...... /* 初始化AVAS系统 */ avas_init(&avas_state); avas_update(&avas_state, current_speed); /* 初始化音频引擎 */ if (audio_engine_init(&audio, current_style) != 0) { ...... } /* 主循环 */ while (running) { /* 显示状态 */ display_status(&avas_state, current_style); /* 检查按键 */ int key = get_key(); if (key != -1) { ...... } /* 限制速度范围 */ if (current_speed < 0.0f) current_speed = 0.0f; if (current_speed > 30.0f) current_speed = 30.0f; /* 更新AVAS状态 */ avas_update(&avas_state, current_speed); } /* 根据AVAS状态控制音频 */ if (avas_state.is_active) { audio_engine_update(&audio, avas_state.frequency_hz, avas_state.volume_db); if (!audio.is_playing) { audio_engine_play(&audio, avas_state.frequency_hz, avas_state.volume_db); } } else { audio_engine_stop(&audio); } ...... } /* 清理资源 */ audio_engine_destroy(&audio); clear_screen(); printf("\n" COLOR_GREEN "感谢使用AVAS演示系统!\n" COLOR_RESET); return 0; }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 10:17:15

C#使用Aspose.Words把 word转成图片

///文件分页保存成图片 Document doc new Document("f:\\333.doc"); ImageSaveOptions iso new ImageSaveOptions(SaveFormat.Jpeg);iso.Resolution 128;//这个数据越大越好 清晰度iso.PrettyFormat true;iso.UseAntiAliasing true;///抗锯齿for (int i 0; i &…

作者头像 李华
网站建设 2026/5/1 8:18:25

【计算机毕业设计案例】基于python公寓出租管理系统基于python的租房管理系统的设计与实现(程序+文档+讲解+定制)

java毕业设计-基于springboot的(源码LW部署文档全bao远程调试代码讲解等) 博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、…

作者头像 李华
网站建设 2026/4/24 17:29:44

提示工程度量标准权威解读:W3C最新规范,架构师带你划重点

提示工程度量标准权威解读&#xff1a;W3C最新规范&#xff0c;架构师带你划重点消除提示工程黑箱&#xff0c;构建可量化、可评估的LLM应用基石第一部分&#xff1a;引言与基础摘要/引言 问题陈述&#xff1a; 大语言模型 (LLM) 应用开发中&#xff0c;“提示工程” (Prompt E…

作者头像 李华
网站建设 2026/5/3 1:29:35

从原型工具到产设研协作平台:2026年我在项目中重新认识墨刀

引言这两年我对“原型工具”这件事的看法&#xff0c;其实变了好几次。一开始&#xff0c;它就是个画线框、做交互的工具&#xff1b;后来变成评审用的&#xff1b;再后来&#xff0c;我发现自己打开它的时机&#xff0c;已经不再局限于“要画原型了”。说实话&#xff0c;我重…

作者头像 李华
网站建设 2026/5/3 11:41:02

CANN推理引擎:从云端到边缘的极致加速与部署实战

CANN组织链接&#xff1a;https://atomgit.com/cann ops-nn仓库链接&#xff1a;https://atomgit.com/cann/ops-nn 当ResNet-50推理延迟高达200ms无法满足实时医疗诊断&#xff0c;当BERT-base在边缘设备内存溢出导致服务中断——推理加速已成为AI落地的“临门一脚”。传统框架…

作者头像 李华