summaryrefslogtreecommitdiff
path: root/validation/test
diff options
context:
space:
mode:
authorLudovic Maillard2012-09-10 16:41:09 +0200
committerLudovic Maillard2012-09-12 11:07:51 +0200
commit21d1380c0be7abb80510ea886bfd212094a9e5c5 (patch)
tree07e88339da2f739ff21a651875a444ca1f2fbcad /validation/test
parent0ac19bbb690782ec3222422ba0f4329d74555190 (diff)
validation: add the CE stats in the validation test report, closes #3335
Diffstat (limited to 'validation/test')
-rw-r--r--validation/test/test_iperf/test_bench.diabin5242 -> 5252 bytes
-rw-r--r--validation/test/test_iperf/test_throughput.py316
-rw-r--r--validation/test/test_iperf/test_throughput.rst4
3 files changed, 225 insertions, 95 deletions
diff --git a/validation/test/test_iperf/test_bench.dia b/validation/test/test_iperf/test_bench.dia
index f54dd3db5d..db21d2ab55 100644
--- a/validation/test/test_iperf/test_bench.dia
+++ b/validation/test/test_iperf/test_bench.dia
Binary files differ
diff --git a/validation/test/test_iperf/test_throughput.py b/validation/test/test_iperf/test_throughput.py
index a4561d0e6a..525245e38a 100644
--- a/validation/test/test_iperf/test_throughput.py
+++ b/validation/test/test_iperf/test_throughput.py
@@ -12,9 +12,9 @@ import math
import validlib.attenuator as attenuator
import validlib.waveform_generator as waveform_generator
-import validlib.iperf as iperf
-import validlib.spc300 as spc300
import validlib.power_strip as power_strip
+import validlib.spc300 as spc300
+import validlib.iperf as iperf
config = {
#True|False
@@ -24,26 +24,37 @@ config = {
#True|False
#If True, the plugs are restarted before each serie of measurements
#If False, the plugs are not restarted before a serie of measurements
- "restart_plugs":True,
+ "restart_plugs":False,
+ #If True and if the 2 plugs are MSTAR, the 'vs_get_ce_stats' MME is sent
+ #before and after each serie of measurements
+ #If False or if one of the 2 plugs is not MSTAR, no MME is sent
+ "get_CE_stats":True,
+ #CE stats which difference, before and after each serie of measurements,
+ #is displayed in the report
+ "displayed_diff_CE_stats": ["Restart BER",
+ "Restart PB error rate",
+ "Restart peer request",
+ "Restart tone map update",
+ "Restart ber margin update"],
#True|False
#If True, the measurements are reset, made and then the report is generated
#If False, the report is generated from the previous measurements
"make_measurements":True,
"attenuation":{
- "values":numpy.arange(38, 98, 5).tolist(),
- "duration_s":5,
+ "values":numpy.arange(30, 100, 5).tolist(),
+ "duration_s":20,
#["a_b_uni"|"b_a_uni"|"bi"]
#see iperf.measurement_specs() for the meaning of the values
"curves":["a_b_uni", "b_a_uni", "bi"]},
"SNR": {
"values":numpy.arange(40, -10, -5).tolist(),
- "duration_s":5,
+ "duration_s":20,
#["a_b_uni"|"b_a_uni"|"bi"]
#see iperf.measurement_specs() for the meaning of the values
- "curves":["a_b_uni", "b_a_uni", "bi"]},
+ "curves":["a_b_uni", "b_a_uni"]},
"SJR":{
- "values":numpy.arange(10, -35, -5).tolist(),
- "duration_s":5,
+ "values":numpy.arange(0, -55, -5).tolist(),
+ "duration_s":20,
#["a_b_uni"]
#see iperf.measurement_specs() for the meaning of the values
"curves":["a_b_uni"]},
@@ -52,21 +63,21 @@ config = {
#The frame size and the max throughput includes the Ethernet,
#IP and TCP/UDP headers
"values":[
- (68, 11),
- (128, 20),
- (256, 50),
- (512, 90),
- (768, 120),
- (1024, 120),
- (1280, 120),
- (1514, 120),
- (1515, 120),
- (1550, 120),
- (1600, 120),
- (1700, 120),
- (2000, 120)
+ (68, 18),
+ (128, 34),
+ (256, 65),
+ (512, 105),
+ (768, 125),
+ (1024, 142),
+ (1280, 142),
+ (1514, 142),
+ (1515, 142),
+ (1550, 142),
+ (1600, 142),
+ (1700, 142),
+ (2000, 142)
],
- "duration_s":5,
+ "duration_s":20,
#["a_b_uni"|"b_a_uni"|"bi"]
#see iperf.measurement_specs() for the meaning of the values
"curves":["a_b_uni", "b_a_uni", "bi"]
@@ -75,7 +86,7 @@ config = {
#Must be ["time"]
"values":["time"],
#Must be seconds
- "duration_s":120,
+ "duration_s":15,
#["a_b_uni"|"b_a_uni"|"bi"]
#see iperf.measurement_specs() for the meaning of the values
"curves":["a_b_uni"]},
@@ -107,7 +118,7 @@ config = {
],
#Duration after the channel modification during which we generate traffic
#to let the CE converge
- "ce_sync_time_s":10,
+ "ce_sync_time_s":2,
#Directory where the report is generated
"reports_directory":"reports",
#True|False
@@ -115,13 +126,13 @@ config = {
#noise or the attenuation to be applied on the devices
#True should be used in AV
#False should be used in EoC
- "amn":True,
+ "amn":False,
#Bandwidth of the useful signal
#Typical values are (2, 28) in AV and (1, 38) in EoC
- "signal_band_mhz":(2, 28),
+ "signal_band_mhz":(1, 38),
#Power Spectral Density
#Typical values are -50 in AV and -63 in EoC
- "ppsd_dbm_per_hz":-50,
+ "ppsd_dbm_per_hz":-63,
#We want to reach a very low SJR, but the output power of the
#waveform generator is limited. Therefore, we set the signal to
#a low value, actually the lowest for which the throughput
@@ -129,50 +140,104 @@ config = {
#the results obtained in the 'attenuation' test. If the curve starts going
#down at 55 dB and if the minimal attenuation of the bench is 38,
#sjr_attenuator_attenuation_db must be equal to (55 - 38) dB = 17 dB
- "sjr_attenuator_attenuation_db": 17,
+ "sjr_attenuator_attenuation_db": 29,
+ #Signal attenuation on each side of the bench, to avoid any dazzling
+ #between the plugs. A typical value is 10.
+ "signal_attenuation_db": 10,
+ #(unidir, bidir) throughput targets in Mbit/s for UDP tests
+ #Typical values are the following:
+ # - (100, 85) in AV with an SPR310 and
+ # - (142, 85) for EoC with an SPK300g
+ "udp_throughputs_mbit_per_s": (142, 85),
+ #Configuration passed to the 'attenuator' module
+ "attenuator" : {
+ "name":"att",
+ "buttons":{1:1, 2:2, 3:4, 4:4, 5:10, 6:20, 7:40, 8:0},
+ "user":"spidcom",
+ "host":"tursan"
+ },
+ #Configuration passed to the 'waveform_generator' module
+ "waveform_generator" : {
+ "name":"gbf",
+ "user":"spidcom",
+ "host":"tursan",
+ "noise_band_mhz":(0, 50),
+ "power_range_dbm":(-40, 24)
+ },
#Configuration passed to the 'power_strip' module
"power_strip":{1: ("192.168.0.10", "admin", "anel")},
#Configuration passed to the 'spc300' module
- #If the devices are not MSTAR plugs, it has no impact
"spc300":{
- "eth_netmask": "10.3.6.",
+ "eth_netmask": "192.168.5.",
"plc_netmask": "unused",
+ #Empty dictionnary means that no MSTAR plugs are used
"plugs":
{
- (1, 1): ("143", "unused", "unused"),
- (1, 5): ("141", "unused", "unused")
+ (1, 1): ("100", "unused", "unused"),
+ (1, 5): ("101", "unused", "unused")
}
+ },
+ #Configuration passed to the 'iperf' module
+ "iperf" : {
+ "host_a":{"non_plc_ip_address":"tursan",
+ "user":"spidcom",
+ "plc_ip_address":"192.168.5.254",
+ "power_strip_key":(1, 1),
+ "device":("SPK300g-master", "eoc-0.7.9")
+ },
+ "host_b":{"non_plc_ip_address":"spidcom-lab1",
+ "user":"spidcom",
+ "plc_ip_address":"192.168.5.52",
+ "power_strip_key":(1, 5),
+ "device":("SPK300g-slave", "eoc-0.7.9")
+ },
}
}
#Peak to Average Ratio of the power, in OFDM
par_db = 10
-#Signal attenuation on each side of the bench
-signal_attenuation_db = 10
#Waveform attenuation at the output of the generator
waveform_attenuation_db = 10
#Attenuation of an AMN
amn_attenuation_db = 6
#Attenuation of the T
attenuation_t_db = 6
+#String displayed for the maximum throughput test
+str_max_throughput = "Maximum throughput"
#Units of the "values" for each type of test
units = {"attenuation":"dB",
"SNR":"dB",
"SJR":"dB",
"frame_size":"bytes",
- "dynamic_jammer":"seconds"}
+ "dynamic_jammer":"seconds",
+ "Maximum throughput":"Mbit/s",
+ "Restart BER":"no unit",
+ "Restart PB error rate":"no unit",
+ "Restart peer request":"no unit",
+ "Restart tone map update":"no unit",
+ "Restart ber margin update":"no unit"
+ }
def report():
"""Generates the PDF report as specified in the configuration.
It requires to set up first the test bench as detailed in the test bench
description."""
+ # Configure the 'attenuator' module
+ attenuator.update_config(config["attenuator"])
+
+ # Configure the 'waveform_generator' module
+ waveform_generator.update_config(config["waveform_generator"])
+
# Configure the 'power_strip' module
power_strip.update_config(config["power_strip"])
# Configure the 'spc300' module
spc300.update_config(config["spc300"])
+ # Configure the 'iperf' module
+ iperf.update_config(config["iperf"])
+
# Build the picture of the test bench
fig_name = build_test_bench_picture()
@@ -194,7 +259,13 @@ def report():
# images
for (test_protocol, test_type, test_params) in config["fixtures"]:
datarates = extract_datarates(test_protocol, test_type, test_params)
- dump_and_draw(test_protocol, test_type, test_params, datarates)
+ dump_and_draw(test_protocol, test_type, test_params, datarates,
+ str_max_throughput)
+ for stat_name in config["displayed_diff_CE_stats"]:
+ stats = extract_stats(test_protocol, test_type, test_params,
+ stat_name)
+ dump_and_draw(test_protocol, test_type, test_params, stats,
+ stat_name)
# Build the rst file
build_rst_file(fig_name)
@@ -257,10 +328,12 @@ def build_rst_file(fig_name):
data = waveform_data()
(non_plc_ip_address_a, non_plc_ip_address_b) = iperf.non_plc_ip_addresses()
(version_a, version_b) = iperf.versions()
- rst_template = open(os.path.splitext(__file__)[0] + ".rst", "r").read()
+ rst_file = open(os.path.splitext(__file__)[0] + ".rst", "r")
+ rst_template = rst_file.read()
+ rst_file.close()
(device_a, device_b) = iperf.devices()
- (device_model_a, device_version_a, _) = device_a
- (device_model_b, device_version_b, _) = device_b
+ (device_model_a, device_version_a) = device_a
+ (device_model_b, device_version_b) = device_b
rst_template_dict = dict(device_model_a = device_model_a,
device_version_a = device_version_a,
device_model_b = device_model_b,
@@ -289,10 +362,34 @@ def rst_results():
"Results\n" \
"=======\n" \
"\n"
- results = [ rst_result(fixture) for fixture in config["fixtures"] ]
+ results = []
+ for fixture in config["fixtures"] :
+ results = results + [rst_result(fixture, str_max_throughput)] + \
+ [rst_result(fixture, stat_name)
+ for stat_name in config["displayed_diff_CE_stats"]]
return title + rst_page_break().join(results)
-def rst_result((test_protocol, test_type, test_params)):
+def rst_subtitle_break():
+ return "\n" \
+ "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" \
+ "\n"
+
+def rst_title_break():
+ return "\n" \
+ "------------------------------------------------------------------\n" \
+ "\n"
+
+def rst_picture_scale():
+ return ".png\n" + \
+ " :scale: 65 %\n" + \
+ "\n"
+
+def rst_figure(test_protocol, test_type, test_params, figure_name):
+ return ".. figure:: " + file_prefix(test_protocol, test_type, test_params,
+ None, None, False) + "_" + \
+ figure_name.replace(' ','_')
+
+def rst_result((test_protocol, test_type, test_params), figure_name):
if test_type == "SJR":
(freq_mhz, am) = test_params
if am is None:
@@ -305,18 +402,23 @@ def rst_result((test_protocol, test_type, test_params)):
% test_params
else:
test_params_title = ""
- return test_protocol + " - " + test_type + test_params_title + "\n" \
- "------------------------------------------------------------------\n" \
- "\n" + \
- rst_param("Duration of each measurement (seconds)",
- config[test_type]["duration_s"]) + \
- rst_comment(test_type, test_params) + \
- "\n" + \
- ".. figure:: " + file_prefix(test_protocol, test_type, test_params,
- None, False) + \
- ".png\n" \
- " :scale: 65 %\n" \
- "\n"
+ if str_max_throughput in figure_name:
+ return test_protocol + " - " + test_type + test_params_title + \
+ rst_title_break() + \
+ rst_param("Duration of each measurement (seconds)",
+ config[test_type]["duration_s"]) + \
+ rst_comment(test_type, test_params) + "\n" + \
+ rst_figure(test_protocol, test_type, test_params, figure_name) + \
+ rst_picture_scale()
+ else:
+ return figure_name + " - " + test_protocol + " - " + test_type + \
+ test_params_title + rst_subtitle_break() + \
+ rst_param("Y-axis value", "difference between the statistic " \
+ "retrieved before and after each measurement" \
+ "(a value of (-1) means that the statistics " \
+ "are invalid)") + \
+ rst_figure(test_protocol, test_type, test_params, figure_name) + \
+ rst_picture_scale()
def rst_comment(test_type, test_params):
if test_type in ["attenuation", "SNR"]:
@@ -408,6 +510,7 @@ def change_channel(test_type, test_params, test_value):
if test_type == "attenuation":
#Offset allowing to convert the overall attenuation in the attenuation
#at the attenuator level (attenuation = overall attenuation - offset)
+ signal_attenuation_db = config["signal_attenuation_db"]
offset = 2 * (signal_attenuation_db + get_amn_attenuation_db()) + \
attenuation_t_db
assert test_value >= offset, (test_type, test_value)
@@ -451,14 +554,16 @@ def make_measurement(test_protocol, test_type, test_params, test_value):
curves = config[test_type]["curves"]
prefix = file_prefix(test_protocol, test_type, test_params, test_value)
if test_type in ["attenuation", "SNR", "SJR", "dynamic_jammer"]:
- udp_parameters = ((iperf.default_frame_size, 103),
- (iperf.default_frame_size, 88))
+ udp_throughputs = config["udp_throughputs_mbit_per_s"]
+ (unidir_udp_throughput, bidir_udp_throughput) = udp_throughputs
+ udp_parameters = ((iperf.default_frame_size, unidir_udp_throughput),
+ (iperf.default_frame_size, bidir_udp_throughput))
elif test_type == "frame_size":
udp_parameters = (test_value, test_value)
else:
assert False, test_type
iperf.make_measurement(test_protocol, udp_parameters, duration_s, curves,
- prefix)
+ prefix, config["get_CE_stats"])
def extract_datarates(test_protocol, test_type, test_params):
"""Extract the datarates from the measurement files"""
@@ -467,20 +572,32 @@ def extract_datarates(test_protocol, test_type, test_params):
test_values = get_test_values(test_type)
if test_values == ["time"]:
datarates[direction] = \
- extract_datarates_from_report(test_protocol, test_type, \
- test_params, None, \
- direction)[0]
+ extract_values_from_report(test_protocol, test_type,
+ test_params, None,
+ direction, str_max_throughput)[0]
else:
datarates[direction] = \
- [ extract_datarates_from_report(test_protocol, test_type, \
- test_params, test_value, \
- direction)[1]
+ [ extract_values_from_report(test_protocol, test_type,
+ test_params, test_value, direction,
+ str_max_throughput)[1]
for test_value in test_values ]
return datarates
-def extract_datarates_from_report(test_protocol, test_type, test_params,
- test_value, direction):
- """Extract the datarate from a measurement file"""
+def extract_stats(test_protocol, test_type, test_params, stat_name):
+ """Extract the statistics from the measurement files"""
+ stats = {}
+ for direction in get_all_directions(test_type):
+ test_values = get_test_values(test_type)
+ stats[direction] = \
+ [ extract_values_from_report(test_protocol, test_type,
+ test_params, test_value,
+ direction, stat_name)
+ for test_value in test_values ]
+ return stats
+
+def extract_values_from_report(test_protocol, test_type, test_params,
+ test_value, direction, name):
+ """Extract the data from a measurement file"""
prefix = file_prefix(test_protocol, test_type, test_params, test_value)
if test_type in ["attenuation", "SNR", "SJR", "dynamic_jammer"]:
frame_size = iperf.default_frame_size
@@ -489,22 +606,27 @@ def extract_datarates_from_report(test_protocol, test_type, test_params,
else:
assert False, test_type
duration_s = config[test_type]["duration_s"]
- return iperf.extract_datarates_from_report(test_protocol, frame_size,
- prefix, direction, duration_s)
+ if str_max_throughput in name:
+ fun = iperf.extract_datarates_from_report
+ else:
+ fun = iperf.extract_statistic_from_report
+ return fun(test_protocol, frame_size, prefix, direction, duration_s, name)
-def dump_and_draw(test_protocol, test_type, test_params, datarates):
- """Dump the data and draw the curves of the datarates"""
+def dump_and_draw(test_protocol, test_type, test_params, values, yname):
+ """Dump the data and draw the curves"""
directions = get_all_directions(test_type)
test_values = get_test_values(test_type)
if test_values == ["time"]:
test_values = range(1, config[test_type]["duration_s"] + 1)
- file_name_base = file_prefix(test_protocol, test_type, test_params)
- iperf.dump(directions, test_type, test_values, file_name_base + ".txt",
- datarates)
- title = "Maximum throughput vs " + test_type + " in " + test_protocol
+ file_name_base = file_prefix(test_protocol, test_type, test_params,
+ None, yname, True)
+ title = yname + " vs " + test_type + " in " + test_protocol
+ iperf.dump_measurement(directions, test_type, test_values,
+ file_name_base + ".txt", values)
xlabel = test_type + " (" + units[test_type] + ")"
- iperf.draw(title, xlabel, directions, test_type, test_values,
- config["show"], file_name_base + ".png", datarates)
+ ylabel = yname + " (" + units[yname] + ")"
+ iperf.draw(title, xlabel, ylabel, directions, test_type, test_values,
+ config["show"], file_name_base + ".png", values)
def get_all_directions(test_type):
curves = config[test_type]["curves"]
@@ -517,7 +639,7 @@ def get_reports_directory():
return directory
def file_prefix(test_protocol = None, test_type = None, test_params = None,
- test_value = None, directory = True):
+ test_value = None, measure_name = None, directory = True):
if directory == False:
reports_directory = ""
else:
@@ -527,10 +649,10 @@ def file_prefix(test_protocol = None, test_type = None, test_params = None,
else:
test_unit = units[test_type]
return get_file_prefix(test_protocol, test_type, test_params, test_value,
- test_unit, reports_directory)
+ test_unit, measure_name, reports_directory)
def get_file_prefix(test_protocol, test_type, test_params, test_value,
- test_unit, reports_directory):
+ test_unit, measure_name, reports_directory):
base_name = os.path.splitext(os.path.basename(__file__))[0]
if test_protocol is not None:
base_name += "_" + test_protocol
@@ -541,20 +663,24 @@ def get_file_prefix(test_protocol, test_type, test_params, test_value,
base_name += "_%s" % "_".join(test_params_strings)
if test_value is not None:
base_name += "_%s%s" % (str(test_value), test_unit)
+ if measure_name is not None:
+ base_name += "_" + measure_name.replace(' ','_')
return os.path.join(reports_directory, base_name)
def waveform_data():
ppsd_dbm_per_hz = config["ppsd_dbm_per_hz"]
signal_band_mhz = config["signal_band_mhz"]
sjr_attenuator_attenuation_db = config["sjr_attenuator_attenuation_db"]
+ signal_attenuation_db = config["signal_attenuation_db"]
amn_attenuation_db = get_amn_attenuation_db()
noise_band_mhz = waveform_generator.noise_band_mhz()
return get_waveform_data(ppsd_dbm_per_hz, signal_band_mhz,
noise_band_mhz, sjr_attenuator_attenuation_db,
- amn_attenuation_db)
+ amn_attenuation_db, signal_attenuation_db)
def get_waveform_data(ppsd_dbm_per_hz, signal_band_mhz, noise_band_mhz,
- sjr_attenuator_attenuation_db, amn_attenuation_db):
+ sjr_attenuator_attenuation_db, amn_attenuation_db,
+ signal_attenuation_db):
(signal_freq_min_mhz, signal_freq_max_mhz) = signal_band_mhz
signal_bandwith_mhz = signal_freq_max_mhz - signal_freq_min_mhz
#the term 60 corresponds to the conversion from MHz to Hz
@@ -643,7 +769,7 @@ if __name__ == "__main__":
"waveform_attenuation_db":10,
"snr_offset":11,
"sjr_offset":-9} == \
- get_waveform_data(-50, (2, 28), (0, 50), 17, 6)
+ get_waveform_data(-50, (2, 28), (0, 50), 17, 6, 10)
assert {"ppsd_dbm_per_hz":-63,
"par_db":10,
@@ -661,30 +787,32 @@ if __name__ == "__main__":
"waveform_attenuation_db":10,
"snr_offset":4,
"sjr_offset":-14} == \
- get_waveform_data(-63, (1, 38), (0, 50), 17, 0)
+ get_waveform_data(-63, (1, 38), (0, 50), 17, 0, 10)
assert "./test_throughput_UDP_frame_size_(5, 5)bytes" == \
- get_file_prefix("UDP", "frame_size", None, (5, 5), "bytes", ".")
+ get_file_prefix("UDP", "frame_size", None, (5, 5), "bytes", None, ".")
assert "./test_throughput_UDP_SNR_-5dB" == \
- get_file_prefix("UDP", "SNR", None, -5, "dB", ".")
+ get_file_prefix("UDP", "SNR", None, -5, "dB", None, ".")
assert "/reports/test_throughput_UDP_SNR_-5dB" == \
- get_file_prefix("UDP", "SNR", None, -5, "dB", "/reports")
+ get_file_prefix("UDP", "SNR", None, -5, "dB", None, "/reports")
assert "reports/test_throughput_UDP_SNR_-5dB" == \
- get_file_prefix("UDP", "SNR", None, -5, "dB", "reports")
+ get_file_prefix("UDP", "SNR", None, -5, "dB", None, "reports")
assert "reports/test_throughput_UDP_SNR_-5dB" == \
- get_file_prefix("UDP", "SNR", None, -5, "dB", "reports/")
+ get_file_prefix("UDP", "SNR", None, -5, "dB", None, "reports/")
assert "reports/subreports/test_throughput_UDP_SNR_-5dB" == \
- get_file_prefix("UDP", "SNR", None, -5, "dB", "reports/subreports")
+ get_file_prefix("UDP", "SNR", None, -5, "dB", None, "reports/subreports")
assert "reports/subreports/test_throughput_UDP_SJR_15_-5dB" == \
- get_file_prefix("UDP", "SJR", (15,), -5, "dB", "reports/subreports")
+ get_file_prefix("UDP", "SJR", (15,), -5, "dB", None, "reports/subreports")
assert "reports/test_throughput_TCP_SNR" == \
- get_file_prefix("TCP", "SNR", None, None, None, "reports")
+ get_file_prefix("TCP", "SNR", None, None, None, None, "reports")
assert "reports/test_throughput_TCP" == \
- get_file_prefix("TCP", None, None, None, None, "reports")
+ get_file_prefix("TCP", None, None, None, None, None, "reports")
assert "reports/test_throughput" == \
- get_file_prefix(None, None, None, None, None, "reports")
+ get_file_prefix(None, None, None, None, None, None, "reports")
assert "test_throughput" == \
- get_file_prefix(None, None, None, None, None, "")
+ get_file_prefix(None, None, None, None, None, None, "")
+ assert "reports/test_throughput_UDP_SNR_-10dB_Throughput" == \
+ get_file_prefix("UDP", "SNR", None, -10, "dB", "Throughput", "reports")
assert flatten([]) == []
assert flatten([1]) == [1]
diff --git a/validation/test/test_iperf/test_throughput.rst b/validation/test/test_iperf/test_throughput.rst
index dafa1cd52f..cc34454bfc 100644
--- a/validation/test/test_iperf/test_throughput.rst
+++ b/validation/test/test_iperf/test_throughput.rst
@@ -39,6 +39,8 @@ On the figure, the host A controls the attenuator and the noise generator but it
The attenuation of 10 dB on the noise generator is useful when the generator is off, in order to avoid any reflection.
+The purpose of the attenuation of N dB (typically 10 dB) on the output of each plug is to avoid any dazzling between the plugs.
+
The AMN's are necessary only if the plugs are not EoC, i.e have no native output in coax.
Configuration
@@ -88,7 +90,7 @@ The PC of test and the host A (resp. B) should be configured so that the PC of t
- Execute the following command, where ethX is the interface between the host and the plug::
- sudo iptables -t nat -A POSTROUTING -s $TEST_PC_NETWORK -o sethX -j MASQUERADE
+ sudo iptables -t nat -A POSTROUTING -s $TEST_PC_NETWORK -o ethX -j MASQUERADE
.. raw:: pdf