Simulação de séries temporais com potência e densidades espectrais cruzadas

20

Estou tendo problemas para gerar um conjunto de séries temporais coloridas estacionárias, dada sua matriz de covariância (suas densidades espectrais de potência (PSDs) e densidades espectrais de potência cruzada (CSDs)).

Eu sei que, dadas duas séries temporais yEu(t) e yJ(t) , posso estimar suas densidades espectrais de potência (PSDs) e densidades espectrais cruzadas (CSDs) usando muitas rotinas amplamente disponíveis, como psd()e csd()funções no Matlab , etc. Os PSDs e os refrigerantes compõem a matriz de covariância:

C(f)=(PEuEu(f)PEuJ(f)PJEu(f)PJJ(f)),
que é geralmente uma função da frequênciaf .

O que acontece se eu quiser fazer o inverso? Dada a matriz de covariância, como faço para gerar uma realização de yEu(t) e yJ(t) ?

Por favor inclua qualquer teoria de background ou aponte as ferramentas existentes que fazem isso (qualquer coisa em Python seria ótimo).

Minha tentativa

Abaixo está uma descrição do que tentei e dos problemas que notei. É um pouco de uma leitura longa e desculpe se ele contém termos que foram mal utilizados. Se o que está errado pode ser apontado, isso seria muito útil. Mas minha pergunta é a negrita acima.

  1. Os PSDs e CSDs podem ser escritos como o valor esperado (ou média do conjunto) dos produtos das transformadas de Fourier da série temporal. Portanto, a matriz de covariância pode ser escrita como:
    C(f)=2τY(f)Y(f),
    onde
    Y(f)=(y~Eu(f)y~J(f)).
  2. Uma matriz de covariância é uma matriz hermitiana, com valores próprios reais que são zero ou positivos. Portanto, ele pode ser decomposto em que é uma matriz diagonal cujos elementos diferentes de zero são as raízes quadradas dos autovalores de ; é a matriz cujas colunas são os autovetores ortonormais de ;
    C(f)=X(f)λ12(f)Euλ12(f)X(f),
    λ12(f)C(f)X(f)C(f)Eu é a matriz de identidade.
  3. A matriz de identidade é escrita como que e são séries de frequência não correlacionadas e complexas com média zero e variação unitária.
    Eu=z(f)z(f),
    z(f)=(zEu(f)zJ(f)),
    {zEu(f)}Eu=Eu,J
  4. Usando 3. em 2. e depois compare com 1. As transformadas de Fourier das séries temporais são:
    Y(f)=τ2z(f)λ12(f)X(f).
  5. As séries temporais podem ser obtidas usando rotinas como a transformação rápida inversa de Fourier.

Eu escrevi uma rotina em Python para fazer isso:

def get_noise_freq_domain_CovarMatrix( comatrix , df , inittime , parityN , seed='none' , N_previous_draws=0 ) :
    """                                                                                                          
    returns the noise time-series given their covariance matrix                                                  
    INPUT:                                                                                                       
    comatrix --- covariance matrix, Nts x Nts x Nf numpy array                                                   
      ( Nts = number of time-series. Nf number of positive and non-Nyquist frequencies )                     
    df --- frequency resolution
    inittime --- initial time of the noise time-series                                                           
    parityN --- is the length of the time-series 'Odd' or 'Even'                                                 
    seed --- seed for the random number generator                                                                
    N_previous_draws --- number of random number draws to discard first                                          
    OUPUT:                                                                                                       
    t --- time [s]                                                                                               
    n --- noise time-series, Nts x N numpy array                                                                 
    """
    if len( comatrix.shape ) != 3 :
       raise InputError , 'Input Covariance matrices must be a 3-D numpy array!'
    if comatrix.shape[0]  != comatrix.shape[1] :
        raise InputError , 'Covariance matrix must be square at each frequency!'

    Nts , Nf = comatrix.shape[0] , comatrix.shape[2]

    if parityN == 'Odd' :
        N = 2 * Nf + 1
    elif parityN == 'Even' :
        N = 2 * ( Nf + 1 )
    else :
        raise InputError , "parityN must be either 'Odd' or 'Even'!"
    stime = 1 / ( N*df )
    t = inittime + stime * np.arange( N )

    if seed == 'none' :
        print 'Not setting the seed for np.random.standard_normal()'
        pass
    elif seed == 'random' :
        np.random.seed( None )
    else :
        np.random.seed( int( seed ) )
    print N_previous_draws
    np.random.standard_normal( N_previous_draws ) ;

    zs = np.array( [ ( np.random.standard_normal((Nf,)) + 1j * np.random.standard_normal((Nf,)) ) / np.sqrt(2)
                 for i in range( Nts ) ] )

    ntilde_p = np.zeros( ( Nts , Nf ) , dtype=complex )
    for k in range( Nf ) :
        C = comatrix[ :,:,k ]
        if not np.allclose( C , np.conj( np.transpose( C ) ) ) :
            print "Covariance matrix NOT Hermitian! Unphysical."
        w , V = sp_linalg.eigh( C )
        for m in range( w.shape[0] ) :
            w[m] = np.real( w[m] )
            if np.abs(w[m]) / np.max(w) < 1e-10 :
                w[m] = 0
            if w[m] < 0 :
                print 'Negative eigenvalue! Simulating unpysical signal...'

        ntilde_p[ :,k ] =  np.conj( np.sqrt( N / (2*stime) ) * np.dot( V , np.dot( np.sqrt( np.diag( w ) ) , zs[ :,k ] ) ) )

    zerofill = np.zeros( ( Nts , 1 ) )
    if N % 2 == 0 :
        ntilde = np.concatenate( ( zerofill , ntilde_p , zerofill , np.conj(np.fliplr(ntilde_p)) ) , axis = 1 )
    else :
        ntilde = np.concatenate( ( zerofill , ntilde_p , np.conj(np.fliplr(ntilde_p)) ) , axis = 1 )
    n = np.real( sp.ifft( ntilde , axis = 1 ) )
    return t , n

Eu apliquei essa rotina a PSDs e CSDs, cujas expressões analíticas foram obtidas a partir da modelagem de algum detector com o qual estou trabalhando. O importante é que, em todas as frequências, eles formem uma matriz de covariância (pelo menos eles passam todas essas ifdeclarações na rotina). A matriz de covariância é 3x3. As três séries temporais foram geradas cerca de 9000 vezes, e os PSDs e CSDs estimados, calculados em média sobre todas essas realizações, são plotados abaixo com os analíticos. Enquanto as formas gerais concordam, existem características ruidosas perceptíveis em determinadas frequências nos CSDs (Fig.2). Depois de um close dos picos nos PSDs (Fig.3), notei que os PSDs são realmente subestimados, e que os recursos ruidosos nos CSDs ocorrem nas mesmas frequências que os picos nos PSDs. Eu não acho que isso seja uma coincidência e que, de alguma forma, esteja vazando poder dos PSDs para os refrigerantes. Eu esperava que as curvas se sobrepusessem, com tantas realizações dos dados.

Figura 1: P11
Figura 2: P12 Figura 2: P11 (close-up)

Eu sou casado
fonte
Bem vindo ao site. Votei esta questão, em parte, para que você não consiga postar imagens. Caso contrário, basta postar links e alguém com reputação suficiente será editado para incorporar as imagens.
cardeal
1
Você já tentou filtrar ruídos de alta frequência?
Carl

Respostas:

1

Como seus sinais são estacionários, uma abordagem simples seria usar o ruído branco como base e filtrá-lo para caber nos seus PSDs. Uma maneira de calcular esses coeficientes de filtro é usar a previsão linear .

Parece que existe uma função python para ele, tente:

from scikits.talkbox import lpc

Se desejar (usei apenas o equivalente MATLAB). Essa é uma abordagem usada no processamento de fala, em que os formantes são estimados dessa maneira.

Jonas Schwarz
fonte
Você não quer dizer aplicar o filtro ao sinal e não ao ruído branco?
Michael R. Chernick
Não, o que pretendo é aproximar um filtro em que a função de transferência se assemelhe ao PSD de um processo estacionário. Se o ruído branco, que tem a mesma potência em todas as faixas de frequência, é filtrado com elas, a saída se assemelha idealmente aos sinais originais em sua densidade espectral de potência.
Jonas Schwarz
0

Um pouco atrasado para a festa, como sempre, mas eu vejo alguma atividade recente, então eu vou com meus dois ienes.

Primeiro, não posso culpar a tentativa do OP - parece certo para mim. As discrepâncias podem ocorrer devido a problemas com amostras finitas, por exemplo, viés positivo na estimativa da potência do sinal.

No entanto, acho que existem maneiras mais simples de gerar séries temporais a partir da matriz de densidade espectral cruzada (CPSD, isto é o que o OP chamou de matriz de covariância).

Uma abordagem paramétrica é usar o CPSD para obter uma descrição auto-regressiva e, em seguida, usá-la para gerar as séries temporais. No matlab, você pode fazer isso usando as ferramentas de causalidade Granger (por exemplo , caixa de ferramentas de causalidade Multivaraite Granger, Seth, Barnett ). A caixa de ferramentas é muito fácil de usar. Como a existência do CPSD garante uma descrição autorregressiva, essa abordagem é exata. (para obter mais informações sobre o CPSD e a regressão automática, consulte "Medição da dependência linear e feedback entre várias séries temporais" de Geweke, 1982, ou muitos dos artigos da Aneil Seth + Lionel Barnett, para obter uma visão completa).

Potencialmente mais simples, é notar que o CPSD pode ser formado aplicando o fft à covariância automática (fornecendo a diagonal do CPSD, isto é, a potência dos sinais) e a covariância cruzada (fornecendo os elementos diagonais externos, ou seja, a potência cruzada). Assim, aplicando o fft inverso ao CPSD, podemos obter a autocorrelação e a covariância automática. Podemos então usá-los para gerar amostras de nossos dados.

Espero que isto ajude. Por favor, deixe todos os pedidos de informações nos comentários e tentarei abordar.

dcneuro
fonte