def plot_fr(b, a, ops, func, title): plt.figure() legend = [] for op in ops: b_p, a_p = func(b, a, op) adsp.plot_magnitude_response(b_p, a_p, worN=2 * np.logspace(1, 4, 500), fs=fs) legend.append(f'A = {op}') plt.grid() plt.xlim(20, 20000) plt.title(title) plt.legend(legend) plt.xlabel('Frequency [Hz]') plt.ylabel('Magnitude [dB]')
sweep = adsp.sweep_log (20, 22000, 1, fs) legend = [] freqs = np.logspace (1, 3.4, num=1000, base=20) for g in [0.00001, 0.04, 0.2, 1.0]: cur_sweep = np.copy (sweep) * g y = np.copy (cur_sweep) filter = NLFeedback() filter.setCoefs (b, a) filter.fb_lambda = lambda a,x : a*np.tanh (x) y = filter.process_block (y) h = adsp.normalize (adsp.sweep2ir (cur_sweep, y)) adsp.plot_magnitude_response (h, [1], worN=freqs, fs=fs) if g < 0.0001: legend.append ('Linear') else: legend.append ('Nonlinear (gain={})'.format (g)) plt.title ('Lowpass Filter with nonlinear feedback') plt.legend (legend) plt.ylim (-10) #%% [markdown] # From the above plot, it seems pretty obvious that as the gain of the input # signal increases, the resonant frequency of the filter seems to shift # as well. Vadim Zavalishin describes a similar effect that occurs when # adding nonlinear elements to the feedback paths of a ladder filter, and # he has a useful way of thinking about this phenomenon: "as audio-rate # modulation of the cutoff (frequency)"[1]. The result of this modulation
return signal.bilinear(b_s, a_s, fs=fs) def new_fr_plot(): plt.figure() plt.xlabel('Frequency [Hz]') plt.ylabel('Magnitude [dB]') plt.grid() plt.xlim(20, 20000) # Feedback gain plot new_fr_plot() legend = [] for G in [0.0, 0.25, 0.5, 0.75, 0.9]: b, a = calc_fb_coefs(10000, G) adsp.plot_magnitude_response(b, a, worN=worN, fs=fs) legend.append(f'Feedback = {G}') plt.title('Feedback Stage Response at various feedback gains') plt.legend(legend) # LFO plot new_fr_plot() legend = [] for lfo in [-1, 0, 0.5, 0.9, 1.0]: b, a = calc_fb_coefs(lfo2res(lfo), 0.5) adsp.plot_magnitude_response(b, a, worN=worN, fs=fs) legend.append(f'LFO = {lfo}') plt.title('Feedback Stage Response at various LFO values') plt.legend(legend, loc='lower left')
import numpy as np import matplotlib.pyplot as plt import audio_dspy as adsp FS = 48000 worN = np.logspace(1, 2, 500) # 12 dB/Oct filters freq = [45, 40, 35] legend = [] for fc in freq: b, a = adsp.design_HPF2(fc, 0.7071, FS) adsp.plot_magnitude_response(b, a, fs=FS, worN=worN) legend.append(f'12 dB Slope, fc={fc}') # 24 dB/Oct fitler freq = 35 sos = adsp.design_HPFN(freq, 0.7071, 4, FS) adsp.plot_magnitude_response_sos(sos, fs=FS, worN=worN) legend.append(f'24 dB Slope, fc={freq}') plt.grid(which='both') plt.ylim([-30, 3]) plt.legend(legend, loc='lower right') plt.title('DC Blockers Comparison') plt.show()
x = np.sin(2 * np.pi * np.arange(N) * freq / fs) y = NLAllpass(x, func=lambda x: 3 * x) # %% ind = 3000 plt.plot(x[:ind]) plt.plot(y[:ind]) plt.title('Sine Response for Nonlinear Allpass') plt.xlabel('Time [samples]') plt.legend(['Dry', 'Wet']) # %% worN = np.logspace(1, 3.3, num=500, base=20) adsp.plot_magnitude_response(y, [1], worN=worN, fs=fs, norm=True) plt.ylim(-100) plt.title('Nonlinear Allpass Harmonic Response') # %% [markdown] # ## Adding more nonlinearity # # One thing I noticed after playing around with these nonlinear allpass filters # for a little while, is that when increase the gain factor for the filter # coefficients, the filter started become very harsh, and exhibit a "wrapping" # effect on the input sine wave. # %% y = NLAllpass(x, func=lambda x: 15 * x) ind = 3000
def inches2meters(inches): return inches / 39.370078740157 def deg2rad(deg): return deg * np.pi / 180 tape_width = inches2meters(0.25) tape_speed = inches2meters(15) azimuth_angle = deg2rad(5) delay_dist = (tape_width / 2) * np.sin(azimuth_angle) delay_ms = 1000 * (delay_dist / tape_speed) print(delay_ms) FS = 48000 delay_samp = (delay_ms / 1000) * FS print(delay_samp) FILT_SAMP = delay_samp / 16 x = np.arange( FILT_SAMP) # np.pi * np.arange(-FILT_SAMP, FILT_SAMP) / FILT_SAMP p = 1 h = -(6.0 / FILT_SAMP**3) * x * (x - FILT_SAMP) # plt.plot(h) adsp.plot_magnitude_response(h, [1], fs=FS) plt.ylim(-60) plt.show()
lifetime = r.gauss(1.2*pred_lifetime, 0.1*pred_lifetime) if (age > lifetime): # failure return r.uniform(0.0, 1.0) * 15.0*val + 0.5*val return val * (1 - 0.025 * np.log10(age)) def design_SKLPF(R, C, R1, R2, fs, age=1, temp=300, ageRs=True, ageCs=True, failCs=True): fc = 1.0 / (2 * np.pi * getResVal(R, age if ageRs else 1, temp) * getCapVal(C, age if ageCs else 1, temp, fail=failCs)) Q = 1.0 / (2 - (getResVal(R2, age if ageRs else 1, temp) / getResVal(R1, age if ageRs else 1, temp))) return adsp.design_LPF2(fc, Q, fs) fs = 44100 b, a = design_SKLPF(4.7e-9, 33800, 1000, 1500, fs) adsp.plot_magnitude_response(b, a, fs=fs) plt.ylim(-60) plt.title('Sallen-Key LPF') # %% [markdown] # ## Resistor Aging # # As a resistor grows old, the resistance tends to # increase. For a typical thin-film resistor, the # age dependence is described by [[1]]: # # $$ # \frac{\Delta R}{R} = (1.51 \times 10^{12})\ # t^{0.61}\ e^{- 15,087 / T} # $$ #
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) procNL = FBProc() procNL.feedback_lambda = lambda x: 0.5 * adsp.soft_clipper(2 * x) y_NL = procNL.process_block(y_NL) #%% h = adsp.sweep2ir(sweep, y) h_NL = adsp.sweep2ir(sweep, y_NL) adsp.plot_magnitude_response(h, [1], fs=fs) adsp.plot_magnitude_response(h_NL, [1], fs=fs) #%% plt.plot(sweep, y_NL) #%% [markdown] # $$ # y[n] = x[n] + y[n-1] * a_1 # $$ #%% def q2damp(freq, Q, fs): alpha = np.sin(2 * np.pi * freq / fs) / (2 * Q) return np.sqrt(1 - alpha) / np.sqrt(1 + alpha)
impact_wavs = [] plt.figure() # plt.title('Waterbottle Impacts') for i in impacts: impact_wavs.append(get_impact_response(i)) plt.legend() plt.xlabel('Time [samples]') plt.ylabel('Magnitude') plt.grid() plt.savefig('Figures/Impacts_time.png') # %% worN = np.logspace(1, 3.35, base=20, num=1000) legend = [] plt.figure() # plt.title('Waterbottle Impacts Frequency Responses') for idx, wav in enumerate(impact_wavs): adsp.plot_magnitude_response(wav, [1], worN=worN, fs=48000, norm=True) legend.append(impacts[idx]['name']) # wavfile.write('Impacts/Wavs/{}.wav'.format(impacts[idx]['name']), 48000, wav) plt.legend(legend) plt.ylim(-45) plt.xlim(20, 5000) plt.grid() plt.savefig('Figures/Impacts_freq.png') plt.show() # %%