Compensators#
- class ChromaticDispersionFIRCompensator(z: float, *, fs: float = 1.0, name: str = 'fir cd compensator')[source]#
Static FIR compensator of chromatic dispersion (truncated inverse impulse response, Savory).
Signal Model#
A fiber span of length \(z\) acts on the complex envelope as the all-pass dispersive filter
\[H_{\mathrm{CD}}(\omega) = e^{j \frac{\beta_2}{2} z \omega^2}\]where \(\omega\) is the angular frequency in rad/s and \(\beta_2\) the group velocity dispersion. The compensator approximates its inverse. Sampling at \(f_s\) and using the normalized pulsation \(\Omega = \omega / f_s \in [-\pi, \pi]\) (rad/sample), the target response is the quadratic-phase all-pass
\[H_c\!\left(e^{j\Omega}\right) = e^{-j \frac{\beta_2}{2} z f_s^2 \Omega^2} = e^{j K \Omega^2}, \qquad K = -\frac{\beta_2 z f_s^2}{2}\]with the dimensionless dispersion \(K > 0\). Its inverse DTFT is the Fresnel (chirped) sequence
\[h[n] = \sqrt{\frac{j}{4 \pi K}} \, e^{-j \frac{n^2}{4 K}}\]truncated to the span imposed by the maximum group delay \(2 \pi K\) of the all-pass, that is \(|n| \le \lfloor 2 \pi K \rfloor\), hence \(N = 2 \lfloor 2 \pi K \rfloor + 1\) taps. The block applies the full linear convolution
\[y[n] = \sum_{l} h[l] \, x[n - l]\]so the output is \(N - 1\) samples longer than the input and carries a group delay of \((N - 1) / 2\) samples.
Units follow the module convention: \(\beta_2 = -10^3 D \lambda^2 / (2 \pi c)\) is returned in ps^2/km by
comnumpy.optical.utils.compute_beta2()and converted internally to s^2/km (factor \(10^{-24}\)), \(z\) is in km and \(f_s\) in Hz, which makes \(K\) dimensionless.Axes: axis -1 – the convolution runs along the last axis (
scipy.signal.convolvein"full"mode); leading axes are batch, every row through the same taps.- param z:
Fiber length \(z\) in km.
- type z:
float
- param fs:
Sampling frequency \(f_s\) in Hz. Default is 1.
- type fs:
float, optional, keyword-only
- param name:
Name of the processor instance. Default is
"fir cd compensator".- type name:
str, optional, keyword-only
- h#
Filter taps \(h[n]\) for \(|n| \le \lfloor 2 \pi K \rfloor\), built in
__post_init__.- Type:
np.ndarray
- K#
Dimensionless dispersion \(K = -\beta_2 z f_s^2 / 2\).
- Type:
float
- lamb#
Class-level wavelength \(\lambda\) in nm (
WAVELENGTH).- Type:
float
- D#
Class-level dispersion coefficient \(D\) in ps/nm/km (
CD_COEFFICIENT).- Type:
float
- c#
Class-level speed of light \(c\) in m/s (
SPEED_OF_LIGHT).- Type:
float
References
S. J. Savory, “Digital filters for coherent optical receivers,” Optics Express, vol. 16, no. 2, pp. 804-817, 2008 (Eqs. 4-11).
Examples
Dispersion spreads an isolated pulse; the compensator recompresses it.
>>> from comnumpy.optical.channels import ChromaticDispersion >>> x = np.zeros(512, dtype=complex) >>> x[256] = 1.0 >>> y = ChromaticDispersion(1000.0, fs=20e9)(x) >>> comp = ChromaticDispersionFIRCompensator(1000.0, fs=20e9) >>> delay = (len(comp.h) - 1) // 2 >>> x_hat = comp(y)[delay:delay + 512] >>> print(len(comp.h), round(float(np.abs(y).max()), 3), round(float(np.abs(x_hat[256])), 3)) 55 0.162 0.975
- class ChromaticDispersionLSFIRCompensator(z: float, N: int, *, fs: float = 1.0, w_vect: List[float] = <factory>, name: str = 'optimal')[source]#
Least-squares FIR compensator of chromatic dispersion (optimal design over a frequency band).
Signal Model#
The target response is the same quadratic-phase all-pass as in
ChromaticDispersionFIRCompensator, i.e. the inverse of the dispersive response \(e^{j (\beta_2 / 2) z \omega^2}\) of the fiber, written with the normalized pulsation \(\Omega = \omega / f_s \in [-\pi, \pi]\):\[H_c\!\left(e^{j\Omega}\right) = e^{j K \Omega^2}, \qquad K = -\frac{\beta_2 z f_s^2}{2}\]Rather than truncating the inverse DTFT of \(H_c\), the \(N\) taps \(h[n]\), \(|n| \le (N-1)/2\), minimize the integrated squared error over the design band \([\Omega_1, \Omega_2]\):
\[\min_{h} \int_{\Omega_1}^{\Omega_2} \left| \sum_{l} h[l] e^{-j l \Omega} - e^{j K \Omega^2} \right|^2 d\Omega\]The normal equations of this quadratic problem read \(Q h = d\), with the Hermitian Toeplitz Gram matrix and the cross-correlation vector
\[Q_{m,l} = q(l - m), \quad q(p) = \frac{1}{2\pi} \int_{\Omega_1}^{\Omega_2} e^{-j p \Omega} d\Omega, \qquad d[n] = \frac{1}{2\pi} \int_{\Omega_1}^{\Omega_2} e^{j K \Omega^2} e^{j n \Omega} d\Omega\]Only \(q(p)\) for \(p \ge 0\) is evaluated, the negative lags following from the Hermitian symmetry \(q(-p) = q(p)^*\) that makes \(Q = Q^H\). Completing the square in the integrand of \(d[n]\) and mapping \(j K \Omega^2\) onto \(-t^2\) gives the closed form on an arbitrary band, in terms of the complex error function:
\[d[n] = \frac{e^{j \pi / 4}}{4 \sqrt{\pi K}} e^{-j \frac{n^2}{4 K}} \left[ \mathrm{erf}\!\left(\gamma \left(\Omega_2 + \frac{n}{2K}\right)\right) - \mathrm{erf}\!\left(\gamma \left(\Omega_1 + \frac{n}{2K}\right)\right) \right], \qquad \gamma = \sqrt{K} \, e^{-j \pi / 4}\](the band enters only through the two integration bounds; at \([\Omega_1, \Omega_2] = [-\pi, \pi]\) this collapses, using the oddness of \(\mathrm{erf}\), onto the usual full-band expression \(\mathrm{erf}(\kappa (2\pi K - n)) + \mathrm{erf}(\kappa (2\pi K + n))\) with \(\kappa = e^{j 3 \pi / 4} / (2 \sqrt{K})\)).
The ridge-regularized system \((Q + \epsilon I) h = d\) is then solved rather than inverted. This matters away from the full band: \(Q\) is a prolate matrix whose eigenvalues collapse to zero beyond the \(\approx N (\Omega_2 - \Omega_1) / (2\pi)\) degrees of freedom the band can constrain, so the explicit inverse carries entries of order \(1/\epsilon\) that cancel catastrophically against \(d\). The taps in that numerical null space are not individually determined – they do not affect the response inside the band, which is the quantity the design pins down.
On the full band \([-\pi, \pi]\) the degeneracy disappears: \(q(p) = \mathrm{sinc}(p) = 0\) for \(p \neq 0\) makes \(Q = I\) exactly and \(h = d\). For taps well inside the group-delay span, \(|n| \ll 2 \pi K\), both erf arguments saturate and \(d[n] \to \sqrt{j / (4 \pi K)} e^{-j n^2 / (4K)}\): there the design falls back on the truncated (Savory) filter. The two keep differing near \(|n| \approx 2 \pi K\), where the Fresnel integral is only half-completed and the least-squares design tapers the taps that the truncation keeps at full amplitude. The block then applies the full linear convolution
\[y[n] = \sum_{l} h[l] \, x[n - l]\]whose output is \(N - 1\) samples longer than the input, with a group delay of \((N - 1) / 2\) samples. Units are those of the module: \(\beta_2\) in ps^2/km from
comnumpy.optical.utils.compute_beta2(), converted internally to s^2/km, \(z\) in km and \(f_s\) in Hz, so that \(K\) is dimensionless.Axes: axis -1 – the convolution runs along the last axis (
scipy.signal.convolvein"full"mode); leading axes are batch, every row through the same taps.- param z:
Fiber length \(z\) in km.
- type z:
float
- param N:
Filter length \(N\) in taps; must be odd so that the support \(|n| \le (N-1)/2\) is symmetric.
- type N:
int
- param fs:
Sampling frequency \(f_s\) in Hz. Default is 1.
- type fs:
float, optional, keyword-only
- param w_vect:
Design band \([\Omega_1, \Omega_2]\) in rad/sample, with \(\Omega_1 < \Omega_2\). Default is
[-np.pi, np.pi](full band). A narrower band trades accuracy outside the band for accuracy inside it, which is what one wants when the signal is oversampled.- type w_vect:
List[float], optional, keyword-only
- param name:
Name of the processor instance. Default is
"optimal".- type name:
str, optional, keyword-only
- h#
Least-squares taps \(h[n]\), solution of \(Q h = d\).
- Type:
np.ndarray
- K#
Dimensionless dispersion \(K = -\beta_2 z f_s^2 / 2\).
- Type:
float
- epsilon#
Class-level ridge term \(\epsilon\) added to the diagonal of \(Q\) before solving. Default is
1e-14.- Type:
float
- lamb#
Class-level wavelength \(\lambda\) in nm (
WAVELENGTH).- Type:
float
- D#
Class-level dispersion coefficient \(D\) in ps/nm/km (
CD_COEFFICIENT).- Type:
float
- c#
Class-level speed of light \(c\) in m/s (
SPEED_OF_LIGHT).- Type:
float
- raises ValueError:
If the filter length
Nis even, or if the design bandw_vectis not a strictly increasing pair.
References
A. Eghbali, H. Johansson, O. Gustafsson, S. J. Savory, “Optimal least-squares FIR digital filters for compensation of chromatic dispersion in digital coherent optical receivers,” Journal of Lightwave Technology, vol. 32, no. 8, pp. 1449-1456, 2014.
S. J. Savory, “Digital filters for coherent optical receivers,” Optics Express, vol. 16, no. 2, pp. 804-817, 2008.
Examples
Same round trip as the truncated design, at equal filter length.
>>> from comnumpy.optical.channels import ChromaticDispersion >>> x = np.zeros(512, dtype=complex) >>> x[256] = 1.0 >>> y = ChromaticDispersion(1000.0, fs=20e9)(x) >>> comp = ChromaticDispersionLSFIRCompensator(1000.0, 55, fs=20e9) >>> delay = (comp.N - 1) // 2 >>> x_hat = comp(y)[delay:delay + 512] >>> print(round(float(np.abs(x_hat[256])), 3)) 0.977