In [1]:
%pylab inline

Populating the interactive namespace from numpy and matplotlib

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 = ["<table>"]
for row in self:
html.append("<tr>")
for col in row:
try:
float(col)
html.append("<td>%.3f</td>" % col)
except(ValueError):
html.append("<td><b>%s</b></td>" % col)
html.append("</tr>")
html.append("</table>")
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)

Out[5]:

## 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 ""

Synthesized a 5-order NTF, with roots:

Zeros:			 Poles:
(1.000000, 0.000000j)	(0.806557, -0.119823j)
(0.998603, 0.052839j)	(0.806557, 0.119823j)
(0.998603, -0.052839j)	(0.898071, -0.219819j)
(0.996045, 0.088847j)	(0.898071, 0.219819j)
(0.996045, -0.088847j)	(0.777767, 0.000000j)

The NTF transfer function has the following expression:

(z^2 - 1.992z + 0.9999) (z^2 - 1.997z + 1) (z - 1)
-------------------------------------------------------------
(z^2 - 1.613z + 0.665) (z^2 - 1.796z + 0.8549) (z - 0.7778)



### 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

ABCD Matrix:
[[ 1.     0.     0.     0.     0.     0.001 -0.001]
[ 1.     1.    -0.003  0.     0.     0.    -0.008]
[ 1.     1.     0.997  0.     0.     0.    -0.063]
[ 0.     0.     1.     1.    -0.008  0.    -0.244]
[ 0.     0.     1.     1.     0.992  0.    -0.802]
[ 0.     0.     0.     0.     1.     0.     0.   ]]

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

Doing dynamic range scaling...  Done.
Maximum input magnitude: 0.583

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

Verifying dynamic range scaling...  Done.
Maximum DC input level: 0.583

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
}
}


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,
t

Out[19]:
 Coefficients DAC feedback Resonator feedback Feed-in Interstage a(n) g(n) b(n) c(n) #1 0.100 0.015 0.100 0.137 #2 0.170 0.018 0.000 0.191 #3 0.213 0.000 0.384 #4 0.363 0.000 0.440 #5 0.365 0.000 1.530 #6 0.000

### System version information¶

In [20]:
#%install_ext http://raw.github.com/jrjohansson/version_information/master/version_information.py