#!/usr/bin/env python # coding: utf-8 # In[1]: get_ipython().run_line_magic('pylab', 'inline') # In[2]: from __future__ import division from IPython.core.display import Image from deltasigma import * import warnings warnings.filterwarnings('ignore') # In[3]: # skip this, this is just to display nice tables. from itertools import izip_longest class Table(list): def _repr_html_(self): html = [""] for row in self: html.append("") for col in row: try: float(col) html.append("" % col) except(ValueError): html.append("" % col) html.append("") html.append("
%.3f%s
") return ''.join(html) # In[4]: np.set_printoptions(suppress=True, precision=3) # Delta Sigma modulator synthesis - example #1 # ============================================ # # Demonstration of the synthesis of an example delta sigma modulator, as done in the `MATLAB Delta Sigma Toolbox`, employing its Python port `deltasigma`. # # * The **Noise Transfer Function** (NTF) is synthesized for a **5th-order**, **low-pass** modulator, having the following characteristics: # # * A relatively low Over Sampling Ratio (OSR), equal to `32`, # * A 1-bit quantizer. # * Maximum NTF gain equal to 1.5. # # * For this example modulator, we select to implement the CRFB topology -- see below, for order being odd -- with a single feed-in, ie $b_n = 0\ \forall n > 1$ . # In[5]: Image(url='http://python-deltasigma.readthedocs.org/en/latest/_images/CRFB.png', retina=True) # ## Set up the parameters # In[6]: order = 5 osr = 32 nlev = 2 f0 = 0. Hinf = 1.5 form = 'CRFB' # ## Synthesize the NTF # In[7]: ntf = synthesizeNTF(order, osr, 2, Hinf, f0) # Optimized zero placement print "Synthesized a %d-order NTF, with roots:\n" % order print " Zeros:\t\t\t Poles:" for z, p in zip(ntf[0], ntf[1]): print "(%f, %fj)\t(%f, %fj)" % (np.real(z), np.imag(z), np.real(p), np.imag(p)) print "" print "The NTF transfer function has the following expression:\n" print pretty_lti(ntf) print "" # ### Graphical inspection of the synthesized singularities # In[8]: plotPZ(ntf, showlist=True) # ## Realize the NTF with the CRFB topology and create the ABCD representation # In[9]: a, g, b, c = realizeNTF(ntf, form) b = np.hstack(( # Use a single feed-in for the input np.atleast_1d(b[0]), np.zeros((b.shape[0] - 1, )) )) ABCD = stuffABCD(a, g, b, c, form) print "ABCD Matrix:" print ABCD # In[10]: DocumentNTF(ABCD, osr, f0) f = gcf() f.set_size_inches((15, 6)) # ## Typical spectral characteristics # In[11]: figure(figsize=(15,8)) PlotExampleSpectrum(ntf, M=1, osr=osr, f0=f0) # ## Signal to Noise Ratio analysis # In[12]: snr, amp = simulateSNR(ntf, osr, None, f0, nlev) # In[13]: figure(figsize=(15,8)) if nlev == 2: snr_pred, amp_pred, k0, k1, se = predictSNR(ntf, osr) plot(amp_pred, snr_pred, '-', label='predicted') hold(True) plot(amp, snr,'o-.g', label='simulated') xlabel('Input Level (dBFS)') ylabel('SQNR (dB)') peak_snr, peak_amp = peakSNR(snr, amp) msg = 'peak SQNR = %4.1fdB \n@ amp = %4.1fdB ' % (peak_snr, peak_amp) text(peak_amp-10,peak_snr,msg, horizontalalignment='right', verticalalignment='center'); msg = 'OSR = %d ' % osr text(-2, 5, msg, horizontalalignment='right'); hold(False) figureMagic([-100, 0], 10, None, [0, 100], 10, None, [12, 6], 'Time-Domain Simulations') legend(loc=2); # ## Dynamic range scaling # # Keep the integrator outputs within their working range -- to avoid waveform clipping and instabilities. # # The ABCD matrix is scaled opportunely, then the effectiveness of the dynamic range scaling is verified and the state maxima are plotted for different amplitudes. # In[14]: print 'Doing dynamic range scaling... ', ABCD0 = ABCD.copy() ABCD, umax, S = scaleABCD(ABCD0, nlev, f0) print 'Done.' print "Maximum input magnitude: %.3f" % umax # In[15]: print 'Verifying dynamic range scaling... ', u = np.linspace(0, 0.95*umax, 30) N = 1e4 N0 = 50 test_tone = np.cos(2*np.pi*f0*np.arange(N)) test_tone[:N0] = test_tone[:N0]*(0.5 - 0.5*np.cos(2*np.pi/N0*np.arange(N0))) maxima = np.zeros((order, u.shape[0])) for i in np.arange(u.shape[0]): ui = u[i] v, xn, xmax, y = simulateDSM(ui*test_tone, ABCD, nlev) maxima[:, i] = xmax[:, 0] if (xmax > 1e2).any(): print 'Warning, umax from scaleABCD was too high.' umax = ui u = u[:i] maxima = maxima[:, :i] break print 'Done.' print "Maximum DC input level: %.3f" % umax # In[16]: colors = get_cmap('jet')(np.linspace(0, 1.0, order)) hold(True) for i in range(order): plot(u,maxima[i,:], 'o-', color=colors[i], label='State %d' % (i+1)) grid(True) #text(umax/2, 0.05, 'DC input', horizontalalignment='center', verticalalignment='center') figureMagic([0, umax], None, None, [0, 1] , 0.1, 2, [12, 6], 'State Maxima') xlabel('DC input') ylabel('Maxima') legend(loc='best'); # ## Conclusions # ###Scaled coefficients # In[17]: a, g, b, c = mapABCD(ABCD, form) # In[18]: adc = { 'order':order, 'osr':osr, 'nlev':nlev, 'f0':f0, 'ntf':ntf, 'ABCD':ABCD, 'umax':umax, 'peak_snr':peak_snr, 'form':form, 'coefficients':{ 'a':a, 'g':g, 'b':b, 'c':c } } # ### Final ADC coefficients # In[19]: t = Table() ilabels = ['#1', '#2', '#3', '#4', '#5', '#6'] t.append(['Coefficients', 'DAC feedback', 'Resonator feedback', 'Feed-in', 'Interstage']) t.append(['', 'a(n)', 'g(n)', ' b(n)', ' c(n)']) [t.append(x) for x in izip_longest(ilabels, adc['coefficients']['a'].tolist(), adc['coefficients']['g'].tolist(), adc['coefficients']['b'].tolist(), adc['coefficients']['c'].tolist(), fillvalue="")] t # ### System version information # In[20]: #%install_ext http://raw.github.com/jrjohansson/version_information/master/version_information.py get_ipython().run_line_magic('load_ext', 'version_information') get_ipython().run_line_magic('reload_ext', 'version_information') get_ipython().run_line_magic('version_information', 'numpy, scipy, matplotlib, deltasigma')