/*************************************
    Maximum Entropy Method
**************************************/

#include <stdio.h>
#include <math.h>

main(argc, argv)
int argc;
char *argv[];
{
    FILE *fp;
    FILE *fp2;
    char buff[256];
    char string[256];

    int nd;         /* Tv */
    int ns;         /* XyNg_ */
    int isw;        
    int mmax;           /* (ő)f */
    int minm;
    float dt;           /* TvԊu */
    float pmm;
    float wnmin;        /* ŏg */
    float wnmax;        /* őg */
    float wnint;
    static float x[1024];   /* f[^ */
    static float rfpe[1024];
    static float spectrum[1024];
    
    int i;

    memset( x, 0, sizeof(float)*1024 );
    memset( rfpe, 0, sizeof(float)*1024 );
    memset( spectrum, 0, sizeof(float)*1024 );
    
    nd = 128;
    dt = 0.1;

    isw=2;
    while(isw == 2)
    {
        printf("f@WXE@@A^G}XJ ( Y / N ) ");
        gets(string);
        if( strcmp(string,"y") == 0 || strcmp(string,"Y") == 0 )
        {
            isw=1;
            printf("\nf@WXE = ");
        }
        else if( strcmp(string,"n") == 0 || strcmp(string,"N") == 0 )
        {
            isw=0;
            printf("\nTC_C@f@WXE = ");
        }
        else
            isw=2;
    }

    gets(string);
    mmax = atoi( string );
    
    fp = fopen( argv[1], "rt" );
    for( i = 1; i <= nd; i++)
    {
        fgets( buff, 256, fp );
        x[i] = atof( buff );
    }
    fclose( fp );

    
    ns=nd;
    wnmin = 0.0;
    wnmax = (float)nd;
    
    ar_model(isw,mmax,&minm,nd,&pmm,rfpe,x);
    
    printf("\nTCVE@VEnXE = ");
    gets(string);
    wnmin = atof( string );
    printf("\nTC_C@VEnXE = ");
    gets(string);
    wnmax = atof( string );
    printf("\nXyNg@eXE = ");
    gets(string);
    ns = atoi( string );
    
    wnint=(wnmax-wnmin)/(float)ns;
    power_spectrum(wnmin,wnmax,wnint,dt,rfpe,spectrum,&pmm,&minm);

    fp2 = fopen( argv[2], "wt" );
    for(i=1; i<=ns; ++i)
    {
        fprintf( fp2, "%f\n",spectrum[i]);
    }
    fclose( fp2 );
}
    
    
    
ar_model(isw,mmax,minm,nd,pmm,rfpe,x)
int isw,mmax,*minm,nd;
float *pmm,rfpe[1024],x[1024];
{
    int i,m;
    static float y[1024],fpe[1024],r[1024],rr[1024];
    float sum, sumn, sumd;
    float av,z,pm,fpemin,rm;
    
    sum=0.0;
    for(i=1; i<=nd; ++i)
    {
        sum+=x[i];
    }
    
    av=sum/(float)nd;
    
    sum=0.0;
    for(i=1; i<=nd; ++i)
    {
        z=x[i]-av;
        x[i]=z;
        y[i-1]=z;
        sum+=z*z;
    }
    
    pm=sum/(float)nd;
    fpemin=(float)(nd+1)/(float)(nd-1)*pm;
    fpe[0]=fpemin;

    for(m=1; m<=mmax; ++m)
    {
        sumn=0.0;
        sumd=0.0;
        for(i=1; i<=nd-m; ++i)
        {
            sumn+=x[i]*y[i];
            sumd+=x[i]*x[i]+y[i]*y[i];
        }
        
        rm=-2.0*sumn/sumd;
        r[m]=rm;
        pm*=(1.0-rm*rm);

        if(m!=1)
        {
            for(i=1; i<=m-1; ++i)
            {
                r[i]=rr[i]+rm*rr[m-i];
            }
        }
        
        for(i=1; i<=m; ++i)
        {
            rr[i]=r[i];
        }
        
        for(i=1; i<=nd-m-1; ++i)
        {
            x[i]+=(rm*y[i]);
            y[i]=y[i+1]+rm*x[i+1];
        }
        
        if(isw==0)
        {
            fpe_check(m,minm,fpe,rfpe,r,nd,pm,&fpemin,pmm);
        }
    }

    if(isw==1)
    {       
        *minm=mmax;
        *pmm=pm;
    
        for(i=1; i<=mmax; ++i)
        {
            rfpe[i]=r[i];
        }
    }
}



fpe_check(m,minm,fpe,rfpe,r,nd,pm,fpemin,pmm)
int m,*minm;
float fpe[1024],rfpe[1024],r[1024];
int nd;
float pm,*fpemin,*pmm;
{       
    int i;
    
    fpe[m]=(float)(nd+m+1)/(float)(nd-m-1)*pm;
    if(fpe[m]<= *fpemin)
    {
        *fpemin=fpe[m];
        *minm=m;
        *pmm=pm;
        
        for(i=1; i<=m; ++i)
        {
            rfpe[i]=r[i];
        }
    }
}



power_spectrum(wnmin,wnmax,wnint,dt,rfpe,spectrum,pmm,minm)
float wnmin,wnmax,wnint;
float dt,*pmm;
float rfpe[1024],spectrum[1024];
int *minm;
{
    int i,j;
    float ci,f,sum1,sum2;
    
    ci=2.0*3.14159*dt;
    i=0;
    
    for(f=wnmin; f<=wnmax; f+=wnint)
    {
        sum1=1.0;
        sum2=0.0;
        
        for(j=1; j<=*minm; ++j)
        {
            sum1+=rfpe[j]*cos(ci*f*j);
            sum2+=rfpe[j]*sin(ci*f*j);
        }
        
        spectrum[i]=(*pmm)*dt/(sum1*sum1+sum2*sum2);
        ++i;
    }
}

