Overview
- 背景 : 人类的听感动态范围[能承受的最大响度和能感受的最安静声音响度的范围可达100万:1(即106倍)] 达120dB。扩声系统声音重放的动态范围由于受电子设备的限制,远比人耳的动态范围小很多。最低声音的响度受系统中不相关噪声的限制,使小的声音信号淹没在噪声中而无法听到;最大声音的响度受信号削波失真,而且信号削波后产生大量谐波,损坏扬声器单元(尤其是高音扬声器)。为此,在控制信号动态范围中,音量动态平衡器得到了广泛的应用。简单地说,它是一种限制音频信号动态范围的电子装置,把安静的小信号变得更响,把高幅度的尖峰信号变得更小些,并且不产生信号削波,保护扬声器和功放免受冲击和损坏。
- 动态范围压缩特点:(1) 限制了音乐信号中极大的峰值信号,保护扬声器系统和功放系统免受损坏;(2) 可获得更大的声音增益,因为压低了信号峰值,可使节目信号中的其他幅度较小的信号得到充分的提升;(3) 使音频中的小信号不会落到调音台的噪声中去,提高了节目信号的信噪比;(4) 如果这些装置中的四个基本参数(门槛电平、压缩比、动作时间和释放时间) 调整得不适当时,会出现“泵浦声”、“呼吸声”或根本没法对信号的动态范围进行控制。
Limiting
- 不同的参数压缩的理论效果图如下
- 实际调试的效果图如下
Algorithm
-
一阶滞后滤波算法公式:S(n) = αS(n-1) + (1 - α)G;
-
压缩时间根据α的大小变化,α最小可以设置成1,这样压缩时间为0;
-
原理图示如下:
-


-
Root Mean Square R M S = 1 n x 1 2 + x 2 2 + . . . x n 2 2 RMS=\sqrt[2]{{\frac1n}{x_1^2+x_2^2+...x_n^2}} RMS=2n1x12+x22+...xn2
This caculation is used to get a mean value over a buffer of 512 frames. A frame is
defined as one float per channel of sound. That can later be used to get a smoother
compression. -
Gain X d B = 20 ⋅ log 10 ( R M S ) X_{dB} = 20 · \log_{10}(RMS) XdB=20⋅log10(RMS)
Using the RMS result, it can be converted to the logarithmic plane,it have soft knee.
X s c = { X d B X d B < ( T − W 2 ) X d B + ( 1 R − 1 ) ( X d B − T + W 2 ) 2 2 W ( T − W 2 ) ≤ X d B < ( T + W 2 ) T + X d B − T R X d B > ( T + W 2 ) X_{sc}=\left\{ \begin{array}{rcl} X_{dB} & & {X_{dB} < (T - \frac W2)}\\ X_{dB} +\frac{(\frac1R-1)(X_{dB}-T+\frac W2)^2}{2W} & & {(T - \frac W2) \leq X_{dB} < (T + \frac W2)}\\ T +\frac{X_{dB}-T}{R} & & {X_{dB} >(T + \frac W2)} \end{array} \right. Xsc=⎩⎪⎨⎪⎧XdBXdB+2W(R1−1)(XdB−T+2W)2T+RXdB−TXdB<(T−2W)(T−2W)≤XdB<(T+2W)XdB>(T+2W)
Where T T T = Threshold, R R R = Ratio and W W W = KneeWidth. This is the main part of
the equations, where the gain is computed according to the set values of T T T, R R R and
W.
g c = X s c + X d B gc = X_{sc} + X_{dB} gc=Xsc+XdBThe computed gain and the original signal is added to each other. -
Smoothing Gain
g s = { α A ⋅ g s [ n − 1 ] + ( 1 − α A ) ⋅ g c g c [ n ] < g s [ n − 1 ] α R ⋅ g s [ n − 1 ] + ( 1 − α R ) ⋅ g c g c [ n ] ≥ g s [ n − 1 ] g_s=\left\{ \begin{array}{rcl} α_A · g_s[n − 1] + (1 − α_A) · g_c & & {g_c[n] < g_s[n − 1]} \\ α_R · g_s[n − 1] + (1 − α_R) · g_c & & {g_c[n] \geq g_s[n − 1] } \end{array} \right. gs={αA⋅gs[n−1]+(1−αA)⋅gcαR⋅gs[n−1]+(1−αR)⋅gcgc[n]<gs[n−1]gc[n]≥gs[n−1]
α A = e x p ( − l o g ( 9 ) F s ⋅ T A ) α_A = exp(\frac{−log(9)}{F_s · T_A }) αA=exp(Fs⋅TA−log(9))
α R = e x p ( − l o g ( 9 ) F s ⋅ T R ) α_R = exp(\frac{−log(9)}{F_s · T_R }) αR=exp(Fs⋅TR−log(9))
Where T A T_A TA = AttackTime Period, T R T_R TR = ReleaseTime Period and F s F_s Fs = Sample
Frequency. The smoothing function is there to give a natural transition from no compression to the calculated compression. Mathworks (2017)
Program
- 程序中算法使用不含soft knee,其变形公式如下
X s c = { X d B X d B < ( T − W 2 ) T + X d B − T R X d B ≥ ( T + W 2 ) X_{sc}=\left\{ \begin{array}{rcl} X_{dB} & & {X_{dB} < (T - \frac W2)}\\ T +\frac{X_{dB}-T}{R} & & {X_{dB} \geq(T + \frac W2)} \end{array} \right. Xsc={XdBT+RXdB−TXdB<(T−2W)XdB≥(T+2W)
#if 0
void vRMSLimExec(float* input, LIM_Type* pLim)
{
int i;
volatile float aA = 0.0;
for(i = 0; i < MG_DEF_BLK_SZ; i++)
{
if(pLim->Pro.fGc <= pLim->Pro.fGs)
{
aA = pLim->Set.aA; /* compress time*/
pLim->Pro.Cnt = 0;
}
else
{
aA = 1.0; /*hold time*/
pLim->Pro.Cnt++;
if(pLim->Pro.Cnt >= pLim->Pro.HdCnt)
{
pLim->Pro.Cnt = pLim->Pro.HdCnt;
aA = pLim->Set.aR; /*release time*/
}
}
pLim->Pro.fGs = aA * pLim->Pro.fGs + (1 - aA) * pLim->Pro.fGc; /* one order lag algrithm*/
input[i] = pLim->Pro.fGs * input[i];
input[i] = pLim->Pro.fGm * input[i];
}
*pLim->reduc = (1.0 / pLim->Pro.fGs);
*pLim->reduc = ((*pLim->reduc) > 1.0) ? (*pLim->reduc) : 1.0;
}
#endif
#if 1
void vRMSLimExec(float* input, LIM_Type* pLim)
{
fGc = pLim->Pro.fGc;
fGm = pLim->Pro.fGm;
aA = pLim->Set.aA;
aR = pLim->Set.aR;
HoldTime = pLim->Pro.HdCnt;
HoldCnt = &pLim->Pro.Cnt;
RmsLimExec(input, &pLim->Pro.fGs);
*pLim->reduc = (1.0 / pLim->Pro.fGs);
*pLim->reduc = ((*pLim->reduc) > 1.0) ? (*pLim->reduc) : 1.0;
}
#endif
/**
* @brief receive RMS Limiter param
* @param
* @retval None
*/
void cmp_RMSLim_param(LIM_Type* pLim, int ChType)
{
ENV_RMS_LIMITER_T* pCfgLim = (ENV_RMS_LIMITER_T*)(pLim->CfgLim);
SetMaxMinValue_Float(&pCfgLim->fRatio, 1.2, 24.9);
SetMaxMinValue_Float(&pCfgLim->fGain, -12, 12);
SetMaxMinValue_Int(&pCfgLim->nAttackTime, 1, 10000);
SetMaxMinValue_Int(&pCfgLim->nReleaseTime, 1, 10000);
SetMaxMinValue_Int(&pCfgLim->nHoldTime, 1, 10000);
if(ChType == OUTPUT_CHANNEL)
{
pLim->HwGain = fOutGainHW;
SetMaxMinValue_Float(&pCfgLim->fThreshold, 12, 42);
}
if(ChType == INPUT_CHANNEL)
{
pLim->HwGain = fInGainHW;
SetMaxMinValue_Float(&pCfgLim->fThreshold, -24, 24);
}
pLim->Set.fVth = pCfgLim->fThreshold + pLim->HwGain;
pLim->Set.aA = (Factor / (pCfgLim->nAttackTime * pLim->Set.Fs));
pLim->Set.aA = exp(pLim->Set.aA);
pLim->Set.aR = (Factor / (pCfgLim->nReleaseTime * pLim->Set.Fs));
pLim->Set.aR = exp(pLim->Set.aR);
pLim->Set.fW = 2;
pLim->Set.fRatio = pCfgLim->fRatio;
pLim->Set.fM = pCfgLim->fGain;
pLim->Pro.HdCnt = pCfgLim->nHoldTime * pLim->Set.Fs;
}
/**
* @brief get RMS limit phase status
* @param length
* @retval None
*/
void gPhaseStatus(LIM_Type* pLim, float* pRMS)
{
pLim->Pro.fInRMSdBu = 20 * log10(*pRMS) + dBuVrefCoef;
pLim->Pro.fInRMSdBu = (pLim->Pro.fInRMSdBu > (-140)) ? pLim->Pro.fInRMSdBu : (-140);
//pLim->Pro.fSCdBu = pLim->Pro.fInRMSdBu;
#if 1
/*no soft knee*/
if(pLim->Pro.fInRMSdBu <= (pLim->Set.fVth))
{
pLim->Pro.fSCdBu = pLim->Pro.fInRMSdBu;
}
else
{
pLim->Pro.fSCdBu = ((pLim->Pro.fInRMSdBu - pLim->Set.fVth) / pLim->Set.fRatio);
pLim->Pro.fSCdBu = pLim->Set.fVth + pLim->Pro.fSCdBu;
}
#endif
#if 0
/*have soft knee*/
if(pLim->Pro.fInRMSdBu < (pLim->Set.fVth - (pLim->Set.fW / 2)))
{
pLim->Pro.fSCdBu = pLim->Pro.fInRMSdBu;
}
if((pLim->Pro.fInRMSdBu >= (pLim->Set.fVth - (pLim->Set.fW / 2))) &&
(pLim->Pro.fInRMSdBu <= (pLim->Set.fVth + (pLim->Set.fW / 2))))
{
pLim->Pro.fSCdBu = (pLim->Pro.fInRMSdBu - pLim->Set.fVth + pLim->Set.fW / 2);
pLim->Pro.fSCdBu = pLim->Pro.fSCdBu * pLim->Pro.fSCdBu * ((1 / pLim->Set.fRatio) - 1) / (2 * pLim->Set.fW) + pLim->Pro.fInRMSdBu;
}
if(pLim->Pro.fInRMSdBu > (pLim->Set.fVth + (pLim->Set.fW / 2)))
{
pLim->Pro.fSCdBu = pLim->Set.fVth + ((pLim->Pro.fInRMSdBu - pLim->Set.fVth) / pLim->Set.fRatio);
}
#endif
pLim->Pro.fGc = pLim->Pro.fSCdBu - pLim->Pro.fInRMSdBu;
pLim->Pro.fGc = gain_computer(pLim->Pro.fGc, 20); /* dBu convert to physical unit*/
pLim->Pro.fGm = gain_computer(pLim->Set.fM, 20);
}
动态范围压缩是一种保护扬声器和功放免受损害的技术,通过限制音频信号中的峰值信号并提升小信号。RMS限幅算法涉及一阶滞后滤波,通过计算RMS值来确定增益,并根据阈值、压缩比和时间参数调整。在程序实现中,算法可能不包含软膝盖特性。



&spm=1001.2101.3001.5002&articleId=95049049&d=1&t=3&u=86ca8a1549664d6db475da421f56c9db)
610

被折叠的 条评论
为什么被折叠?



