def impulse(samplingRate=None, fftDegree=None): """ Generates a normalized impulse signal at time zero, with zeros to fill the time length """ # Code snippet to guarantee that generated object name is # the declared at global scope # for frame, line in traceback.walk_stack(None): for framenline in traceback.walk_stack(None): # varnames = frame.f_code.co_varnames varnames = framenline[0].f_code.co_varnames if varnames == (): break # creation_file, creation_line, creation_function, \ # creation_text = \ extracted_text = \ traceback.extract_stack(framenline[0], 1)[0] # traceback.extract_stack(frame, 1)[0] # creation_name = creation_text.split("=")[0].strip() creation_name = extracted_text[3].split("=")[0].strip() if samplingRate is None: samplingRate = default.samplingRate if fftDegree is None: fftDegree = default.fftDegree numSamples = 2**fftDegree impulseSignal = np.zeros(numSamples) impulseSignal[0] = 1.0 impulseSignal = SignalObj(signalArray=impulseSignal, domain='time', samplingRate=samplingRate, signalType='energy') impulseSignal.creation_name = creation_name return impulseSignal
def impulse(samplingRate=None, fftDegree=None): """ Generates a normalized impulse signal at time zero, with zeros to fill the time length """ # Code snippet to guarantee that generated object name is # the declared at global scope # for frame, line in traceback.walk_stack(None): for framenline in traceback.walk_stack(None): # varnames = frame.f_code.co_varnames varnames = framenline[0].f_code.co_varnames if varnames is (): break # creation_file, creation_line, creation_function, \ # creation_text = \ extracted_text = \ traceback.extract_stack(framenline[0], 1)[0] # traceback.extract_stack(frame, 1)[0] # creation_name = creation_text.split("=")[0].strip() creation_name = extracted_text[3].split("=")[0].strip() if samplingRate is None: samplingRate = default.samplingRate if fftDegree is None: fftDegree = default.fftDegree numSamples = 2**fftDegree # FIXME: I don't know why you created this way. I guess it would be better # to just create a vector of zeros and then substitute the first sample by # 1. # ========================================================================= # impulseSignal = (numSamples / samplingRate) \ # * np.ones(numSamples) + 1j * np.random.randn(numSamples) # impulseSignal = np.real(np.fft.ifft(impulseSignal)) # impulseSignal = impulseSignal / max(impulseSignal) # ========================================================================= impulseSignal = np.zeros(numSamples) impulseSignal[0] = 1.0 impulseSignal = SignalObj(signalArray=impulseSignal, domain='time', samplingRate=samplingRate, signalType='energy') impulseSignal.creation_name = creation_name return impulseSignal
def sin(Arms=0.5, freq=1000, timeLength=1, phase=2 * np.pi, samplingRate=default.samplingRate, fftDegree=None): """ Generates a sine signal with the traditional parameters plus some PyTTa options. Creation parameters: -------------------- * Arms (float) (optional): The signal's RMS amplitude. >>> Apeak = Arms*sqrt(2); * freq (float) (optional): Nothing to say; * timeLength (float) (optional): Sine timeLength in seconds; * fftDegree (int) (optional); 2**fftDegree signal's number of samples; * phase (float) (optional): Sine phase in radians; * samplingRate (int) (optional): Nothing to say; """ # Code snippet to guarantee that generated object name is # the declared at global scope # for frame, line in traceback.walk_stack(None): for framenline in traceback.walk_stack(None): # varnames = frame.f_code.co_varnames varnames = framenline[0].f_code.co_varnames if varnames == (): break # creation_file, creation_line, creation_function, \ # creation_text = \ extracted_text = \ traceback.extract_stack(framenline[0], 1)[0] # traceback.extract_stack(frame, 1)[0] # creation_name = creation_text.split("=")[0].strip() creation_name = extracted_text[3].split("=")[0].strip() if fftDegree is not None: timeLength = 2**(fftDegree) / samplingRate t = np.linspace(0, timeLength - (1 / samplingRate), int(samplingRate * timeLength)) sin = Arms * (2**(1 / 2)) * np.sin(2 * np.pi * freq * t + phase) sinSigObj = SignalObj(sin, domain='time', samplingRate=samplingRate, freqMin=default.freqMin, freqMax=default.freqMax) sinSigObj.creation_name = creation_name return sinSigObj
def random_noise(kind='white', samplingRate=None, fftDegree=None, startMargin=None, stopMargin=None, windowing='hann'): """ Generates a noise of kind White, Pink (TO DO) or Blue (TO DO), with a silence at the beginning and ending of the signal, plus a fade in to avoid abrupt speaker excursion. All noises have normalized amplitude. White noise is generated using numpy.randn between [[1];[-1]]; Pink noise is still in progress; Blue noise is still in progress; """ # Code snippet to guarantee that generated object name is # the declared at global scope # for frame, line in traceback.walk_stack(None): for framenline in traceback.walk_stack(None): # varnames = frame.f_code.co_varnames varnames = framenline[0].f_code.co_varnames if varnames == (): break # creation_file, creation_line, creation_function, \ # creation_text = \ extracted_text = \ traceback.extract_stack(framenline[0], 1)[0] # traceback.extract_stack(frame, 1)[0] # creation_name = creation_text.split("=")[0].strip() creation_name = extracted_text[3].split("=")[0].strip() # It was done like this because a function default argument is a value # assigned at import time, and PyTTa have a default object that handles # default values for all functions and all classes across all submodules. # In order to it work as expected, the values should be reassigned at # every function call to get updated default values. Otherwise, despite # how the default has it's properties values changed, it won't change # for the function calls. if samplingRate is None: samplingRate = default.samplingRate if fftDegree is None: fftDegree = default.fftDegree if startMargin is None: startMargin = default.startMargin if stopMargin is None: stopMargin = default.stopMargin # [samples] initial silence number of samples stopSamples = round(stopMargin * samplingRate) # [samples] ending silence number of samples startSamples = round(startMargin * samplingRate) # [samples] total silence number of samples marginSamples = startSamples + stopSamples # [samples] full signal number of samples numSamples = 2**fftDegree # [samples] Actual noise number of samples noiseSamples = int(numSamples - marginSamples) if kind.upper() in ['WHITE', 'FLAT']: noiseSignal = np.random.randn(noiseSamples) # elif kind.upper() == 'PINK: # TODO # noiseSignal = np.randn(Nnoise) # noiseSignal = noiseSignal/max(abs(noiseSignal)) # noiseSignal = __do_pink_filtering(noiseSignal) # elif kind.upper() == 'BLUE: # TODO # noiseSignal = np.randn(Nnoise) # noiseSignal = noiseSignal/max(abs(noiseSignal)) # noiseSignal = __do_blue_filtering(noiseSignal) noiseSignal = __do_noise_windowing(noiseSignal, noiseSamples, windowing) noiseSignal = noiseSignal / max(abs(noiseSignal)) noiseSignal = np.concatenate( (np.zeros(int(startSamples)), noiseSignal, np.zeros(int(stopSamples)))) noiseSignal = SignalObj(signalArray=noiseSignal, domain='time', freqMin=default.freqMin, freqMax=default.freqMax, samplingRate=samplingRate) noiseSignal.creation_name = creation_name return noiseSignal
def sweep(freqMin=None, freqMax=None, samplingRate=None, fftDegree=None, startMargin=None, stopMargin=None, method='logarithmic', windowing='hann'): """ Generates a chirp signal defined by the "method" input, windowed, with silence interval at the beggining and end of the signal, plus a hanning fade in and fade out. >>> x = pytta.generate.sweep() >>> x.plot_time() Return a signalObj containing a logarithmic chirp signal from 17.8 Hz to 22050 Hz, with a fade in beginning at 17.8 Hz time instant and ending at the 20 Hz time instant; plus a fade out beginning at 20000 Hz time instant and ending at 22050 Hz time instant. The fade in and the fade out are made with half hanning window. First half for the fade in and last half for the fade out. Different number of points are used for each fade, so the number of time samples during each frequency is respected. Input arguments (default), (type): ------------------------ * freqMin (20), (float) * freqMax (20), (float) * samplingRate (44100), (int) * fftDegree (18), (float) * startMargin (0.3), (float) * stopMargin (0.7), (float) * method (logarithmic'), (string) * windowing ('hann'), (string) """ # Code snippet to guarantee that generated object name is # the declared at global scope # for frame, line in traceback.walk_stack(None): for framenline in traceback.walk_stack(None): # varnames = frame.f_code.co_varnames varnames = framenline[0].f_code.co_varnames if varnames == (): break # creation_file, creation_line, creation_function, \ # creation_text = \ extracted_text = \ traceback.extract_stack(framenline[0], 1)[0] # traceback.extract_stack(frame, 1)[0] # creation_name = creation_text.split("=")[0].strip() creation_name = extracted_text[3].split("=")[0].strip() # It was done like this because a function default argument is a value # assigned at import time, and PyTTa have a default object that handles # default values for all functions and all classes across all submodules. # In order to it work as expected, the values should be reassigned at # every function call to get updated default values. Otherwise, despite # how the default has it's properties values changed, it won't change # for the function calls. if freqMin is None: freqMin = default.freqMin if freqMax is None: freqMax = default.freqMax if samplingRate is None: samplingRate = default.samplingRate if fftDegree is None: fftDegree = default.fftDegree if startMargin is None: startMargin = default.startMargin if stopMargin is None: stopMargin = default.stopMargin # frequency limits [Hz] freqLimits = { 'freqMin': freqMin / (2**(1 / 6)), 'freqMax': min(freqMax * (2**(1 / 6)), samplingRate / 2) } samplingTime = 1 / samplingRate # [s] sampling period stopSamples = stopMargin * samplingRate # [samples] initial silence number of samples startSamples = startMargin * samplingRate # [samples] ending silence number of samples marginSamples = startSamples + stopSamples # [samples] total silence number of samples numSamples = 2**fftDegree # [samples] full signal number of samples sweepSamples = numSamples - marginSamples + 1 # [samples] actual sweep number of samples if sweepSamples < samplingRate / 10: raise Exception('Too small resultant sweep. For such big margins you' + ' must increase your fftDegree.') sweepTime = sweepSamples / samplingRate # [s] sweep's time length timeVecSweep = np.arange(0, sweepTime, samplingTime) # [s] time vector if timeVecSweep.size > sweepSamples: timeVecSweep = timeVecSweep[0:int(sweepSamples)] # adjust length sweep = 0.95 * ss.chirp(timeVecSweep, freqLimits['freqMin'], sweepTime, freqLimits['freqMax'], 'logarithmic', phi=-90) # sweep, time domain sweep = __do_sweep_windowing(sweep, timeVecSweep, freqLimits, freqMin, freqMax, windowing) # fade in and fade out # add initial and ending slices timeSignal = np.concatenate( (np.zeros(int(startSamples)), sweep, np.zeros(int(stopSamples)))) if timeSignal.size != numSamples: timeSignal = timeSignal[0:int(numSamples)] # adjust length # transforms into a pytta signalObj and sets the correct name sweepSignal = SignalObj(signalArray=timeSignal, domain='time', samplingRate=samplingRate, **freqLimits) sweepSignal.creation_name = creation_name return sweepSignal
def noise(kind='white', samplingRate=None, fftDegree=None, startMargin=None, stopMargin=None, windowing='hann'): """ Generates a noise of kind White, Pink (TO DO) or Blue (TO DO), with a silence at the beginning and ending of the signal, plus a fade in to avoid abrupt speaker excursioning. All noises have normalized amplitude. White noise is generated using numpy.randn between [[1];[-1]]; # FIXME: This looks incorrect because the signal has normal # distribution, so no limits but an average and standard deviation. Pink noise is still in progress; Blue noise is still in progress; """ # Code snippet to guarantee that generated object name is # the declared at global scope # for frame, line in traceback.walk_stack(None): for framenline in traceback.walk_stack(None): # varnames = frame.f_code.co_varnames varnames = framenline[0].f_code.co_varnames if varnames is (): break # creation_file, creation_line, creation_function, \ # creation_text = \ extracted_text = \ traceback.extract_stack(framenline[0], 1)[0] # traceback.extract_stack(frame, 1)[0] # creation_name = creation_text.split("=")[0].strip() creation_name = extracted_text[3].split("=")[0].strip() if samplingRate is None: samplingRate = default.samplingRate if fftDegree is None: fftDegree = default.fftDegree if startMargin is None: startMargin = default.startMargin if stopMargin is None: stopMargin = default.stopMargin # [samples] initial silence number of samples stopSamples = round(stopMargin * samplingRate) # [samples] ending silence number of samples startSamples = round(startMargin * samplingRate) # [samples] total silence number of samples marginSamples = startSamples + stopSamples # [samples] full signal number of samples numSamples = 2**fftDegree # [samples] Actual noise number of samples noiseSamples = int(numSamples - marginSamples) if kind.upper() in ['WHITE', 'FLAT']: noiseSignal = np.random.randn(noiseSamples) # elif kind.upper() == 'PINK: # TODO # noiseSignal = np.randn(Nnoise) # noiseSignal = noiseSignal/max(abs(noiseSignal)) # noiseSignal = __do_pink_filtering(noiseSignal) # elif kind.upper() == 'BLUE: # TODO # noiseSignal = np.randn(Nnoise) # noiseSignal = noiseSignal/max(abs(noiseSignal)) # noiseSignal = __do_blue_filtering(noiseSignal) noiseSignal = __do_noise_windowing(noiseSignal, noiseSamples, windowing) noiseSignal = noiseSignal / max(abs(noiseSignal)) noiseSignal = np.concatenate( (np.zeros(int(startSamples)), noiseSignal, np.zeros(int(stopSamples)))) noiseSignal = SignalObj(signalArray=noiseSignal, domain='time', freqMin=default.freqMin, freqMax=default.freqMax, samplingRate=samplingRate) noiseSignal.creation_name = creation_name return noiseSignal
def colored_noise(color: str or int = 'white', samplingRate: int = None, fftDegree: int = None, numChannels: int = None, startMargin: float = None, stopMargin: float = None, windowing: str = 'hann'): """ Power law noise generator. Based on the algorithm in: Timmer, J. and Koenig, M.: On generating power law noise. Astron. Astrophys. 300, 707-710 (1995) Generate random noise with respect to the `(1/f)**B` rate. `f` stands for frequency and `B` is an integer power. The colors and its spectrum characteristics: * Purple | Differentiated: * +6.02 dB/octave | +20 dB/decade | B = -2; * color: 'purple', 'diff', 'differentiated'; * Blue | Azure: * +3.01 dB/octave | +10 dB/decade | B = -1; * color: 'blue', 'azure' * White | Flat: * +0.00 dB/octave | +0 dB/decade | B = 0; * color: 'white', 'flat'; * Pink | Flicker: * -3.01 dB/octave | -10 dB/decade | B = 1; * color: 'pink', 'flicker', '1/f'; * Red | Brownian: * -6.02 dB/octave | -20 dB/decade | B = 2; * color: 'red', 'brown', 'brownian'; The output signal will have `startMargin` silence at the beginning of the waveform, and `stopMargin` silence at the end. There is a fade-in between the starting silence and the noise itself that occurs during 5% of the total noise duration. @author: Chum4k3r """ # Code snippet to guarantee that generated object name is # the declared at global scope # for frame, line in traceback.walk_stack(None): for framenline in traceback.walk_stack(None): # varnames = frame.f_code.co_varnames varnames = framenline[0].f_code.co_varnames if varnames == (): break # creation_file, creation_line, creation_function, \ # creation_text = \ extracted_text = \ traceback.extract_stack(framenline[0], 1)[0] # traceback.extract_stack(frame, 1)[0] # creation_name = creation_text.split("=")[0].strip() creation_name = extracted_text[3].split("=")[0].strip() # It was done like this because a function default argument is a value # assigned at import time, and PyTTa have a default object that handles # default values for all functions and all classes across all submodules. # In order to it work as expected, the values should be reassigned at # every function call to get updated default values. Otherwise, despite # how the default has it's properties values changed, it won't change # for the function calls. if samplingRate is None: samplingRate = default.samplingRate if fftDegree is None: fftDegree = default.fftDegree if numChannels is None: numChannels = len(default.outChannel) if startMargin is None: startMargin = default.startMargin if stopMargin is None: stopMargin = default.stopMargin # [samples] initial silence number of samples stopSamples = round(stopMargin * samplingRate) # [samples] ending silence number of samples startSamples = round(startMargin * samplingRate) # [samples] total silence number of samples marginSamples = startSamples + stopSamples # [samples] full signal number of samples numSamples = 2**fftDegree # [samples] Actual noise number of samples noiseSamples = int(numSamples - marginSamples) if type(color) == int: noiseSignal = _powerlaw_noise(noiseSamples, numChannels, color, samplingRate) elif type(color) == str: if color.upper() in ['PURPLE', 'DIFF', 'DIFFERENTIATED']: noiseSignal = _powerlaw_noise(noiseSamples, numChannels, -2, samplingRate) elif color.upper() in ['BLUE', 'AZURE']: noiseSignal = _powerlaw_noise(noiseSamples, numChannels, -1, samplingRate) elif color.upper() in ['WHITE', 'FLAT']: noiseSignal = _powerlaw_noise(noiseSamples, numChannels, 0, samplingRate) elif color.upper() in ['PINK', 'FLICKER', '1/F']: noiseSignal = _powerlaw_noise(noiseSamples, numChannels, 1, samplingRate) elif color.upper() in ['RED', 'BROWN', 'BROWNIAN']: noiseSignal = _powerlaw_noise(noiseSamples, numChannels, 2, samplingRate) else: raise ValueError("Unknow noise color.") else: raise TypeError("`color` must be int or str.") noiseSignal = __do_noise_windowing(noiseSignal, noiseSamples, windowing) # noiseSignal = noiseSignal / max(abs(noiseSignal)) noiseSignal = np.concatenate((np.zeros( (int(startSamples), numChannels)), noiseSignal, np.zeros((int(stopSamples), numChannels)))) noiseSignal = SignalObj(signalArray=noiseSignal, domain='time', freqMin=default.freqMin, freqMax=default.freqMax, samplingRate=samplingRate) noiseSignal.creation_name = creation_name return noiseSignal