As a (late) Christmas present I thought I’d share my method of determining the required OSNR (ROSNR) value for a transmission system in simulations by means of the Monte Carlo method. Recently, I do prefer the error vector magnitude (EVM) as a figure of merit, but not a lot of people share this view. Many seem to love the ROSNR, especially Bell Labsers, and who am I to tell them otherwise?

For those that are not so familiar with the ROSNR: The ROSNR describes the noise spectral density$^1$ in the optical domain that can be tolerated to achieve a certain BER. It thus separates amplifier noise from other, more deterministic impairments. For more information, see e.g. [1]. Usually, the BER value is taken to be $10^{-3}$ – lower target BER values would make the calculation take forever. The simulation runs noiseless (optical amplifiers add no noise at all), and all the noise power is added just before the receiver. This way, nonlinear noise interactions during propagation cannot be taken into account, but these are seldom relevant (one should check this, though).

What we need in order to determine the ROSNR of a transmission link is access to the optical field just before the receiver, the input and output data, and the free OptiLux simulation package [SourceForge] from the University of Parma – actually, we need only one of the supplementary functions in this package to save us some programming tedium.$^2$

#### Adding Noise

The principle of Monte Carlo ROSNR determination is to find the right amount of noise to add to the signal so that the BER at the receiver output equals some predetermined value. This usually is a trial-and-error or optimization problem. Personally, I like to take a few selected values of noise power, determine their BER and then interpolate. This is often much quicker, but more on that later. The MATLAB code to add the noise is

signalPower = mean(abs(Signalx).^2 + abs(Signaly).^2);

noisePower = signalPower / 10^(OSNR/10) * (sampleRate / 12.5e9);

noiseSamples = randn(length(Signalx), 4) * sqrt(noisePower/4);

noisySignalx = Signalx + noiseSamples(:,1) + 1i*noiseSamples(:,2);

noisySignaly = Signaly + noiseSamples(:,3) + 1i*noiseSamples(:,4);

where `OSNR`

is the OSNR in dB and `sampleRate`

is the simulation bandwidth. Since the OSNR is defined as the noise power in a 12.5 GHz (0.1 nm) bandwidth, the total noise in the simulation bandwidth is correspondingly higher. `Signalx`

and `Signaly`

are the original signal samples in both polarizations, `noisySignalx`

/ `noisySignaly`

are the “noisy” samples. Each quadrature in each polarization, all being independent of one another, receives a quarter of the total noise power. If we simulate only a single polarization, we can omit the last line.

The noisy signal is then received by whatever receiver we have programmed and the received data are compared to the sent data in order to determine the sample BER.

#### Determining BER

Unless we simulate an immensely long bit sequence, we will usually only see a few errors for the OSNR values of interest (with a BER near $10^{-3}$). This sample BER value has little statistical significance [Wikipedia] – one error more or less may significantly alter the obtained BER value. Often, simulations are repeated until at least 100 errors are obtained in order to have some confidence in the results. We can avoid having to run the whole simulation multiple times (which can take eons to complete) by simply adding a different set of noise samples to the signals `Signalx`

and `Signaly`

just in front of the receiver and then adding up the errors from all runs. In essence, many samples of a Gaussian noise variable are added to each signal sample and its error probability determined. Forestieri’s algorithm does this analytically, but is applicable to only a few receiver types [2].

The corresponding MATLAB code uses OptiLux’ `ber_estimate`

function and looks something like this:

cond = true;

while cond

% code to add noise from above goes here

% receiver implementation goes here

[cond, avgber, nruns, stdber] = ber_estimate(rxpat, txpat, ...

struct('nmin', 1000));

% or [cond, avgber, nruns, stdber] = ber_estimate(rxpat, ...

txpat, struct('stop', [0.05 99]));

end

BER(kk) = avgber;

The loop runs until the function returns `cond = false`

, which happens here after 1000 errors have been counted. The variable `rxpat`

contains the received bit sequence and `txpat`

correspondingly the sent sequence. These can be matrices, all their elements are compared and mismatches counted. For QPSK signals in a single polarization I use two colums of bipolar binary data (“1” and “–1” – one column for the in-phase and one for the quadrature data) – for two polarization there would be four columns of data. `nruns`

contains the number of compared bits (matrix elements). The alternative (commented out) function call uses a relative accuracy and confidence value pair as a stopping criterion, both criteria can also be combined. Be sure to make some test runs and check the running time using `tic`

and `toc`

, because the number of runs can easily become excessive when using bad values. A typical convergence graph is shown in Fig. 1 (plotting `avgber`

over `avgber*nruns`

after each run of `ber_estimate`

), the stopping criterion here was an accuracy of 0.025 with 95% confidence. Often, several thousand counted errors are needed for the BER to converge sufficiently. However, depending on the signal and OSNR value, your mileage may vary.

Finally, we protocol the total BER into a variable – here, `kk`

runs over different OSNR values in an outer loop (not shown).

#### Interpolating the ROSNR

Okay, so now we have the BER values for a couple of OSNR values, but very likely none of these is exactly $10^{-3}$. We could run some optimization algorithms, changing the OSNR slightly and running the BER loop again, but this takes very long. I don’t have that much time. It is much easier to just interpolate the data we have. I usually only look at integer OSNR values and interpolate anything in between.

try

ROSNR = interp1(log10(BER), 8:12, -3, 'pchip', NaN);

catch exception

ROSNR = NaN;

end

where `BER`

contains the BERs for integer OSNR values between 8 and 12. I like to wrap the interpolation in a `try`

/`catch`

segment, because sometimes it’ll throw an error (e.g. if input data is not monotonous) and this way it won’t stop the whole script, but simply gives a `NaN`

result. Using the logarithm of the BER makes the interpolation easier (the changes are smaller), especially at very low BERs. We could also use `log10(-log10(BER))`

, since plotting this over the OSNR (in dB) is an pretty much linear function and most simple to interpolate – but then again, taking the logarithm twice makes a linear function out of almost everything. Fig. 2 compares the various BER curves and their MATLAB “pchip” interpolation.

We now know the required OSNR for this particular bit sequence over the transmission link in question. Unless the system is purely linear and has small memory, the ROSNR value will depend on the particular bit sequence, even when this sequence is very long. To be on the safe side, we would have to repeat the simulation with different sequences and average their results – be careful, though: we have to average the BERs *prior* to calculating the ROSNR and not the ROSNRs itself in order to do it correctly from a statistical point of view.

If you think I am doing something wrong or if you have an idea how to improve the code, let me know in the comments.

**1** Since the OSNR is normalized to a 12.5 GHz bandwidth, it rather describes a noise spectral density (which does depend on the usable signal power) than a signal-to-noise ratio in the communications science sense.

**2** Optilux is actually a pretty clever simulation tool that incorporates the split-step Fourier algorithm for optical fibers as well as many algorithms needed for coherent detection and much more. Once you get used to its unusual normalization of frequencies, it’s very powerful.

[1] R.-J. Essiambre, G. Raybon and B. Mikkelsen, “Pseudo-Linear Transmission of High-Speed TDM Signals: 40 and 160 Gb/s,” in *Optical Fiber Telecommunications IV B*, Academic Press, 2002.

[2] E. Forestieri, “Evaluating the error probability in lightwave systems with chromatic dispersion, arbitrary pulse shape and pre- and postdetection filtering,” *Journal of Lightwave Technology*, vol. 21, no. 6, pp. 1592ff., June 2003.

last posts in MATLAB:

Dear Marcus,

Recently, I’m also doing some simulation on BER versus OSNR. And Optilux is also used in my simulation. The perpose is reserching the performance of optical system with PMD improved by Reed-Solomon (RS) code. But I find for a given BER (e.g. 10-3), the OSNR is larger than other reserches which stated in the papers. On the other hand, I do not quite understand the OSNR in the Optilux. Can you give me some advice on how to simulating OSNR in Optilux? Thanks very much.

A college student, LML

Everything that I could answer is already within the post. It is not unusual that ROSNR values differ in different papers, depending on how well the authors checked for convergence of their values. The difference are usually small, much less than a dB or so…

How to use optilux in matlab?

Do help me in this regard.