\begin{equation*}
\newcommand\mean[2]{\mathrm{E}_{#1} \left[ #2 \right]}
\end{equation*}
予稿を書きつつある。同時にWavenetを読み込んでいる。 今日思ったのが、プリエンファシスもAuxiliary FunctionでL1スパース解が求まるのでは無いかという想像。式導出だけでもできるはずなのでやってみたい。
試しにやってみたが、圧縮率が微妙に悪化。 値の範囲チェックが悪かったりするかもしれない。コメントアウトで残すには汚いので、ここに供養する。
/* 残差絶対値平均を最小にするプリエンファシスフィルタ係数計算 */
static void LINNEPreemphasisFilter_CalculateLADCoefficient(
struct LINNEPreemphasisFilter *preem, const int32_t *buffer, uint32_t num_samples)
{
uint32_t smpl, itr;
double coef = 0.0f, obj_value, prev_obj_value;
double curr;
LINNE_ASSERT(preem != NULL);
LINNE_ASSERT(buffer != NULL);
#if 0
/* 係数の初期値を最小二乗法で定める */
{
double corr[2];
curr = buffer[0] * pow(2.0f, -15);
for (smpl = 0; smpl < num_samples - 1; smpl++) {
const double succ = buffer[smpl + 1] * pow(2.0f, -15);
corr[0] += curr * curr;
corr[1] += curr * succ;
curr = succ;
}
coef = (corr[0] <= 1e-6) ? 0.0f : (corr[1] / corr[0]);
}
#endif
prev_obj_value = FLT_MAX;
for (itr = 0; itr < 10; itr++) {
double r01 = 0.0f, r11 = 0.0f;
/* 方程式の係数計算 */
obj_value = 0.0f;
curr = buffer[0] * pow(2.0f, -15);
for (smpl = 0; smpl < num_samples - 1; smpl++) {
double res, inv_res;
const double succ = buffer[smpl + 1] * pow(2.0f, -15);
/* 絶対値残差計算 */
res = fabs(succ - coef * curr);
obj_value += res;
/* 正則化 */
res = (res < 1e-8) ? 1e-8 : res;
inv_res = 1.0f / res;
r01 += succ * curr * inv_res;
r11 += curr * curr * inv_res;
curr = succ;
}
obj_value /= (num_samples - 1);
/* 係数更新 */
coef = r01 / r11;
/* 収束判定 */
if (fabs(prev_obj_value - obj_value) < 1e-8) {
break;
}
}
/* 係数設定 */
preem->coef = (int32_t)LINNEUtility_Round(coef * pow(2.0f, LINNE_PREEMPHASIS_COEF_SHIFT));
/* 丸め込み */
if (preem->coef >= (1 << (LINNE_PREEMPHASIS_COEF_SHIFT - 1))) {
preem->coef = (1 << (LINNE_PREEMPHASIS_COEF_SHIFT - 1)) - 1;
}
}
1次線形近似で平均絶対値が最小になるのは中央値 \(m\) のときだから、 \(\mean{}{|x_{n} - a x_{n-1}|}\) を最小化すると考えると、 \(a x_{n-1} = m\) となるようにすれば良くて、
\begin{equation*}
\mean{}{|x_{n} - a x_{n-1}|}
\end{equation*}
(うまく行かなそうなのでやめた。備忘としては残す。)