summaryrefslogtreecommitdiff
path: root/modules/signal_processing/macros/cepstrum.sci
blob: d7cb3f662e2eda84af135dfc46d31869aff69069 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
// Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
// Copyright (C) INRIA
//
// This file must be used under the terms of the CeCILL.
// This source file is licensed as described in the file COPYING, which
// you should have received as part of this distribution.  The terms
// are also available at
// http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt

function fresp = cepstrum(w,mag)
    // Uses the complex-cepstrum (Oppenheim & Schafer, Digital
    //Signal Processing, p. 501) to generate, at the frequencies
    //w, a complex frequency response fresp whose magnitude is
    //equal to magnitude data mag and whose phase corresponds
    //to a stable, minimum phase transfer function.

    if ~isreal(w) then
        error(msprintf(gettext("%s: Input argument #%d must be real.\n"),"cepstrum",1));
    end
    if ~isreal(mag) then
        error(msprintf(gettext("%s: Input argument #%d must be real.\n"),"cepstrum",2));
    end

    [w,ind]=gsort(-w);w=-w;mag=mag(ind);
    dnum=length(w);

    pw=sqrt(w(dnum)*w(1));
    if w(1)<=0 then
        error(msprintf(gettext("%s: Wrong values for input argument #%d: Elements must be positive.\n"),"cepstrum",1));
    end
    if pw<1.d-8 then
        error(msprintf(gettext("%s: Wrong values for input argument #%d: Distance between Max and Min elements must be greater than %g.\n"),..
        "cepstrum",1,1d-8));
    end
    if size(w,"*")<>size(mag,"*") then
        error(msprintf(gettext("%s: Incompatible input arguments #%d and #%d: Same numbers of elements expected.\n"),"cepstrum",1,2));
    end

    tcomes=(w.*w)/pw/pw;

    dw=acos((1-tcomes)./(1+tcomes));
    lowf=dw(1);
    highf=dw(length(dw));
    if lowf <= 0 | highf >=%pi
        error(msprintf(gettext("%s: Wrong values for input argument #%d: Elements must be positive.\n"),"cepstrum",1));
    end

    nn=ceil((log(2*%pi/min(lowf,%pi-highf)))/log(2));
    npts=2*(2^nn);hnpts =2^nn;
    if npts<4096 then npts=4096;hnpts=2048;end

    lmagin =(1/log(10))*log(mag);lindw =(%pi/hnpts)*(0:hnpts-1);
    lmag=zeros(1,hnpts);topval=length(dw);
    p=find(lindw<dw(1));lmag(p)=lmagin(1)*ones(1,length(p));
    p=find(dw(topval)<=lindw);
    lmag(p)=lmagin(topval)*ones(1,length(p));
    for i=2:topval
        p=find(lindw>=dw(i-1) & lindw<dw(i));
        wrat=lindw(p) - dw(i-1)*ones(1,length(p));
        wrat=(1/(dw(i)-dw(i-1)))*wrat;
        lmag(p)=(ones(1,length(p))-wrat)*lmagin(i-1)+wrat*lmagin(i);
    end
    linmag=exp(log(10)*lmag);

    dome=[lindw,(2*%pi)-fliplr(lindw)];
    mag=[linmag,fliplr(linmag)];

    ymag=log(mag.*mag);ycc=fft(ymag,1);nptso2=npts/2;xcc=ycc(1:nptso2);
    xcc(1)=xcc(1)/2;xhat=exp(fft(xcc,-1));domeg=dome(1:2:nptso2-1);
    xhat = xhat(1:nptso2/2);nptsslo=length(dw);nptsfst = length(domeg);

    if domeg(1)<=dw(1) & domeg(nptsfst)>=dw(nptsslo)
        fresp=zeros(1,nptsslo);
        for i=1:nptsslo
            p=min(find(domeg>=dw(i)));
            wrat=(dw(i)-domeg(p-1))/(domeg(p)-domeg(p-1));
            fresp(i)=wrat*xhat(p) + (1-wrat)*xhat(p-1);
        end
    else
        error(msprintf(gettext("%s: Wrong values for input argument #%d: Not sampled high enough.\n"),"cepstrum",1));
    end
    fresp=fresp(:);

endfunction
function m=fliplr(m)
    //utility fct.
    [p,q]=size(m);
    m=m(:,q:-1:1);
endfunction