Hi - I’m trying to create uncorrelated signal streams with a shared frequency profile. These are basically a Nx1 sample of complex values with a specific frequency profile and random phases pushed through a iFFT function resulting in a real-valued random stream with the desired frequency profile. I thought I could speed this up with Dask but am not getting the results I expect.
See code sample below.
The setup, ie everything up to ifd2.compute()
, takes 10s of seconds for large values of Np. Executing the graph via compute()
takes just a few 100 milliseconds.
My question is can I do something in the setup to have it do a new random draw every time I call ifd2.compute()
(without reperforming the setup). Right now it seems like after a single setup, it pulls the same random values every time I call compute()
Thanks!
import numpy as np
import dask.array as da
import matplotlib.pyplot as plt
def fftnoise(f,ret="R",nn=None):
"""
fftnoise creates a real-valued random array with specific frequency profile.
:param f: frequency profile of return
:param retComplex: return type: _R_eal,_I_mag, _C_omplex, or _M_ag (default="R")
:param nn: optional value that causes status printing with a tag if included (default None)
:return: real valued Dask Array with length = length(f)
"""
ff = da.array(f, dtype='complex')
Np = (len(f) - 1) // 2
if not (nn is None):
print("fftnoise: Doing Random Draw {}".format(nn))
phases = da.random.random(Np) * 2 * np.pi
phases = da.cos(phases) + 1j * da.sin(phases)
ff[1:Np+1] *= phases
ff[-1:-1-Np:-1] = da.conj(ff[1:Np+1])
if not (nn is None):
print("fftnoise: Doing ifft {}".format(nn))
if ret=="R":
ifd=da.fft.ifft(ff).real
elif ret=="I":
ifd=da.fft.ifft(ff).imag
elif ret=="C":
ifd=da.fft.ifft(ff)
else:
ifd=da.absolute(da.fft.ifft(ff))
return da.rechunk(ifd,chunks=min(2**20,len(f)))
Np=2**20
## creates frequency profile with roots as low points
freqFunc=lambda x: ( x-0.2)*( x-0.1)*(x-0.3)*( x-0.4)
ff = freqFunc(np.linspace(0,2,2*Np))
##mirror to other side of pi for ifft
ff[-1:-1-Np:-1] = ff[1:Np+1]
plt.figure(figsize=(20,5))
plt.plot(ff,label="Freq profile")
plt.legend()
ifd2=fftnoise(ff)
plt.figure(figsize=(20,5))
ifd2.compute()
plt.plot(ifd2.real,label="ifd2.real")
plt.legend()
plt.figure(figsize=(20,5))
plt.specgram(ifd2)
print("done")
## each of these subsequent calls produces the same values in ifd2
#ifd2.compute()
#...
#ifd2.compute()