Choose And Override Observation Weights¶
This guide shows how to set observation weights automatically or manually in DiffOrb. It uses /tmp/2025bc10-online-guide.psv to show how weight results are organized, compare automatic weights with reported uncertainties, and change the weights for selected rows.
Prerequisites¶
- Activate the project environment described in Installation.
- Run Load Online Observations From MPC And JPL first.
- The example below uses
/tmp/2025bc10-online-guide.psv. - Install the
weightsdata set in the DiffOrb data directory, or pass an explicit rule-table path toVFCC17WeightPolicy(...). - Read Weighting And Debiasing Models first if you want more detail on the weighting models.
1. Inspect weight blocks¶
DiffOrb provides several WeightPolicy classes for setting weights, such as VFCC17WeightPolicy, ADESWeightPolicy, and InteractiveWeightPolicy. They all use weights(...) to return a WeightResult. Like ObservationData, WeightResult keeps optical and radar data in separate arrays.
from difforb.astrometry import load_local_observations, VFCC17WeightPolicy
obs = load_local_observations("/tmp/2025bc10-online-guide.psv")
result = VFCC17WeightPolicy().weights(obs)
print("OPTICAL_SHAPE", result.optical_uncertainties.shape)
print("RADAR_SHAPE", result.radar_uncertainties.shape)
print("OPTICAL_SOURCE_HEAD", result.optical_sources[:3])
print("RADAR_SOURCE_HEAD", result.radar_sources[:3])
OPTICAL_SHAPE (799, 2)
RADAR_SHAPE (8,)
OPTICAL_SOURCE_HEAD ['VFCC17' 'VFCC17' 'VFCC17']
RADAR_SOURCE_HEAD ['VFCC17' 'VFCC17' 'VFCC17']
Optical uncertainties have two columns. Radar uncertainties have one value per row.
2. Compare weight policies¶
VFCC17WeightPolicy gives statistical optical uncertainties. ADESWeightPolicy uses the uncertainties already stored in each row.
Read Weighting And Debiasing Models if you want more detail on the models behind VFCC17WeightPolicy and ADESWeightPolicy.
import numpy as np
from difforb.astrometry import load_local_observations, ADESWeightPolicy, VFCC17WeightPolicy
obs = load_local_observations("/tmp/2025bc10-online-guide.psv")
vfcc = VFCC17WeightPolicy().weights(obs)
ades = ADESWeightPolicy().weights(obs)
for idx in [7, 8, 9]:
vfcc_ra = float(np.rad2deg(vfcc.optical_uncertainties[idx, 0]) * 3600.0)
ades_ra = float(np.rad2deg(ades.optical_uncertainties[idx, 0]) * 3600.0)
print("ROW", idx, "VFCC17_RA", round(vfcc_ra, 3), "ADES_RA", round(ades_ra, 3))
ROW 7 VFCC17_RA 0.5 ADES_RA 0.384
ROW 8 VFCC17_RA 0.5 ADES_RA 0.765
ROW 9 VFCC17_RA 0.5 ADES_RA 0.382
These rows have reported ADES uncertainties, so the two policies do not match.
These row numbers come from the reference file saved on 2026-04-23. If you save a new file later, the row numbers may change.
3. Use InteractiveWeightPolicy¶
Use InteractiveWeightPolicy when you want one default policy and then a few changes.
Create InteractiveWeightPolicy with these parameters:
default_policyis required. It is the policy used for every row before any override is applied.additional_policiesis optional. Add other policies here if you wantselect_scheme(...)to switch rows to them.
InteractiveWeightPolicy provides these interfaces:
set_manual_optical(...)sets manual uncertainties for selected optical rows.set_manual_radar(...)sets a manual uncertainty for selected radar rows.select_scheme(...)switches selected rows to a registeredWeightPolicyfromdefault_policyoradditional_policies.restore_default_policy(...)removes overrides and returns selected rows to the default policy. If you do not passinput_index, it clears every override.
These interfaces select rows by input_index. input_index is the row number in the original observation file. You can get it from obs.optical.input_indices, obs.radar.input_indices, or obs.to_dataframe(sort_by="input"), as shown in Load Local ADES Observations.
Set Manual Uncertainties¶
The example below uses set_manual_optical(...). Use set_manual_radar(...) the same way for obs.radar rows, but pass one uncertainty value instead of ra_unc and dec_unc.
This example passes only default_policy, because manual uncertainties do not need any extra registered policy.
import numpy as np
from difforb.astrometry import load_local_observations, InteractiveWeightPolicy, VFCC17WeightPolicy
obs = load_local_observations("/tmp/2025bc10-online-guide.psv")
interactive = InteractiveWeightPolicy(default_policy=VFCC17WeightPolicy())
interactive.set_manual_optical(
[10],
ra_unc=np.deg2rad(1.0 / 3600.0),
dec_unc=np.deg2rad(1.5 / 3600.0),
)
result = interactive.weights(obs)
for idx in [9, 10]:
ra = float(np.rad2deg(result.optical_uncertainties[idx, 0]) * 3600.0)
dec = float(np.rad2deg(result.optical_uncertainties[idx, 1]) * 3600.0)
print("ROW", idx, "SOURCE", result.optical_sources[idx], "RA", round(ra, 3), "DEC", round(dec, 3))
ROW 9 SOURCE VFCC17 RA 0.5 DEC 0.5
ROW 10 SOURCE MANUAL RA 1.0 DEC 1.5
Row 10 now uses the manual uncertainties. Row 9 still uses VFCC17.
Select Another Policy¶
Use select_scheme(...) when you want matching rows to use another WeightPolicy.
This example selects all optical rows from station W74 on 2025-03-03. day and day_end define the time range. optical is the obs.optical table. mask selects the rows in that table that match both the time range and the station code. selected_rows are row positions inside the optical table. indices are input_index values from the original observation file.
This example passes additional_policies=[ades], because select_scheme(...) can only switch rows to a policy that was registered when InteractiveWeightPolicy was created.
import numpy as np
from difforb.astrometry import (
load_local_observations,
ADESWeightPolicy,
InteractiveWeightPolicy,
VFCC17WeightPolicy,
)
from difforb.core import Time
obs = load_local_observations("/tmp/2025bc10-online-guide.psv")
vfcc = VFCC17WeightPolicy()
ades = ADESWeightPolicy()
interactive = InteractiveWeightPolicy(default_policy=vfcc, additional_policies=[ades])
day = Time.from_ut_date(2025.0, 3.0, 3.0)
day_end = day + 1.0
optical = obs.optical
mask = np.asarray((optical.t >= day) & (optical.t < day_end)) & (optical.rx_codes == "W74")
selected_rows = np.flatnonzero(mask)
indices = optical.input_indices[selected_rows]
print("INDICES", indices)
interactive.select_scheme(indices, ades)
result = interactive.weights(obs)
for row in selected_rows:
input_index = int(optical.input_indices[row])
ra = float(np.rad2deg(result.optical_uncertainties[row, 0]) * 3600.0)
dec = float(np.rad2deg(result.optical_uncertainties[row, 1]) * 3600.0)
print(
"ROW", int(row),
"INPUT", input_index,
"SOURCE", result.optical_sources[row],
"RA", round(ra, 3),
"DEC", round(dec, 3),
)
INDICES [47 48 49 50 51]
ROW 47 INPUT 47 SOURCE ADES RA 0.037 DEC 0.042
ROW 48 INPUT 48 SOURCE ADES RA 0.038 DEC 0.046
ROW 49 INPUT 49 SOURCE ADES RA 0.035 DEC 0.046
ROW 50 INPUT 50 SOURCE ADES RA 0.034 DEC 0.046
ROW 51 INPUT 51 SOURCE ADES RA 0.036 DEC 0.041
4. Restore the default policy¶
When you no longer need the overrides, use restore_default_policy(...) to return rows to default_policy. If you call restore_default_policy() with no argument, it returns every row to default_policy.
interactive.restore_default_policy([7, 8, 9, 10])
Common Mistakes¶
- The override methods take
input_indexvalues from the original observation file, not row positions inside one table. ADESWeightPolicycan returnNaNfor rows with no reported uncertainty. Do not treat those rows as valid ADES-weight rows.set_manual_optical(...)expects radians, not arcseconds.WeightResultstores uncertainties. It also provides inverse-variance weights.
Next Steps¶
- Continue to Inspect Optical Debias Corrections when you also need catalog corrections for
/tmp/2025bc10-online-guide.psv. - Return to Load Local ADES Observations or Load Online Observations From MPC And JPL when you still need to adjust
/tmp/2025bc10-online-guide.psv. - Continue to Orbit Determination Workflow when you want to use the chosen policy in a full solve.
- Use the Weights API for details on weight policies and
WeightResult.