2019년 7월 13일 토요일

음성인식 메모(kaldi) 4 - gmm training

「原作者へ」

連絡先を存じ上げませんでしたので、不本意ながら無断で翻訳しました。 
正式に翻訳を許可されたいです。 
gogyzzz@gmail.comでご連絡ください。

아래 포스트의 번역입니다.

http://work-in-progress.hatenablog.com/entry/2018/03/21/111613


kaldi의 모델 학습과정을 따라가보자.

모델을 업데이트하기 위해서는 'gmmbin/gmm-est' 커맨드를 사용한다.

Do Maximum Likelihood re-estimation of GMM-based acoustic model
Usage:  gmm-est [options] <model-in> <stats-in> <model-out>
e.g.: gmm-est 1.mdl 1.acc 2.mdl

학습 시의 input은 다음이 필요하다.

  • 업데이트 전의 모델
  • 통계량(statistics)

statistics의 생성에는 「gmmbin/gmm-acc-stats-ali」 커맨드를 사용한다.

Usage:  gmm-acc-stats-ali [options] <model-in> <feature-rspecifier> <alignments-rspecifier> <stats-out>
e.g.: gmm-acc-stats-ali 1.mdl scp:train.scp ark:1.ali 1.acc

input으로는 다음이 필요하다.

  • 초기모델
  • 특징량 파일
  • 균등 분할된 alignment

균등 분할된 alignment의 생성은 「bin/align‐equal‐compiled」 커맨드를 사용한다.

Write an equally spaced alignment (for getting training started)
Usage:  align-equal-compiled <graphs-rspecifier> <features-rspecifier> <alignments-wspecifier>
e.g.:  align-equal-compiled 1.fsts scp:train.scp ark:equal.ali

여기서 input으로 학습용 그래프(FST)가 필요하다.

그래프 생성 시에는 「bin/compile-train-graphs」 커맨드를 사용한다.

Creates training graphs (without transition-probabilities, by default)
Usage:   compile-train-graphs [options] <tree-in> <model-in> <lexicon-fst-in> <transcriptions-rspecifier> <graphs-wspecifier>
e.g.:  compile-train-graphs tree 1.mdl lex.fst 'ark:sym2int.pl -f 2- words.txt text|' ark:graphs.fsts

학습용 그래프 생성에 필요한 input

  • tree
  • 초기모델
  • 그래프(Lexicon FST)
  • text(int형식)

text(int형식)

utterance_id_001 2

(참고)text(symbol형식)

utterance_id_001 MOSIMOSI

모델 토폴로지(non-silence phone)

<TopologyEntry> 
<ForPhones> 
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 
</ForPhones> 
<State> 0 <PdfClass> 0 <Transition> 0 0.75 <Transition> 1 0.25 </State> 
<State> 1 <PdfClass> 1 <Transition> 1 0.75 <Transition> 2 0.25 </State> 
<State> 2 <PdfClass> 2 <Transition> 2 0.75 <Transition> 3 0.25 </State> 
<State> 3 </State> 
</TopologyEntry> 

모델 토폴로지(silence phone)

<Forphones> 
1 2 3 4 5 6 7 8 9 10 
</ForPhones> 
<State> 0 <PdfClass> 0 <Transition> 0 0.25 <Transition> 1 0.25 <Transition> 2 0.25 <Transition> 3 0.25 </State> 
<State> 1 <PdfClass> 1 <Transition> 1 0.25 <Transition> 2 0.25 <Transition> 3 0.25 <Transition> 4 0.25 </State> 
<State> 2 <PdfClass> 2 <Transition> 1 0.25 <Transition> 2 0.25 <Transition> 3 0.25 <Transition> 4 0.25 </State> 
<State> 3 <PdfClass> 3 <Transition> 1 0.25 <Transition> 2 0.25 <Transition> 3 0.25 <Transition> 4 0.25 </State> 
<State> 4 <PdfClass> 4 <Transition> 4 0.75 <Transition> 5 0.25 </State> 
<State> 5 </State> 
</TopologyEntry> 

모델을 FST로 변환한 것

그림의 녹색 글자가 나타내는 것

"_"전 : phone(음소)

"_"후 : phone(음소)내부의 위치

_B begin   
_I internal
_E end

FST(Context to word)

이 2개를 합성한다.

    VectorFst<StdArc> *H;
    VectorFst<StdArc> &ctx2word_fst;
    VectorFst<StdArc> trans2word_fst;
    TableCompose(*H, ctx2word_fst, &trans2word_fst);

FST(합성 후)

파란색은 weight

이어서, determinize, miniminize, self-loop 추가를 진행하고, 학습용 FST를 생성한다.

음성인식 메모(kaldi) 3 - WFST

「原作者へ」

連絡先を存じ上げませんでしたので、不本意ながら無断で翻訳しました。 
正式に翻訳を許可されたいです。 
gogyzzz@gmail.comでご連絡ください。

아래 포스트의 번역입니다.

http://work-in-progress.hatenablog.com/entry/2018/03/04/110331


kaldi에서 사용하는 모델을 작성해보자.

대상은 '모시모시'라는 발화.

대강의 흐름은 아래 4개의 모델을 사용해 합성된다고 보면 된다.

합성은 아래 순서에 따라 수행

L ○ G
↓
C ○ (L ○ G)
↓
H ○ (C ○ (L ○ G))

일단 Grammar. 이것은 ARPA 파일로부터 생성된다.

src/lmbin/arpa2fst \
--disambig-symbol=#0 \
--read-symbol-table=data/lang/words.txt \
2gram.arpa \
G.fst

G.fst

이어서 Grammar와 Lexicon의 합성(compose)

Lexicon은 음향 모델을 만드는 과정에서 준비된 것을 사용한다.

data/lang/L_disambig.fst

determinize와 minimize도 함께 실행된다.

src/fstbin/fsttablecompose \
data/lang/L_disambig.fst \
G.fst | \
src/fstbin/fstdeterminizestar --use-log=true | \
src/fstbin/fstminimizeencoded | \
src/fstbin/fstpushspecial | \
fstarcsort --sort_type=ilabel > LG.fst

LG.fst

이어서, Context와의 합성.

Context는 음소를 기반으로 생성된다.

src/fstbin/fstmakecontextfst \
--read-disambig-syms=disambig_phones.list \
phones_exclude_disambig_phones.list 29 ilabels.sym | \
fstarcsort --sort_type=olabel > C.fst

phonesexcludedisambig_phones.list

<eps> 0
sil 1
sil_B 2
sil_E 3
sil_I 4
sil_S 5
spn 6
spn_B 7
spn_E 8
spn_I 9
spn_S 10
I_B 11
I_E 12
I_I 13
I_S 14
M_B 15
M_E 16
M_I 17
M_S 18
O_B 19
O_E 20
O_I 21
O_S 22
S_B 23
S_E 24
S_I 25
S_S 26

disambig_phones.list

27
28

(참고) data/lang/phones.txt(disambig만 발췌)

#0 27
#1 28

「make-ilabel-transducer」、「fstdeterminizestar」、「fstminimizeencoded」 커맨드를 실행하여

「CLG2.fst」 을 만든다.

CLG2.fst

이어서, HMM과의 합성

(「Ha.fst」는 「make-h-transducer」 커맨드로 생성)

src/fstbin/fsttablecompose Ha.fst \
CLG2.fst | \
src/fstbin/fstdeterminizestar --use-log=true | \
src/fstbin/fstrmsymbols disambig_tstate.list | \
src/fstbin/fstrmepslocal | \
src/fstbin/fstminimizeencoded > HCLGa.fst

이어서, self-loops를 추가하여, 「HCLG.fst」를 생성한다.

HCLG.fst

음성인식 메모(kaldi) 2 - decode

「原作者へ」

連絡先を存じ上げませんでしたので、不本意ながら無断で翻訳しました。 
正式に翻訳を許可されたいです。 
gogyzzz@gmail.comでご連絡ください。

아래 포스트의 번역입니다.

http://work-in-progress.hatenablog.com/entry/2018/02/25/150137


kaldi로 실제 음성을 인식시켜보자.

아래 사이트를 참고하였다.

https://www.eleanorchodroff.com/tutorial/kaldi/kaldi-training.html

https://qiita.com/GushiSnow/items/01296c16f0d9d823ae55#_reference-726cb1a057905797dcf3

사용한 것은 '모시모시'라는 발화 데이터 (프레임 수는 198)

실행 커맨드

src/gmmbin/gmm-decode-faster \
--word-symbol-table=data/lang/words.txt \
exp/tri/final.mdl \
HCLG.fst \
ark:mfcc/mosi1.ark \
ark,t:-

전달한 파라미터는 아래 설명에 따라

Decode features using GMM-based model.
Usage:  gmm-decode-faster [options] model-in fst-in features-rspecifier words-wspecifier 
Options:
--word-symbol-table         : Symbol table for words [for debug output] 

exp/tri/final.mdl은 triphone 모델로, HCLG.fst가 그래프.

mfcc/mosi1.ark가 feature 파일로, 결과는 텍스트 형식으로 표준출력에 쓰여지게 되어 있다.

Symbol table for words(data/lang/words.txt)

<eps> 0
!SIL 1
<UNK> 2
MOSIMOSI 3
#0 4
<s> 5
</s> 6

결과

utterance_id_001 3 
utterance_id_001 MOSIMOSI 
LOG (gmm-decode-faster[5.3.106~1389-9e2d8]:main():gmm-decode-faster.cc:196) Log-like per frame for utterance utterance_id_001 is -9.01644 over 198 frames.
LOG (gmm-decode-faster[5.3.106~1389-9e2d8]:main():gmm-decode-faster.cc:209) Time taken [excluding initialization] 0.031435s: real-time factor assuming 100 frames/sec is 0.0158763
LOG (gmm-decode-faster[5.3.106~1389-9e2d8]:main():gmm-decode-faster.cc:212) Done 1 utterances, failed for 0
LOG (gmm-decode-faster[5.3.106~1389-9e2d8]:main():gmm-decode-faster.cc:214) Overall log-likelihood per frame is -9.01644 over 198 frames.

"MOSIMOSI"로 인식된다.

음성인식 메모(kaldi) 1 - feature

「原作者へ」

連絡先を存じ上げませんでしたので、不本意ながら無断で翻訳しました。 
正式に翻訳を許可されたいです。 
gogyzzz@gmail.comでご連絡ください。

아래 포스트의 번역입니다.

http://work-in-progress.hatenablog.com/entry/2018/02/17/102153


음성인식 toolkit 'kaldi'를 시험해본다.

오늘은 feature extraction.

음성 데이터는 HTK의 HCopy로 해봤을때와 같은것을 사용.

kaldi 공식 사이트에는 다음과 같은 설명이 있는데, (HTK와는) 완전히 같게 되진 않는 것 같다.

With the option –htk-compat=true, and setting parameters correctly, it is possible to get very close to HTK features.

일단은, wav 데이터를 아카이브 형식으로 저장.

featbin/extract-segments scp:mosi1.scp mosi1_segment ark:mosi1.ark

이어서, MFCC feature를 추출.

featbin/compute-mfcc-feats --config=mfcc.conf ark:mosi1.ark ark:mosi1.mfcc

default option (MFCC)

(feat/feature-mfcc.h、struct MfccOptions)

struct MfccOptions {
    FrameExtractionOptions frame_opts;
    MelBanksOptions mel_opts;
    ( 중간생략)
    MfccOptions()
        : mel_opts(23),
          // defaults the #mel-banks to 23 for the MFCC computations.
          // this seems to be common for 16khz-sampled data,
          // but for 8khz-sampled data, 15 may be better.
          num_ceps(13),
          use_energy(true),
          energy_floor(0.0),
          raw_energy(true),
          cepstral_lifter(22.0),
          htk_compat(false) {}

    void Register(OptionsItf *opts) {
    (중간생략)
    }
};

defalut option (프레임 처리)

(feat/feature-window.h、struct FrameExtractionOptions)

struct FrameExtractionOptions {
    (생략)
    FrameExtractionOptions()
        : samp_freq(16000),
          frame_shift_ms(10.0),
          frame_length_ms(25.0),
          dither(1.0),
          preemph_coeff(0.97),
          remove_dc_offset(true),
          window_type("povey"),
          round_to_power_of_two(true),
          blackman_coeff(0.42),
          snip_edges(true),
          allow_downsample(false) { }

    void Register(OptionsItf *opts) {
    (생략)
    }
   (생략)
};

default option (filter bank)

(feat/mel-computations.h、struct MelBanksOptions)

struct MelBanksOptions {
    (생략)
    explicit MelBanksOptions(int num_bins = 25)
        : num_bins(num_bins),
          low_freq(20),
          high_freq(0),
          vtln_low(100),
          vtln_high(-500),
          debug_mel(false),
          htk_mode(false) {}

    void Register(OptionsItf *opts) {
    (생략)
    }
};

파라미터로 넘겨주는 config

--low-freq=0                 # for 16kHz sampled speech.
--high-freq=8000         # for 16kHz sampled speech.
--window-type=hamming    # 
--use-energy=false       
--num-mel-bins=24
--htk-compat=true       # try to make it compatible with HTK
--dither=0
--remove_dc_offset=false

kaldi에서는 디폴트로 dithering을 수행하지만, 이것을 OFF로 하면 FFT 결과까진 HTK와 같아 보인다.

그 후 filterbank처리에 대해서는 HTK에선 amplitude (power spectrum의 square root)를 사용하는 것에 비해, kaldi에선 power spectrum을 사용하기 때문에 값이 달라진다. binning이나 저주파에 대한 weighting 차이는 확인하지 않았지만, filterbank의 결과를 보면 차이가 있다.

filterbank 처리 후(24차원)

(참고) HCopy의 filterbank처리 후

그 후 cepstral 영역으로 옮겨 weighting하는 것은 HTK와 같다.

feature 파일을 텍스트화 하자.

copy-feats ark:mosi1.mfcc ark,t:mosi1_mfcc.txt

mosi1_mfcc.txt(1번째 프레임)

6.969446 -4.22486 2.13142 -5.186962 -8.526231 14.15422 6.308793 -9.442774 1.588198 -27.89196 -2.058122 -11.62059 89.52384 

HTK의 결과와 비교해보자. kaldi 쪽이 특징을 더 잘 식별할 수 있게 되어 있다.

--htk-compat=true 옵션은 출력 행렬의 순서를 HTK와 같도록 해준다.

If true, put energy or C0 last and use a factor of sqrt(2) on C0.

HTK 출력 행렬의 순서

1차원, 2차원, 3차원, ... 12차원, 0차원

kaldi 출력 행렬의 순서

0차원, 1차원, 2차원, 3차원, ... 12차원

2019년 5월 27일 월요일

190527 DSP 노트

spectral leakage, coherent gain, scalloping loss

https://www.recordingblogs.com/wiki/coherent-gain

  • spectral leakage: DFT시 디지털 샘플로 정확히 원하는 주파수의 magnitude를 나타낼 수 없어(정해진 정수개의 sample로 커버가 안되는 주기 같은 것) 인접 주파수에 spectrum이 번져 보이는 현상. window를 적용하면 spectral leakage가 완화됨. 주기 신호처럼 만들어주기 때문인 듯.
  • coherent gain: window의 평균 값(전부 더한 값/윈도우 길이)
  • window마다 coherent gain이 다르기 때문에, window를 적용하면 loss가 생기는 것을 방지 하기 위해 coherent gain으로 나눠주어 normalization을 수행함.

http://web.mit.edu/xiphmont/Public/windows.pdf https://www.recordingblogs.com/wiki/scalloping-loss https://ipfs.io/ipfs/QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco/wiki/Windowfunction.html http://www.bores.com/courses/advanced/windows/10pl.htm

  • spectrum에서 가장 큰 낙폭을 보이는 주파수 bin의 중간 지점의 attenuation. 가장 큰 낙폭은 주로 main lobe에서 일어나므로 main lobe에 대해 주로 말하는 것 같다. 그런데 이 bin 사이의 지점에 대한 정보는 어떻게 얻는다는 것인지 이해가 안된다… 그냥 이 개념이 이해가 안됨.

zero-padding

https://dsp-nbsphinx.readthedocs.io/en/nbsphinx-experiment/spectralanalysisdeterministicsignals/zeropadding.html#Relation-between-Discrete-Fourier-Transformations-with-and-without-Zero-Padding

  • 예를 들자면 [1, 2, 3, 1] 이라는 time domain 신호를 [1, 2, 3, 1, 0, 0, 0, 0]으로 만들어 원래 N(=4) 포인트 DFT를 하던 것을 M(=8) DFT 하겠다는 것
  • 이렇게 하면 주파수 상에서 기존 N 포인트로 보던 스펙트럼을 M 포인트로 볼 수 있으니 더 해상도가 높아진 것과 같은 효과가 남
  • 하지만 해상도가 높아졌다고 해서 없던 정보를 더 얻은 것은 아니고 단순히 보기 좋아지게끔 interpolation 된 것. 용도에 따라 쓸모 있는 기법이 될 수 있음.

zero-padding과 DFT, DTFT의 관계

  • DTFT는 time domain 상에서만 discrete이기 때문에 freq. domain에서는 연속임. 이를 컴퓨터 상에터 보려면 주파수 도메인 bin을 아주 촘촘히 만들어 연속인 것 같이 나타내면 됨.
  • 이 (이산이지만 아주 촘촘한) DTFT를 사실은 DFT로부터 만들어낼 수도 있는데, DFT에 IDFT하고 다시 DTFT 하면 됨(…). 이 과정 (https://dsp-nbsphinx.readthedocs.io/en/nbsphinx-experiment/spectralanalysisdeterministicsignals/zeropadding.html#Interpolation-of-the-Discrete-Fourier-Transformation) 에서 수식에 sum이 두 번 들어가는데 periodic sinc function을 쓰면 sum을 한번만 쓴 형태로 바꾸어 나타낼 수 있음. (https://en.wikipedia.org/wiki/Dirichlet_kernel의 Variant of identity 부분을 볼 것) 처음엔 psinc로 나타낸 수식에 무슨 물리적 의미가 있나 한참 고민했는데, 정신건강에 좋게 그냥 수학적 간결함을 위한 것이라 합리화하였음. (리마인드: sinc function은 사각 윈도우의 주파수 응답. 샘플링 시 impulse 형태가 아니라 어쩔 수 없는 구형파 형태로 필터링 되기 때문에 sampling function이라고도 함 https://www.quora.com/What-is-the-difference-between-sinc-and-sampling-function )
  • 위에서 말했듯이 디지털 상에서 억지로 나타낸 DTFT는 사실 원래 신호를 매우 해상도가 높은 M 포인트 DFT로 표현한 것 뿐임. 즉 수식상에서는 DFT -> IDFT -> DTFT로 만드는 과정이어도 DTFT의 표현을 디지털 상에서 M 포인트 DFT로 나타냈다는 것은 N포인트 DFT를 M 포인트 DFT로 interpolation 한 것이고, 이는 원래 time-domain 신호에 zero-padding 을 통해 M 포인트 DFT로 만든 것과 동일한 결과를 가져옴.

PSD, periodogram, welch technique

https://dsp-nbsphinx.readthedocs.io/en/nbsphinx-experiment/spectralestimationrandom_signals/periodogram.html

  • PSD는 신호 고유의 값이라 알 수 있는 값이 아니라 추정할 수 있는 값임. 스펙트럼을 제곱하여 얻는 periodogram은 우리가 'PSD'로 알고 있는 것으로, PSD estimator라 보면 됨.
  • periodogram을 주파수에 대해 평균내면 '주파수에 대해 평균 낸' PSD와 매우 비슷한 값이 됨.

https://dsp-nbsphinx.readthedocs.io/en/nbsphinx-experiment/spectralestimationrandomsignals/welchmethod.html

  • periodogram으로 PSD를 보면 너무 들쑥날쑥하므로 STFT처럼 windowing을 하여 윈도우마다 periodogram을 계산한 후 window들에 대해 평균을 냄 (결과는 주파수마다 나오는 형태가 됨). 이것이 welch technique(method) 인데 window가 꼭 overlap이 있을 필요는 없음(overlap이 하나도 없이 window끼리 붙어 있는 형태로도 함)
  • 이렇게 하면 주파수 별 PSD를 잘 반영함

causal filter, convolution, correlation

  • f(t + tau)와 f(t - tau)를 이해하자. plot 상에 수평이동 되는 방향이 마치 반대로 움직이는 것 같아 헷갈리기 쉽다.
  • f(t + tau): t에서 tau만큼 미래에 있는 값. f(t - tau)는 그 반대…
  • 왜 수평이동은 반대 방향으로 되는 것처럼 보이는가? f(t + tau)의 plot은 '미래(t + tau)'에 있는 값을 현재 t 에 나타낸 것이기 때문에 값이 과거로 움직인 것처럼 보이는 것. 반대의 경우는 '과거'의 값을 '현재'로 가지고 오기 때문에 미래 방향으로 움직인 것처럼 보이는 것…

https://en.wikipedia.org/wiki/Convolution

  • 예전부터 convolution의 수식이 너무 이해가 안됐다. 이해라기 보단 그냥 저런 공식을 쓰는 연산이다라고 생각해왔음.
  • f*g(t) = intergral(f(tau)g(t - tau), dtau) 인데 여기서 f를 필터, g를 신호라고 생각하자. 이 경우 f(tau)는 필터의 tau번째 미래 tap이 되는 것이고, g(t - tau)는 t 시점으로부터 tau만큼 과거에 있는 신호값이다. 즉 f(tau)g(t - tau)란 t보다 tau 이전의 신호를 미리 f에 집어 넣었고, 그게 t 시점에 f(tau)를 만나 곱해진 값이 되는 것이다. tau 만큼 과거에 밀어넣은 값이므로, tau만큼 미래의 tap과 만나는 것은 너무나 당연하다. 이렇게 t 시점에서 tau이전부터 하나씩 넣어온 신호들을 전부 t 시점에 모아서 더하는 것이 convolution이다.

https://en.wikipedia.org/wiki/Causal_filter

  • causal filter의 경우 미래의 값에 대해 필터링을 할 순 없으므로 현재시점부터 과거로만 가게 tau를 배치한다.

https://en.wikipedia.org/wiki/Cross-correlation

  • cross-correlation의 경우 f, g 둘 다를 '신호'라 간주하는 것이 이해하기 쉽다. 애초 계산하는 이유도 두 신호의 similarity를 측정하기 위함.
  • cross-correlation의 수식의 f, g 중 왜 한쪽은 conjugate인가? complex space에 있는 각 신호의 유사도는 스칼라여야 하기 때문에, complex 값끼리 inner product를 해야 하기 때문에 한쪽을 conjugate로 만들어 곱하고 있는 것
  • cross-correlation 수식은 f(t)g(t + tau)와 f(t - tau)g(t)가 있는데, 내 눈엔 f(t - tau)g(t) 가 더 이해하기 쉽다. g를 기준 신호로 보고, f에 tau만큼 딜레이를 줘가면서 유사도를 계산한 것이라 생각하면 편하기 때문.

wiener filter

https://dsp-nbsphinx.readthedocs.io/en/nbsphinx-experiment/randomsignalsLTIsystems/wienerfilter.html

  • MSE로부터 wiener filter 최적해를 유도하는 과정은 건너뛰도록 하자…
  • source의 distortion을 만드는 시스템 필터 G가 있을 경우, wiener filter H(w) = PSDsx(w) / PSDxx(w) 이다. 주파수 마다 계산된 다는 점에 주의.
  • 이 PSDsx, PSDxx는 어떻게 아는가? 안다고 가정한다…

https://dsp-nbsphinx.readthedocs.io/en/nbsphinx-experiment/randomsignalsLTIsystems/wienerfilter.html#Transfer-Function-of-the-Wiener-Filter

  • 여기 예제 코드에서 'shift for causal'이라는 주석으로 되어 있는 부분이 있는데, 이 간단한 개념을 이해하지 못해 시간 다 썼다.
H = H * np.exp(-1j*2*np.pi/len(H)*np.arange(len(H))*(len(H)//2)) # shift for causal
  • '-1'는 반대 방향, 2pinp.arange(len(H))/len(H)는 frequency(w에 해당), (len(H)//2)는 shift해줄 길이(n또는 t)를 의미한다.

  • 이는 코드상으로 구현한 wiener filter를 그대로 적용(convolution)할 경우 결과 신호가 반 파장 phase shift 되어 나타나는 것을 보정한다. non-causal filter라면 현재 위치 앞/뒤 신호를 한번에 보고 적용하면 되지만, causal system에 구현해야 할 경우 대칭의 중심이 필터 길이의 반에 위치하게 된다. causal filter로 얻은 결과 신호는 원 신호에 대해 lagging 되어 나타나기 때문에, 원 신호와 비교를 하기 위해서는 lagging 된 만큼 땡겨줄 필요가 있다.

  • wiener deconvolution filter라 부르는 것은 wiener filter와 전혀 다를바가 없이 보이는데… 왜 이름을 다시 지었을까? 용도를 강조한 것 같다.

  • wiener deconvolution filter는 wiener filter와 달리 PSDss, PSDnn, SNR, distortion filter G에 대한 수식으로 표현된다. 여기서 G(w)=1인 경우 H(w) = SNR(w) / (SNR(w) + 1) = PSDss / (PSDss + PSD_nn)이 된다.

  • 가산 잡음이 없다면 H(w) = 1 / G(w) 가 된다.