Package: csdTools
CsdToolsA collection of scripts wrapping scipy.signal.csd for some extra features. Most notably, wrapped csd allows one to get uncertainties when using averaging. Future goal is to have more averaging in higher frequency bins of spectrum while getting same number of points per decade.UsageSeeexample notebookfor a working example.Using welch with mean and get standard deviationImport csd and welch from csdTools.fromcsdToolsimportcsd,welchimportnumpyasnpimportmatplotlib.pyplotaspltfrommatplotlibimportcmfromscipyimportsignalimportmatplotlib.tickerasmticker#******************************************************************************#Setting RC Parameters for figure size and fontsizesimportmatplotlib.pylabaspylabparams={'figure.figsize':(16,12),'xtick.labelsize':'xx-large','ytick.labelsize':'xx-large','text.usetex':False,'lines.linewidth':4,'font.family':'serif','font.serif':'Georgia','font.size':20,'xtick.direction':'in','ytick.direction':'in','xtick.labelsize':'medium','ytick.labelsize':'medium','axes.labelsize':'medium','axes.titlesize':'medium','axes.grid.axis':'both','axes.grid.which':'both','axes.grid':True,'grid.color':'xkcd:cement','grid.alpha':0.3,'lines.markersize':12,'lines.linewidth':2.0,'legend.borderpad':0.2,'legend.fancybox':True,'legend.fontsize':'medium','legend.framealpha':0.8,'legend.handletextpad':0.5,'legend.labelspacing':0.33,'legend.loc':'best','savefig.dpi':140,'savefig.bbox':'tight','pdf.compression':9}pylab.rcParams.update(params)#******************************************************************************Generate two signal with some common features.fs=10e3N=1e6amp=20freq=1234.0noise_power=0.001*fs/2time=np.arange(N)/fsb,a=signal.butter(2,0.25,'low')x=np.random.normal(scale=np.sqrt(noise_power),size=time.shape)y=signal.lfilter(b,a,x)x+=amp*np.sin(2*np.pi*freq*time)y+=np.random.normal(scale=0.1*np.sqrt(noise_power),size=time.shape)Use welch function as you would for scipy.signal.welch but give extra argumentgetUnc=Truef,Pxx,Pxxstd=welch(x,fs,nperseg=1000,average='mean',getUnc=True)fig,ax=plt.subplots(1,1,figsize=[16,12])ax.plot(f,np.abs(Pxx))ax.fill_between(f,np.abs(Pxx)-np.abs(Pxxstd),np.abs(Pxx)+np.abs(Pxxstd),alpha=0.3)ax.set_yscale('log')ax.set_xscale('log')ax.set_ylim(1e-6,2e1)ax.set_xlabel('frequency [Hz]',fontsize='xx-large')ax.set_ylabel('PSD [$V^2$/Hz]',fontsize='xx-large')ax.set_title('Using welch with mean averaging and 1-sigma region.',fontsize='xx-large')Using welch with median and get upper-lower boundsf,Pxx,Pxxlb,Pxxub=welch(x,fs,nperseg=2000,average='median',getUnc=True)fig,ax=plt.subplots(1,1,figsize=[16,12])ax.plot(f,np.abs(Pxx))ax.fill_between(f,np.abs(Pxxlb),np.abs(Pxxub),alpha=0.3)ax.set_yscale('log')ax.set_xscale('log')ax.set_ylim(1e-4,1e2)ax.set_xlabel('frequency [Hz]',fontsize='xx-large')ax.set_ylabel('PSD [$V^2$/Hz]',fontsize='xx-large')ax.set_title('Using welch with median averaging\nand 15.865% - 84.135%percentile region.',fontsize='xx-large')Using csd with 'no' averaging and getting full distribution of dataSometimes, we are interested in how the PSD or CSD of data is distributed across time.
We can have no averaging by settingaverage='no'in csd or welch function and would
get PSD or CSD with extra dimension containing individual PSD or CSD of each time window
considered.f,Pxy=csd(x,y,fs,nperseg=1024,average='no',getUnc=True)This can be histogrammed at each frequency bin to understand the underlying
distribution.Pxyhist=np.zeros((Pxy.shape[0],70))bins=np.arange(-7,0.1,0.1)forrowinrange(Pxy.shape[0]):Pxyhist[row,:],be=np.histogram(np.log10(np.abs(Pxy[row,:])),bins=bins)Pxyhist[row,:]/=np.linalg.norm(Pxyhist[row,:])Plotting a pcolormesh.fig=plt.figure(figsize=[16,12])ax=fig.gca()X,Y=np.meshgrid(f,be[:-1])Z=np.transpose(Pxyhist)pcm=ax.pcolormesh(X,Y,Z,cmap=cm.Greys,shading='auto')ax.set_ylim(-5,-0.8)ticks_loc=ax.get_yticks().tolist()ax.yaxis.set_major_locator(mticker.FixedLocator(ticks_loc))ax.set_yticklabels([r'$10^{'+str(int(ele))+'}$'foreleinticks_loc],fontsize='xx-large')ax.set_xlabel('frequency [Hz]',fontsize='xx-large')ax.set_ylabel('CSD [$V^2$/Hz]',fontsize='xx-large')ax.set_title('Absolute value of CSD distribution (no averaging)',fontsize='xx-large')# Add a color bar which maps values to colors.fig.colorbar(pcm,shrink=0.5,aspect=5,label='Normalized Histrogram')