V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
SystemLight
V2EX  ›  程序员

音频 PCM 的数据中包含负值,但是分贝转换公式中的值要求是正值,请问这样是否存在冲突呢?

  •  
  •   SystemLight ·
    SystemLight · 2020-05-04 16:31:11 +08:00 · 4580 次点击
    这是一个创建于 1671 天前的主题,其中的信息可能已经有所发展或是发生改变。

    音频 PCM 的数据中包含负值,但是分贝转换公式中的值要求是正值,请问这样是否存在冲突呢?

    a

    我通过 python 采集到的 sample 值是包含负值的,这样的话如何将这个振幅值转成分贝值,还有 adobe Audition 中的时域波形图基准线为何是负无穷而不是 0 呢,看起来怪怪的。

    b

    29 条回复    2020-05-05 00:02:58 +08:00
    noe132
        1
    noe132  
       2020-05-04 16:38:00 +08:00
    分贝是个比值单位,要看做对比的值( 0db )是哪一个。
    振幅是负的不是取个绝对值就搞定的事么
    catror
        2
    catror  
       2020-05-04 17:05:59 +08:00 via Android
    分贝是衡量数量比例的单位,正负是不会影响比例的。另外你给出的计算公式应该是不对。
    ZZSZZSZZS
        3
    ZZSZZSZZS  
       2020-05-04 17:20:55 +08:00 via iPhone
    pcm 就是有正有负的,因为这是个正弦波就是有正有负的,跟交流电一样,所以你把负的取绝对值就好了。
    ZZSZZSZZS
        4
    ZZSZZSZZS  
       2020-05-04 17:23:17 +08:00 via iPhone
    幅度趋近于 0 的时候,db 就是趋近于负无穷啊
    Accelerant
        5
    Accelerant  
       2020-05-04 17:51:42 +08:00
    麦克风的振膜是可以两个方向运动的,0 就是静止
    msg7086
        6
    msg7086  
       2020-05-04 19:27:19 +08:00
    振幅不是震动的幅度吗?幅度不就是采样点到 0 的距离吗?你负数采样点到 0 的距离也不是负距离呀。
    SystemLight
        7
    SystemLight  
    OP
       2020-05-04 19:40:39 +08:00
    @msg7086 我的音频数据的位深是 2 字节的,我取数据时候是不是用无符号的 16 位整型去取就行了啊,我现在用的是有符号的整型,会出现负值,但是不清楚这个 2 字节的 sample 表示的大小到底是不是有符号的
    liuzhedash
        8
    liuzhedash  
       2020-05-04 19:42:20 +08:00
    首先:取绝对值是不正确的,假设声音的波形按照 x 轴为时间,y 轴为振幅显示,取绝对值等于把 y 轴负半轴的波形翻转到正半轴。
    有负值的原因:音频采集的两个主要物理量是采样频率( sample rate )和采样深度( bit depth ),采样频率代表每秒对声音进行多少次采样,采样深度代表每次采样用多少 bit 的信息描述采样结果,如果把这个结果定义为有符号数,那么就会有负值,反之定义为无符号数就不会有负值。
    公式:这个公式本身没问题,但是有限定条件:当采样深度是 16bit,且采样过来的数值定义为无符号数的时候(值域[0,65535]),可以用这个公式计算 db 数值。
    SystemLight
        9
    SystemLight  
    OP
       2020-05-04 19:42:25 +08:00
    @Accelerant 那音频数据每一个 sample 的大小是有符号的还是无符号的呢,音频数据有正负方向的说法么
    SystemLight
        10
    SystemLight  
    OP
       2020-05-04 19:45:12 +08:00
    @liuzhedash 对对对,我现在不清楚的是这个数据定义本身是有符号的还是无符号的呢,因为我自己转的时候,2 个字节么,我可以转成有符号,也可以转无符号,但是这个真实情况下是不是有符号还是无符号就不清楚了。
    autogen
        11
    autogen  
       2020-05-04 20:06:30 +08:00
    归一化*65535
    deanguqiang
        12
    deanguqiang  
       2020-05-04 20:10:55 +08:00
    @liuzhedash 你是认真的吗。。。
    几乎所有的 ADC 采样进来都是有符号数(可能会有一个 1/2dBFS 的偏置),楼主的公式是计算 dBFS,即相对满幅度的分贝值,所以按照绝对值就行了。
    deanguqiang
        13
    deanguqiang  
       2020-05-04 20:13:41 +08:00
    另外我认为楼主的公式不太对,16bit 有符号数的范围是-32768 到 32767,所以 dBFS = 20 * log10(abs(sample) / 32768)。
    liuzhedash
        14
    liuzhedash  
       2020-05-04 20:20:21 +08:00
    @deanguqiang
    我搞错了,16bit 的采样数值应该有符号的
    liuzhedash
        15
    liuzhedash  
       2020-05-04 20:32:06 +08:00
    @deanguqiang
    @SystemLight
    研究了一下,13L 的公式是正确的。
    我 8L 说的有很多问题,不要看了。

    可以参考这两个:
    https://blog.jianchihu.net/pcm-vol-control-advance.html
    https://stackoverflow.com/questions/28632721/does-16bit-integer-pcm-data-mean-its-signed-or-unsigned
    xiangyuecn
        16
    xiangyuecn  
       2020-05-04 20:39:40 +08:00
    pcm=[1,-2,3,-4.....]
    计算这个 pcm 的分贝的一种方法:取出 pcm 里面的最大值,可以不管负数(或者用绝对值),然后用这个最大值来计算有多少分贝。

    so,取最大值不可能会出现负数,最多为 0
    jagger2048
        17
    jagger2048  
       2020-05-04 20:45:24 +08:00
    1. 首先 lz 的公式中 20*log_10 ( x ) 其实就是 10 * log_10(x^2),有平方的情况下正负无所谓
    2. 其次 一般 16 bits 的 PCM 都是有符表示,公式中的 65536 有问题,应该是 32767
    thedrwu
        18
    thedrwu  
       2020-05-04 20:51:41 +08:00 via Android
    计算采样单位宽度的电功率,除以参考功率,做 10log,不管数值正负,功率肯定是正的。但是楼主说的不是这个。

    如果楼主指的是人耳听到的 dB,每个频率的标准线不一样,先傅立叶拆成频谱再做除法或者减法。

    基准线负无穷是因为 log0=负无穷。
    msg7086
        19
    msg7086  
       2020-05-04 20:53:53 +08:00
    采样都是有符号的。
    SystemLight
        20
    SystemLight  
    OP
       2020-05-04 21:03:58 +08:00
    @jagger2048 实际上公式是 10 * log_10((sample/32767)^2) 对吧
    SystemLight
        21
    SystemLight  
    OP
       2020-05-04 21:07:30 +08:00
    @thedrwu 基准线是因为采样的数值为 0 时,得到的分贝是负无穷,而基准线两边就是分别代表采样的振幅值的正负换算过来的分贝值是吧。
    SystemLight
        22
    SystemLight  
    OP
       2020-05-04 21:16:17 +08:00
    @liuzhedash 诶,有点糊涂了,第一个文章里面提到:如果将声音采样大小增加一倍到 16bit,产生的动态范围则为 96 分贝,计算公式如下:
    dB = 20 * log(65536)

    他在 16 位的 sample width 用的不就是 65536 么
    thedrwu
        23
    thedrwu  
       2020-05-04 21:41:33 +08:00 via Android
    @SystemLight #21
    你想清楚你的目的是什么。分贝本身只是一个功率比例的 log 。

    #22
    和带不带符号无关,多一个 bit 你能测的信号范围变成了原来的 2 倍(=6dB )。(符号位也使范围增两倍,只不过人为地解释成了符号)
    SystemLight
        24
    SystemLight  
    OP
       2020-05-04 22:00:45 +08:00
    @thedrwu 感觉好像是离目标越来越远了,哈哈,我其实呢想实现这个图片效果,https://www.buzzsprout.com/player/wave/10,看这个最高的高度是 60,我的想法就是把分贝固定到 0 到 60 分贝这个范围,然后对整个音频的帧均匀抽样出 200 个片段,然后根据这个片段中每个的振幅值算出对应的分贝大小,决定每个小块的大小,这样的思路是否合理正确呢,求指点。
    ssdde
        25
    ssdde  
       2020-05-04 22:57:38 +08:00
    知乎也能做图床?稳吗?
    thedrwu
        26
    thedrwu  
       2020-05-04 23:17:13 +08:00 via Android
    @SystemLight
    链接里只有个窄窄的小图。
    忽略人耳感官的基准曲线和 masking 之类的机制,听到的音量和振幅大致是对数关系的。
    如果画图不需要精确的数值,坐标可以比较随意。

    稍微比例正确地画那张窄窄的小图,可以计算每个小区间的平均功率(或绝对值平均,如果时间均匀,反正开对数之后只差个 2 ),取了对数再缩放到 60 的区间,比如把最大的对数功率定为 60,小于某数字(听力的阈值)的砍成 0 。
    thedrwu
        27
    thedrwu  
       2020-05-04 23:21:33 +08:00 via Android
    @SystemLight
    再简单点,算个平均 most significant bit 的位数,不需要真正的取对数。
    xcstream
        28
    xcstream  
       2020-05-04 23:33:22 +08:00
    分贝 为什么不能是负的
    SystemLight
        29
    SystemLight  
    OP
       2020-05-05 00:02:58 +08:00
    @thedrwu 好的,感谢指教
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   966 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 20:15 · PVG 04:15 · LAX 12:15 · JFK 15:15
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.