def setUp(self): g = adsp.delay_feedback_gain_for_t60(1, _fs_, 0.5) self.N = int(0.6 * _fs_) np.random.seed(0x2345) self.test_filt = adsp.normalize( np.random.randn(self.N) * g**np.arange(self.N)) self.lin_sys = lambda sig: signal.convolve(sig, self.test_filt) self.nonlin_sys = lambda sig: signal.convolve( adsp.soft_clipper(1.1 * sig, deg=9), self.test_filt)
plt.xlabel('Frequency [Hz]') plt.ylabel('Magnitude [dB]') plt.legend(legend) fs = 44100 b, a = filters.calcCoefsLPF2(1000, 10, fs) plotNonlinearFilterResponse(b, a, 'Nonlinear Resonant Lowpass') plt.ylim(-15) plt.grid() plt.savefig('Pics/NL-LPF.png') #%% r = 2 adsp.plot_static_curve(lambda x: np.tanh(x), gain=r) adsp.plot_static_curve(lambda x: adsp.soft_clipper(x), gain=r) adsp.plot_static_curve(lambda x: adsp.hard_clipper(x), gain=r) plt.title('Comparing Saturating Nonlinearities') plt.legend(['Tanh Clipper', 'Soft Clipper', 'Hard Clipper']) plt.xlim(-2, 2) plt.grid() plt.savefig('Pics/Sat-NLs.png') #%% from matplotlib import patches def zplane(p, z): ax = plt.subplot(111) uc = patches.Circle((0, 0),
def test_soft_clipper_block(self): self.run_block(lambda x: adsp.soft_clipper(x, 5), 10000, [0.8, 0.0, -0.8])
def test_soft_clipper(self): self.run_samples(lambda x: adsp.soft_clipper(x, 5), 10000, [0.8, 0, -0.8])
# more broadband, a bit more like white noise, without losing it's amplitude # envelope, or overall melody and harmony. # # ## Nonlinearities # # The solution to this problem can come from putting our signal through a # nonlinear function before putting it through the adaptive filter, # since the nonlinear function can generate more frequencies. # %% freq1 = 1000 freq2 = 9000 desired = np.sin(2 * np.pi * np.arange(N) * freq2 / fs) input0 = np.sin(2 * np.pi * np.arange(N) * freq1 / fs) input1 = adsp.soft_clipper(input0, deg=7) output, filt, e = adsp.LMS(input1, desired, 0.01, 128) plot_specgram(desired, 'Desired Signal') plot_specgram(input0, 'Input Signal') plot_specgram(input1, 'Input Signal after nonlinearity') plot_specgram(output, 'Output Signal') # %% [markdown] # Above we show another example of frequency shifting with our adaptive filter, # but with a saturating nonlinearity at the input of the filter. A couple of # interesting things to note here: First, the extra harmonics added by the # nonlinearity allow for a smoother frequency shift, since there is more # high frequency content to aid in the frequency shifting. Second, notice # that the output signal has an interesting harmonic structure to it as well, # with a number of both overtones and undertones. Adaptive filtering with a
plt.xlabel('Frequency [Hz]') plt.ylabel('Magnitude [dB]') plt.legend(legend) fs = 44100 b, a = filters.calcCoefsLPF2(1000, 10, fs) plotNonlinearFilterResponse(b, a, 'Nonlinear Resonant Lowpass') plt.ylim(-15) #%% import audio_dspy as adsp r = 2 adsp.plot_static_curve(lambda x: np.tanh(x), range=r) adsp.plot_static_curve(lambda x: 1.5 * adsp.soft_clipper(x), range=r) adsp.plot_static_curve(lambda x: adsp.hard_clipper(x), range=r) plt.title('Comparing Saturating Nonlinearities') plt.legend(['Tanh Clipper', 'Soft Clipper', 'Hard Clipper']) #%% from matplotlib import patches def zplane(p, z): ax = plt.subplot(111) uc = patches.Circle((0, 0), radius=1, fill=False, color='white',
self.x1 = x + self.feedback_lambda(y) return y def process_block(self, block): for n in range(len(block)): block[n] = self.process_sample(block[n]) return block #%% imp = np.zeros(64) imp[0] = 1 out = np.copy(imp) proc = FBProc() proc.feedback_lambda = lambda x: -0.8 * adsp.soft_clipper(x) out = proc.process_block(out) plt.plot(imp) plt.plot(out) #%% fs = 44100 sweep = adsp.sweep_log(20, 22000, 4, fs) y = np.copy(sweep) y_NL = np.copy(sweep) procLin = FBProc() procLin.feedback_lambda = lambda x: 0.5 * (2 * x) y = procLin.process_block(y)