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 e , 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:
O que acontece se eu quiser fazer o inverso? Dada a matriz de covariância, como faço para gerar uma realização de e ?
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.
- 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:
onde
- 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 ;é a matriz de identidade.
- 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.
- Usando 3. em 2. e depois compare com 1. As transformadas de Fourier das séries temporais são:
- 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 if
declaraçõ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.
fonte
Respostas:
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:
Se desejar (usei apenas o equivalente MATLAB). Essa é uma abordagem usada no processamento de fala, em que os formantes são estimados dessa maneira.
fonte
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.
fonte