Paper · 2026-02-03 · cs.CV
Dynamic High-frequency Convolution for Infrared Small Target Detection
DHiF replaces the standard convolution in infrared small target detectors. Each location gets its own k x k filter bank, generated from the local patch and bounded by tanh. The filtered response is added to the input before a standard convolution. Author-reported: IoU rises over standard convolution in all 7 tested networks on both datasets, e.g. DNANet on NUAA-SIRST goes from 71.97 to 77.68.
Dynamic convolutionConvolutional neural networkSemantic segmentationinfrared-small-target-detectionconvolutiondynamic-filtershigh-frequency
arXivPDFCodeMarkdown14 min read
AI-compiled by claude-haiku-5-5 on 2026-11-06, not yet reviewed by a human. Every claim cites its source; check it when a detail matters.
In plain words
Infrared pictures can hide a tiny bright target, but they also contain many other sharp bright spots and edges, such as bright corners and broken clouds. Detectors have to tell the target apart from these look-alikes. Most networks learn one fixed set of small filters and use it everywhere in the picture.
This paper changes one building block of such networks, the ordinary convolution, so that its filters adapt to each spot. At every location, a small learned step looks at the nearby pixels and writes out its own bank of filters for that spot. The values in those filters are kept inside a range centred on zero, which suits the sharp brightness changes the detector needs to pick up. The filtered result is added to the original pixels, and then an ordinary convolution runs as usual.
The new block is a drop-in replacement, so it can be placed into existing detectors without redesigning them. According to the authors, detection improves across the networks they tried, at a small cost in speed.
TL;DR
- DHiF is a convolution whose k x k filters are generated per location from the local input, bounded to (-1, 1) by tanh §II-B.3 eq. 5 eq. 6.
- The generated filters are applied to the local patch, and the sum of the patch and its filtered version feeds a standard convolution §II-B.3 eq. 7 eq. 8.
- Author-reported: in the encoders of seven SIRST networks on IRSTD-1K and NUAA-SIRST, DHiF beats the standard convolution on IoU in every case tab. 1.
- The paper's motivation for the zero-centred range relies on Fourier-property arguments §II-B.2 eq. 3 eq. 4; the code enforces the range only, not the zero-sum property the argument mentions.
- Code exists and is linked from the paper. Its normalisation of the generator input and its layer placement differ from the paper's description (see Paper vs code).
Problem
Single-frame infrared small target (SIRST) detection must separate tiny, locally salient targets from clutter. Both targets and clutter (bright corners, broken clouds, other fragments) are high-frequency components of the image, and they share similar local contrast §I. Traditional methods use hand-made, fixed-parameter operators such as local contrast measures and top-hat transforms, which do not adapt well across scenes §I. Learned detectors fit features from annotated data, but the paper argues they do not explicitly model or discriminate the different high-frequency categories inside local regions §I §II-A. The method assumes the detector is built from convolutional layers: DHiF is designed for networks with convolutional structures §IV [supp. §IV].
Method
DHiF keeps the usual sliding window of a convolution and adds a second, local path. For each window it (a) normalises the local input, (b) generates a bank of k^2 filters, one per tap, each of length k^2, via a linear projection followed by tanh, (c) applies that bank to the local patch of every channel, (d) adds the result to the original patch, and (e) runs a standard convolution over the sum §II-B.1 §II-B.3.
The filter-sensitivity argument is as follows. The paper notes that a derivative in the spatial domain corresponds to multiplying by jω in the Fourier domain eq. 3, and that a constant (DC) offset adds an impulse at zero frequency eq. 4. From this it concludes that filter kernels should contain positive and negative values, with a sum close to zero, to respond to high frequencies rather than to flat regions §II-B.2. The paper implements this by restricting each kernel entry to an interval centred at zero §II-B.2.
The DHiF operation, as written in the paper:
- Local feature vector. For each window, flatten the normalised single-channel local map to length k^2. The paper describes this as a normalisation layer applied to the input features; the method of normalisation is not specified §II-B.3.
- Filter generation. A linear projection maps the k^2 values to k^2 vectors of length k^2. Each entry is passed through tanh §II-B.3 eq. 5 eq. 6.
\boldsymbol{v}_1, \dots, \boldsymbol{v}_{k^2} = \rho\big(\mathrm{vec}(\boldsymbol{F}^{local}_{norm})\big) eq. 5
\boldsymbol{W}_{f_1}, \dots, \boldsymbol{W}_{f_{k^2}} = \theta(\boldsymbol{v}_1, \dots, \boldsymbol{v}_{k^2}), \quad \theta = \tanh eq. 6
- Filtering. Flatten the C-channel local input to C x k^2. Multiply it by the k^2 x k^2 filter matrix W_f. The same bank is applied to every channel §II-B.3 eq. 7.
\boldsymbol{F}^{local}_{filt} = \mathrm{vec}(\boldsymbol{F}^{local}_{in}) \, \boldsymbol{W}_{\boldsymbol{f}} eq. 7
- Output. Add the flattened input to the filtered features, multiply element-wise by the weights of each of the C' output filters, and sum. Each output filter has shape C x k^2 §II-B.3 eq. 8.
\boldsymbol{F}^{local}_{out}[j] = \sum_{1}^{k^2} \Big( \big( \mathrm{vec}(\boldsymbol{F}^{local}_{in}) + \boldsymbol{F}^{local}_{filt} \big) \odot \boldsymbol{W}_j \Big) eq. 8
Equation 8 writes the sum over k^2 only; the weights W_j have shape C x k^2, so the sum also runs over channels (see Paper vs code).
Repeating these steps for every window gives the output map §II-B.3. The paper calls the block a drop-in replacement for standard convolution in SIRST networks §II-B.3 §III-B. In the residual block, DHiF replaces the first convolution, and the DHiF-Res block is defined as follows [supp. §II-B] [supp. eq. 1].
\mathrm{Res}_{DHiF}(\boldsymbol{X}) = \sigma\Big( \kappa(\boldsymbol{X}) + \gamma\big( \sigma( DHiF(\boldsymbol{X}) ) \big) \Big) [supp. eq. 1]
Here DHiF(·) includes its batch-norm layer, γ is a standard convolution followed by batch norm, σ is the activation and κ the shortcut [supp. §II-B].
The DHiF-Res block in pseudocode, from the supplementary equation:
# DHiF-Res block [supp. eq. 1] [supp. §II-B]
# Input and output: features (B, C, H, W)
def dhif_res_block(inputs, dhif_layer, conv, bn_out):
# Shortcut kappa; the paper leaves its form open (see Pitfalls)
shortcut = shortcut_path(inputs)
# DHiF, then batch norm, then activation [supp. eq. 1]
hidden = relu(dhif_layer(inputs))
# Standard convolution, then batch norm [supp. eq. 1]
hidden = bn_out(conv(hidden))
# Add the shortcut and apply the activation [supp. eq. 1]
return relu(shortcut + hidden)The DHiF forward pass in pseudocode, from eq. 5 to eq. 8:
# DHiF forward pass for one input map [§II-B.3] [eq. 5]-[eq. 8]
# Input: features (B, C, H, W); kernel size k
# Output: features (B, C_out, H, W)
def dhif(features, k, linear, conv_weight):
# Gather the k x k neighbourhood of every location [§II-B.3]
patches = unfold(features, k) # (B, C, H, W, k*k)
# Reduce the channels to one normalised value per tap [§II-B.3]
# (paper: normalisation layer; code: L2 norm, see Paper vs code)
local = channel_norm(patches) # (B, H, W, k*k)
# Project to k*k filter vectors of length k*k [eq. 5]
projected = linear(local) # (B, H, W, k*k, k*k)
# Bound every filter entry to (-1, 1) with tanh [eq. 6] [§II-B.2]
filters = tanh(projected) # (B, H, W, k*k, k*k)
# Apply each location's filter bank to every channel [eq. 7]
filtered = apply_bank(patches, filters) # (B, C, H, W, k*k)
# Add the local input to the filtered response [eq. 8]
combined = patches + filtered # (B, C, H, W, k*k)
# Standard weights over channels and taps [eq. 8]
return weighted_sum(combined, conv_weight) # (B, C_out, H, W)Hyperparameters
Values from the paper and its supplementary material, with the official code where the paper is silent. Code values are facts about the repository at code_commit, not statements by the authors.
| Name | Value | Where | Notes |
|---|---|---|---|
| kernel size k | 3 | [supp. §III-D.2] model_DNANet.py | k = 5 and 7 tested, not better [supp. tab. II] |
| filter generator | linear k^2 -> k^4, then tanh | §II-B.3 basic.py | No hidden layer. Generator has bias in code (PyTorch default); paper does not say basic.py |
| non-linearity on filters | tanh | §II-B.2 [supp. §III-D.3] basic.py | GELU, LeakyReLU and Sigmoid all trail standard conv on IoU [supp. tab. III] |
| DHiF position in block | first conv of residual block, before the standard conv | [supp. §II-B] [supp. §III-D.1] | Standard then DHiF: IoU 74.55 vs 77.68 [supp. tab. I] |
| DHiF levels in DNANet | paper: levels 2 to 5 in table, levels 2 and 3 in text; code: levels 2 and 3 | §III-C.1 §III-C.2 model_DNANet.py | See Paper vs code |
| weight init, DHiF conv | PyTorch kaiming_uniform with a = sqrt(5) | basic.py | Paper: "Kaiming method" [supp. §III-B]. See Paper vs code |
| optimizer | Adam, lr 5e-4 | [supp. §III-B] train.py | |
| lr schedule | multiply by 0.5 "after every 50 epochs" | [supp. §III-B] train.py | Code: MultiStepLR at epochs 100, 150, ..., 500, gamma 0.5 train.py |
| epochs | 500 | [supp. §III-B] train.py | |
| batch size | 16 | [supp. §III-B] train.py | |
| training crop | 256 x 256 | [supp. §III-B] train.py dataset.py | Random crop per sample |
| augmentation | not stated | dataset.py dataset.py | Code: random vertical flip, horizontal flip, transpose, each p = 0.5 |
| input normalisation | per dataset: NUAA-SIRST mean 101.06, std 34.62; IRSTD-1K mean 87.47, std 39.72 | utils.py | Not in paper |
| loss | not stated | net.py loss.py | Code: soft IoU loss, averaged over deep-supervision outputs for DNANet |
| deep supervision | not stated | model_DNANet.py model_DNANet.py | Code default True; returns a list of 4 outputs during training |
| binarisation threshold | 0.5 | train.py | Not in paper |
| random seed | not stated | train.py | Code default 1337 |
| metrics | IoU, nIoU, P_d, F_a | §III-A [supp. §III-A] | IoU, nIoU, P_d in units of 10^-2; F_a in units of 10^-5 §III-A |
| datasets | IRSTD-1K: 1001 images, 512 x 512, 800 train and 201 test. NUAA-SIRST: 427 images, 213 train and 214 test | [supp. §III-B] | Text says "IRSDT-1k"; tables and code say "IRSTD-1K" §III-A |
| hardware | Intel Xeon Gold 6328H, 2 x Tesla V100 PCIe 32 GB | [supp. §III-B] |
Results
Author-reported. Setup: IRSTD-1K and NUAA-SIRST, seven SIRST networks split into CNN (FC3Net, DNANet, ISNet, MSHNet) and CNN-Transformer hybrid (MTU-Net, SCTransNet, APTNet) §III-B tab. 1. Each row is the same network with the encoder convolutions replaced. The table below gives the standard convolution and DHiF rows; the other replacements (CDC, WTConv, PConv) are in tab. 1. The paper does not state the number of runs or any variance.
| Network | Conv | IRSTD-1K IoU | nIoU | P_d | F_a | NUAA IoU | nIoU | P_d | F_a |
|---|---|---|---|---|---|---|---|---|---|
| FC3Net | Standard | 60.12 | 59.36 | 89.23 | 4.73 | 31.09 | 30.30 | 94.27 | 30.19 |
| FC3Net | DHiF | 62.10 | 61.08 | 91.25 | 2.49 | 71.33 | 72.54 | 94.27 | 3.77 |
| DNANet | Standard | 63.27 | 63.56 | 88.55 | 1.25 | 71.97 | 78.66 | 95.04 | 6.31 |
| DNANet | DHiF | 69.42 | 65.68 | 90.57 | 1.38 | 77.68 | 79.03 | 95.42 | 1.53 |
| ISNet | Standard | 62.38 | 62.25 | 89.90 | 3.27 | 71.10 | 72.88 | 95.04 | 5.52 |
| ISNet | DHiF | 68.08 | 63.90 | 90.91 | 2.92 | 72.57 | 75.27 | 93.13 | 3.89 |
| MSHNet | Standard | 63.56 | 64.79 | 89.90 | 1.22 | 76.98 | 77.04 | 95.80 | 1.97 |
| MSHNet | DHiF | 65.15 | 65.50 | 90.91 | 1.10 | 77.07 | 76.13 | 96.56 | 1.08 |
| MTU-Net | Standard | 64.78 | 64.53 | 88.22 | 1.51 | 75.73 | 78.71 | 94.66 | 3.09 |
| MTU-Net | DHiF | 65.56 | 65.50 | 89.23 | 1.54 | 77.12 | 79.19 | 94.66 | 2.48 |
| SCTransNet | Standard | 64.05 | 65.10 | 90.24 | 2.27 | 77.97 | 79.39 | 95.04 | 2.86 |
| SCTransNet | DHiF | 65.58 | 65.47 | 92.59 | 2.17 | 78.83 | 79.40 | 96.56 | 2.60 |
| APTNet | Standard | 63.18 | 63.89 | 88.22 | 1.02 | 75.08 | 77.57 | 96.95 | 3.22 |
| APTNet | DHiF | 65.25 | 64.17 | 89.23 | 1.92 | 77.79 | 78.29 | 96.95 | 1.63 |
Source: tab. 1. Units: IoU, nIoU, P_d in 10^-2; F_a in 10^-5 §III-A.
Competing replacements, as the paper reports them tab. 1: CDC, WTConv and PConv each lower IoU below standard in some networks. On NUAA-SIRST the paper says all other replacements, except DHiF, cause severe drops in most networks §III-B. PConv in SCTransNet fails to converge (IoU 0.04 on IRSTD-1K) and is reported with a footnote tab. 1.
Placement of DHiF in the DNANet encoder, on NUAA-SIRST tab. 2:
| Replaced level | IoU | nIoU | P_d | F_a | FPS | #Params |
|---|---|---|---|---|---|---|
| none | 71.97 | 78.66 | 95.04 | 6.31 | 8.53 | 18346 K |
| 1st (1 block) | 72.95 | 77.77 | 94.66 | 4.89 | 8.43 | 18349 K |
| 2nd (2 blocks) | 78.37 | 79.29 | 96.18 | 3.32 | 8.05 | 18352 K |
| 3rd (2 blocks) | 77.02 | 78.99 | 95.42 | 2.57 | 8.42 | 18352 K |
| 4th (2 blocks) | 77.19 | 78.01 | 96.18 | 2.68 | 8.47 | 18352 K |
| 5th (2 blocks) | 75.48 | 79.10 | 96.18 | 3.86 | 8.51 | 18352 K |
Kernel size on NUAA-SIRST [supp. tab. II]:
| Kernel size | Convs | IoU | nIoU | P_d | F_a |
|---|---|---|---|---|---|
| 3 | Standard | 71.97 | 78.66 | 95.04 | 6.31 |
| 3 | DHiF | 77.68 | 79.03 | 95.42 | 1.53 |
| 5 | Standard | 72.36 | 77.55 | 93.51 | 3.49 |
| 5 | DHiF | 76.87 | 78.86 | 94.27 | 1.58 |
| 7 | Standard | 74.17 | 77.26 | 93.13 | 1.26 |
| 7 | DHiF | 76.80 | 79.02 | 94.27 | 1.06 |
Non-linearity on NUAA-SIRST [supp. tab. III]:
| Mapping | IoU | nIoU | P_d | F_a |
|---|---|---|---|---|
| None | 71.81 | 75.58 | 91.98 | 2.94 |
| GELU | 71.12 | 77.02 | 93.75 | 3.86 |
| LeakyReLU | 72.92 | 76.84 | 93.51 | 1.48 |
| Sigmoid | 72.25 | 78.28 | 93.89 | 4.13 |
| Tanh | 77.68 | 79.03 | 95.42 | 1.53 |
Block structure on NUAA-SIRST [supp. tab. I]:
| Structure | IoU | nIoU | P_d | F_a |
|---|---|---|---|---|
| DHiF + standard | 77.68 | 79.03 | 95.42 | 1.53 |
| standard + DHiF | 74.55 | 77.97 | 93.13 | 1.38 |
Cost, DNANet at 512 x 512 [supp. tab. IV]:
| Convs | #Params | FPS | Runtime (s) |
|---|---|---|---|
| Standard | 17.92 M | 8.61 | 0.1161 |
| CDC | 17.92 M | 8.60 | 0.1163 |
| WTConv | 17.60 M | 8.57 | 0.1167 |
| PConv | 17.78 M | 8.43 | 0.1186 |
| DHiF | 17.93 M | 8.02 | 0.1247 |
Salt-and-pepper noise, DNANet variants [supp. tab. V]:
| Convs | IoU | nIoU | P_d | F_a |
|---|---|---|---|---|
| Standard | 66.48 | 70.45 | 89.69 | 6.52 |
| CDC | 67.56 | 72.03 | 91.22 | 5.86 |
| WTConv | 69.00 | 71.12 | 88.55 | 3.00 |
| PConv | 66.89 | 70.21 | 88.55 | 4.56 |
| DHiF | 72.08 | 72.82 | 92.37 | 2.66 |
Qualitative results and feature visualisations are shown in fig. 3 and in the supplement [supp. fig. 3] [supp. fig. 4]. The paper says the visualisation shows DHiF producing negative responses inside bright-clutter regions and positive responses along edges §III-C.2 fig. 3.
Paper vs code
Searched: the paper's own text and abstract link https://github.com/TinaLRJ/DHiF (the owner name matches the first author's homepage, linked in the author biography of the paper). Owner is the first author, so it qualifies as official. Cloned at commit 06862c844bc16a3b5ee0d0019e5ae24f0f1bb4e7. The repository has no LICENSE file, and its README is a single title line README.md. Nothing was quoted from the code. The code of DHiF is in model/basic.py, and the networks that use it are under model/.
- Generator input normalisation. Paper: a normalisation layer on the single-channel input map, then flatten and project §II-B.3 eq. 5. Code: no normalisation layer in DHiF. The generator input is the L2 norm over channels of each k x k patch basic.py. Results depend on this choice, and the paper does not name its normalisation.
- Output sum. Paper: sum over k^2 only eq. 8. Code: the weighted sum runs over channels and taps basic.py. The weight W_j has shape C x k^2, so the code is consistent with the shape the paper gives.
- Generator structure. Paper: linear projection then tanh eq. 5 eq. 6. Code: one
nn.Linear(k*k, (k*k)*(k*k))followed byTanhbasic.py. The reshape to k^2 x k^2 matches the paper. The code has a bias; the paper does not mention one. - Shortcut and attention in the DNANet block. Paper's block equation has a shortcut and no attention [supp. eq. 1]. Code: the DNANet DHiF block applies channel attention and spatial attention (CBAM) after the second batch norm, before the residual addition model_DNANet.py. The baseline DNANet block uses the same attention model_DNANet.py. The shortcut is a 1x1 convolution plus batch norm when shapes change model_DNANet.py; the paper leaves κ unspecified.
- Layer placement in DNANet. Paper: replacements in encoder levels 2 to 5 for the table; levels 2 and 3 in the main experiments §III-C.1 §III-C.2 tab. 2. Code: DHiF is used only in
conv1_0andconv2_0, i.e. encoder levels 2 and 3 model_DNANet.py. - Input-layer use in ISNet. Paper: DHiF at the input layer provides no gain and reduces P_d; the paper advises replacing encoder hidden layers §III-C.1. Code: the ISNet stem convolution becomes DHiF when
conv == 'DHiF'model_ISNet.py. The paper does not say whether the ISNet rows of tab. 1 used this stem. - Learning-rate schedule. Paper: decay by 0.5 after every 50 epochs [supp. §III-B]. Code:
MultiStepLRwith milestones 100, 150, ..., 500 and gamma 0.5 train.py. The first decay is at epoch 100, not 50. - Initialisation. Paper: Kaiming initialisation for the convolution layers [supp. §III-B]. Code: DHiF's weight uses PyTorch's
kaiming_uniform_with a = sqrt(5) basic.py, which is the PyTorch default forConv2dand not the He initialisation the paper cites. The helperweights_init_kaimingexists inutils.pyutils.py, but a search of the training path found no call to it. - Loss and deep supervision. Paper: no loss stated. Code: soft IoU loss loss.py net.py. DNANet has deep supervision on by default and returns four outputs in training model_DNANet.py model_DNANet.py. The paper does not mention either.
- Augmentation. Paper: no augmentation stated. Code: random crop, then random flips and transpose with probability 0.5 each dataset.py dataset.py.
- Checkpoint and threshold. Paper: not stated which checkpoint is reported. Code: saves a checkpoint at the final epoch train.py and tests with threshold 0.5 train.py.
- Dataset name. Text: "IRSDT-1k". Tables and code: "IRSTD-1K" §III-A utils.py.
- Compute cost. Supplement: "introduces only 0.01 MB new parameters". Table: the parameter counts are in M, and the difference is 0.01 M [supp. tab. IV]. The unit in the text is wrong.
No discrepancies found in the DHiF filter equations beyond those listed above: the generator, the tanh bound and the filtering step match eq. 5-eq. 7 basic.py basic.py.
Pitfalls
- Normalisation is unspecified. The paper names a normalisation layer for the generator input but does not define it. The code uses an L2 norm over channels with no learned or batch normalisation basic.py. An implementer must choose; the code's choice is the only one tested.
- Zero-centred range is a bound, not a sum constraint. The argument for sensitivity to high frequencies asks for kernels with a sum close to zero §II-B.2. The implementation only bounds each entry to (-1, 1) with tanh eq. 6. Nothing enforces zero sum or symmetry. The supplement's non-linearity ablation shows that removing tanh hurts [supp. tab. III], but it does not test the zero-sum property directly.
- Compute and memory per pixel. Each location builds a k^2 x k^2 filter bank regardless of channel count basic.py, so filter tensors scale with H x W x k^4. The unfold step materialises a k^2 copy of the feature map basic.py. The paper reports 8.61 to 8.02 FPS for DNANet (6.85% slower) [supp. tab. IV], but nothing on peak memory.
- Level-ablation table is ambiguous. tab. 2 lists one row per level, but the caption and text do not say whether other levels were also replaced. The main configuration (levels 2 and 3 §III-C.2) gives 77.68 IoU in tab. 1 and [supp. tab. II], which matches no single row of tab. 2. The text's "2nd to 5th" claim is an average across rows §III-C.1.
- Input layer is not recommended. The paper finds that DHiF on the input layer reduces P_d §III-C.1, but the ISNet code puts DHiF in the stem model_ISNet.py. Do not copy the ISNet stem without a test.
- Sum notation in equation 8. The sum is written over k^2 only, but the weights have shape C x k^2. An implementer following the equation literally would sum over the wrong axis; sum over channels and taps, as the code does basic.py.
- Outliers and failures. FC3Net with standard convolution on NUAA-SIRST has IoU 31.09 and F_a 30.19, far below the other networks tab. 1; the paper gives no explanation. PConv in SCTransNet does not converge tab. 1.
- Single numbers with no variance. The paper does not say how many training runs back each number, or whether the reported checkpoint was chosen on the test set (NUAA-SIRST has train and test splits only [supp. §III-B]). Differences of 1 to 2 IoU points between rows should be read with that in mind.
- Attention is part of the block in code. An implementation that follows [supp. eq. 1] alone may not reproduce the code's DNANet numbers; the code was not run here, so this is a risk, not a measured gap. The CBAM attention is in both the standard and DHiF blocks model_DNANet.py.
- Units in the complexity text. "0.01 MB new parameters" in the supplement should read 0.01 M parameters [supp. tab. IV].
Lineage
- Builds on: the residual block [he2016deep] as the place where DHiF is inserted, and DNANet [li2022dense] as the main test network. The paper gives no arXiv ids for either. Also related: fixed local-contrast and pixel-difference operators such as ALCNet and PDC, which the paper contrasts with its learned, per-location filters [supp. §I-B].
- Compared against: CDC (MDIGCNet, IEEE JSTARS 2024), WTConv (wavelet convolutions, ECCV 2024) and PConv (pinwheel-shaped convolution, AAAI 2025) tab. 1. None has an arXiv id in the paper's bibliography, so none is linked here.
- Superseded by: not known.
Source and license
Adapted from “Dynamic High-frequency Convolution for Infrared Small Target Detection” by Ruojing Li, Chao Xiao, Qian Yin, Wei An, Nuo Chen, Xinyi Ying, Miao Li, Yingqian Wang (arXiv:2602.02969), used under CC BY 4.0. Changes: condensed and restructured for implementation, with tables, equations and algorithms taken from the paper and its code, each cited to its source. Not affiliated with or endorsed by the authors. Code citations refer to https://github.com/TinaLRJ/DHiF at commit 06862c844bc1 (not stated (no LICENSE file in repository)). Any quoted code is shown under that license.