sawg: handle clipping interpolator

* give 1 bit headroom to interpolator to handle overshoot
* fix Config limiter widths (NFC)
* move clipper to behind the HBF to correctly shield DUC

This leaves a factor of two headroom for the sum of the following
effects:

  * HBF overshoot (~15 % of the step)
  * A1/A2 DDS sum

While this is technically not sufficient and can still lead to
overflows, it is unlikely that one would trigger those. It would require
doing large amplitude A1, large amplitude A2 and additionally doing
amplitude/phase jumps that would overshoot the HBF. No sane person would
try that, right?

closes #743
This commit is contained in:
Robert Jördens 2017-06-12 20:27:55 +02:00
parent 1fb3995ffc
commit 9a8a7b9102
1 changed files with 15 additions and 7 deletions

View File

@ -129,11 +129,11 @@ class Channel(Module, SatAddMixin):
self.submodules.a1 = a1 = SplineParallelDDS(widths, orders) self.submodules.a1 = a1 = SplineParallelDDS(widths, orders)
self.submodules.a2 = a2 = SplineParallelDDS(widths, orders) self.submodules.a2 = a2 = SplineParallelDDS(widths, orders)
coeff = halfgen4_cascade(parallelism, width=.4, order=8) coeff = halfgen4_cascade(parallelism, width=.4, order=8)
hbf = [ParallelHBFUpsampler(coeff, width=width) for i in range(2)] hbf = [ParallelHBFUpsampler(coeff, width=width + 1) for i in range(2)]
self.submodules.b = b = SplineParallelDUC( self.submodules.b = b = SplineParallelDUC(
widths._replace(a=len(hbf[0].o[0]), f=widths.f - width), orders, widths._replace(a=len(hbf[0].o[0]), f=widths.f - width), orders,
parallelism=parallelism) parallelism=parallelism)
cfg = Config(widths.a) cfg = Config(width)
u = Spline(width=widths.a, order=orders.a) u = Spline(width=widths.a, order=orders.a)
self.submodules += cfg, u, hbf self.submodules += cfg, u, hbf
self.u = u.tri(widths.t) self.u = u.tri(widths.t)
@ -170,17 +170,25 @@ class Channel(Module, SatAddMixin):
b.ce.eq(cfg.ce), b.ce.eq(cfg.ce),
u.o.ack.eq(cfg.ce), u.o.ack.eq(cfg.ce),
Cat(a1.clr, a2.clr, b.clr).eq(cfg.clr), Cat(a1.clr, a2.clr, b.clr).eq(cfg.clr),
Cat(b.xi).eq(Cat(hbf[0].o)),
Cat(b.yi).eq(Cat(hbf[1].o)),
] ]
self.sync += [ for i in range(parallelism):
hbf[0].i.eq(self.sat_add(a1.xo[0], a2.xo[0], self.comb += [
b.xi[i].eq(self.sat_add(hbf[0].o[i],
limits=cfg.limits[0], limits=cfg.limits[0],
clipped=cfg.clipped[0])), clipped=cfg.clipped[0])),
hbf[1].i.eq(self.sat_add(a1.yo[0], a2.yo[0], b.yi[i].eq(self.sat_add(hbf[1].o[i],
limits=cfg.limits[1], limits=cfg.limits[1],
clipped=cfg.clipped[1])), clipped=cfg.clipped[1])),
] ]
for i in range(2):
for j in range(2):
# correct pre-DUC limiter by cordic gain
v = cfg.limits[i][j].reset.value
cfg.limits[i][j].reset.value = int(v / b.gain)
self.comb += [
hbf[0].i.eq(a1.xo[0] + a2.xo[0]),
hbf[1].i.eq(a1.yo[0] + a2.yo[0])
]
# wire up outputs and q_{i,o} exchange # wire up outputs and q_{i,o} exchange
for o, x, y in zip(self.o, b.xo, self.y_in): for o, x, y in zip(self.o, b.xo, self.y_in):
self.sync += [ self.sync += [