Validate Somersalo scaling law
Here we show how we can compute multipactor thresholds measured for different reflection coefficient, and compare this evolution to Somersalo scaling law.
We also illustrate some ThresholdSet manipulations.
Load data
[1]:
from functools import partial
from multipac_testbench import AveragedThresholdSet, TestCampaign, ThresholdSet
from multipac_testbench.data import config_path
from multipac_testbench.data.multipactor_tests import tests_140
from multipac_testbench.instruments import CurrentProbe, ForwardPower
from multipac_testbench.util.multipactor_detectors import quantity_is_above_threshold
freqs = (140.0, 140.0, 140.0, 140.0)
swrs = (4.0, 3.0, 2.0, 1.0)
test_campaign = TestCampaign.from_filepaths(
tests_140,
freqs,
swrs,
config_path,
is_raw=True
)
[INFO ] [loader.py ] Applied trigger_policy = 'keep_all' on /home/placais/Documents/simulation/python/multipac_testbench/src/multipac_testbench/data/multipactor_tests/2025.06.20_140MHz-SWR4-11.csv
[WARNING ] [power.py ] ReflectedPower typically measured on channel B, so you should provide the arguments for the channel B fix.
[WARNING ] [factory.py ] column_header = 'NI9205_E1' not present in provided file. Skipping associated instrument.
[WARNING ] [test_conditions.py ] freq_mhz was supplied explicitly but FrequencySetpoint is also defined in the TOML. The explicit value takes precedence. Consider removing the freq_mhz argument and relying on the TOML.
[INFO ] [loader.py ] Applied trigger_policy = 'keep_all' on /home/placais/Documents/simulation/python/multipac_testbench/src/multipac_testbench/data/multipactor_tests/2025.06.20_140MHz-SWR3-12.csv
[WARNING ] [power.py ] ReflectedPower typically measured on channel B, so you should provide the arguments for the channel B fix.
[WARNING ] [factory.py ] column_header = 'NI9205_E1' not present in provided file. Skipping associated instrument.
[INFO ] [loader.py ] Applied trigger_policy = 'keep_all' on /home/placais/Documents/simulation/python/multipac_testbench/src/multipac_testbench/data/multipactor_tests/2025.06.20_140MHz-SWR2-13.csv
[WARNING ] [power.py ] ReflectedPower typically measured on channel B, so you should provide the arguments for the channel B fix.
[WARNING ] [factory.py ] column_header = 'NI9205_E1' not present in provided file. Skipping associated instrument.
[INFO ] [loader.py ] Applied trigger_policy = 'keep_all' on /home/placais/Documents/simulation/python/multipac_testbench/src/multipac_testbench/data/multipactor_tests/2025.06.20_140MHz-SWR1-14.csv
[WARNING ] [power.py ] ReflectedPower typically measured on channel B, so you should provide the arguments for the channel B fix.
[WARNING ] [factory.py ] column_header = 'NI9205_E1' not present in provided file. Skipping associated instrument.
/home/placais/Documents/simulation/python/multipac_testbench/src/multipac_testbench/util/physics.py:28: RuntimeWarning: invalid value encountered in sqrt
reflection_coefficient = np.abs(np.sqrt(reflected_power / forward_power))
/home/placais/Documents/simulation/python/multipac_testbench/src/multipac_testbench/util/physics.py:28: RuntimeWarning: invalid value encountered in sqrt
reflection_coefficient = np.abs(np.sqrt(reflected_power / forward_power))
Calculate multipactor thresholds
[2]:
current_multipactor_criterions = {'threshold': 14., 'minimum_number_of_points': 1}
current_multipac_detector = partial(quantity_is_above_threshold, **current_multipactor_criterions)
As Somersalo scaling law concerns power thresholds, we look for “global” multipactor criterions:
[3]:
merged = test_campaign.determine_thresholds(
current_multipac_detector,
CurrentProbe,
threshold_predicate=lambda t: t.sample_index > 300, # Only consider Thresholds measured after 300th power step
threshold_reducer="any", # Keyword to merge the multipactor zones
)
[INFO ] [threshold.py ] Signal does not end falling. Consider trimming trailing points.
[INFO ] [threshold.py ] Signal does not end falling. Consider trimming trailing points.
[INFO ] [threshold.py ] Signal does not end falling. Consider trimming trailing points.
[INFO ] [threshold.py ] Signal does not end falling. Consider trimming trailing points.
Check Somersalo scaling law
Naive thresholds
From there, you have several options. You can simply use these thresholds:[4]:
_ = test_campaign.check_somersalo_scaling_law(merged, figsize=(8, 8))
Extreme thresholds
You can filter out the thresholds, to keep only one lower and one upper threshold per half-power cycle.
[5]:
extreme = {test: ThresholdSet.extreme(threshold_set) for test, threshold_set in merged.items()}
_ = test_campaign.check_somersalo_scaling_law(extreme, figsize=(8, 8))
Average thresholds
We average the “global” multipactor thresholds measured during the last power step:
Note
AveragedThresholdSet is an object derived from ThresholdSet.
Internally, when you call AveragedThresholdSet.data_at_thresholds(<AnInstrumentType>), it will gather the signal measured by <AnInstrumentType> at all lower and upper thresholds, and return the median of those signals.
[6]:
averaged = {test: AveragedThresholdSet.from_threshold_set(threshold_set) for test, threshold_set in merged.items()}
_ = test_campaign.check_somersalo_scaling_law(averaged, figsize=(8, 8))