Search code examples
pythonaudiosignal-processing

Generate colors of noise in Python


I would like to use Python to generate different colors of noise, just like Wikipedia mentions : https://en.wikipedia.org/wiki/Colors_of_noise.

For example, White, Pink, Brownian, Blue and Violet noise. And would like to have similar spectrums just like the website.

It would be a great help if I could just adjust a few parameters to get it done. Any links or tips would be very appreciated! Thanks a lot.


Solution

  • Let's use numpy to compute the noise and matplotlib to plot the results

    import numpy as np
    import matplotlib.pyplot as plt
    
    def plot_spectrum(s):
        f = np.fft.rfftfreq(len(s))
        return plt.loglog(f, np.abs(np.fft.rfft(s)))[0]
    
    

    This is a good use case for a python decorator

    def noise_psd(N, psd = lambda f: 1):
            X_white = np.fft.rfft(np.random.randn(N));
            S = psd(np.fft.rfftfreq(N))
            # Normalize S
            S = S / np.sqrt(np.mean(S**2))
            X_shaped = X_white * S;
            return np.fft.irfft(X_shaped);
    
    def PSDGenerator(f):
        return lambda N: noise_psd(N, f)
    
    @PSDGenerator
    def white_noise(f):
        return 1;
    
    @PSDGenerator
    def blue_noise(f):
        return np.sqrt(f);
    
    @PSDGenerator
    def violet_noise(f):
        return f;
    
    @PSDGenerator
    def brownian_noise(f):
        return 1/np.where(f == 0, float('inf'), f)
    
    @PSDGenerator
    def pink_noise(f):
        return 1/np.where(f == 0, float('inf'), np.sqrt(f))
    

    The function PSDGenrator takes as input a function and returns another function that will produce a random signal with the power spectrum shaped accordingly to the given function.

    The line S = S / np.sqrt(np.mean(S**2)) makes sure that the colored noise will preserve the energy of the white noise.

    Let's test

    plt.style.use('dark_background')
    plt.figure(figsize=(12, 8), tight_layout=True)
    for G, c in zip(
            [brownian_noise, pink_noise, white_noise, blue_noise, violet_noise], 
            ['brown', 'hotpink', 'white', 'blue', 'violet']):
        plot_spectrum(G(30*50_000)).set(color=c, linewidth=3)
    plt.legend(['brownian', 'pink', 'white', 'blue', 'violet'])
    plt.suptitle("Colored Noise");
    plt.ylim([1e-3, None]);
    

    consistently_colored_noise