#!/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("%.3f | " % col)
except(ValueError):
html.append("%s | " % col)
html.append("
")
html.append("
")
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')