title: Resonant dipoles at various heights
slug: resonant_dipoles_at_various_heights
date: 2026-09-04 16:43:52 UTC+02:00
modified: 2026-09-05 20:51:23 UTC+02:00
type: text

## What is this? [🔗](#intro){.small} {: #intro}

This is a study of how the behavior of resonant half-wave dipoles
changes when height is changed.

This is intended to be an interesting read by itself for people
interested in antennas.  This also serves as part of the showcase for
my Python software
[antenna-simulation-driver](https://pypi.org/project/antenna-simulation-driver/),
in the following sense:

- This part shows one example of **what** can be done with that software.
  We hope it will be interesting for a general audience of people interested
  in short-wave antennas, who may or may not be programmers.
- There is an accompanying Jupyter notebook that tells you in detail
  **how** this was done.  That part is intended for people who are
  familiar with Python programming.  You want to look at the
  `antenna-simulation-driver` software's [showcase
  page](/antennas/antenna_simulation_driver_showcase/) if interested
  (maybe after briefly reading this first).

## Object of study [🔗](#object){.small} {: #object}

We study resonant half-wave dipoles at different heights from 2 m
above ground to 100 m above ground. We do so by running many antenna
simulations (via some NEC2 variant).

Each such dipole is resonant at 7100 kHz and consists of copper wire
with a diameter of 1 mm.

Dipoles are studied over two grounds: Average ground with dielectric
constant of 13 and conductivity of 0.005 S/m, and city ground with
dielectric constant of 3 and conductivity 0.001 S/m.

As a first step, it was determined that the resonant half-wave length
of a dipole built from such wire is 20.563 m in free space.

## Dipole length [🔗](#lengths){.small} {: #lengths}

It is well-known that height (somewhat) de-tunes antennas. Before
doing measurements for a resonant half-wave dipole at a certain
height, we first determine the precise length required for half-wave
resonance **at that height.**

Here is this relative length, in percent of the resonant length in free
space, depending on height, for average ground and city ground:

![Tow graphs. For numerical data, see below.](/images/2026/resonant_dipoles_length.png)
{.big}

For accessibility and general karma, here is an excerpt of the same
data as a textual table:

height/m | length avg | length city
---------|------------|------------
2.0 |99.20 |99.14
3.0 |99.21 |99.35
4.0 |99.10 |99.39
5.0 |98.91 |99.37
6.0 |98.78 |99.35
7.0 |98.73 |99.36
8.0 |98.75 |99.41
9.0 |98.86 |99.49
10.0 |99.03 |99.60
12.5 |99.64 |99.95
15.0 |100.26 |100.26
20.0 |100.69 |100.36
25.0 |99.96 |99.87
30.0 |99.52 |99.73
35.0 |99.93 |100.04
40.0 |100.36 |100.21
45.0 |100.12 |100.02
50.0 |99.74 |99.83
55.0 |99.86 |99.96
60.0 |100.19 |100.14
65.0 |100.16 |100.06
70.0 |99.86 |99.89
75.0 |99.84 |99.93
80.0 |100.10 |100.08
85.0 |100.16 |100.08
90.0 |99.94 |99.94
95.0 |99.85 |99.92
100.0 |100.04 |100.04

Each of the following graphs in this blog post assumes that at each
height, the half-wave dipole is used that **is resonant at that
height.**

## Sideline: computational effort [🔗](#effort){.small} {: #effort}

For people interested in a brief overview of the mechanics of these
calculations:

- 9 simulations were needed to establish 20.563 m as the resonant
  dipole length in free space, using the
  [toms748](https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.toms748.html)
  root finding algorithm from scipy.
- 441 data points went into each of the curves: 80 of those for the
  heights up to 10 m (every 0.1 m), 361 for the heights up to 100 m
  (every 0.25 m).
- The result of the simulations were 882 data records.  Each data
  record contains various values for the resonant dipoles at a certain
  height over one of the two grounds.  The graphs and tables in this
  present blog post expose different aspects of those 882 data points.
- Most antenna simulations were used to establish the resonant length
  at each height.  Length calculations were started from scratch at
  each height.  It would have been beneficial to optimize by using the
  result of nearby heights.  However, this was not done, but plain
  toms748 was thrown at the problem instead.  A total of 11670 antenna
  simulations were needed with this wasteful approach.  Spreading
  those over 4 cores (and 4 would-be cores, aka "hyperthreading")
  meant all of these simulations took a little less than 8 minutes.
  It was judged that coding the optimization would have slowed down
  proceedings.
  
## Loss [🔗](#loss){.small} {: #loss}

Loss changes with height.  We map combined wire and ground loss, again
for both average and city ground, measured in dB.

![Two graphs. For numerical data, see below.](/images/2026/resonant_dipoles_loss.png)
{.big}

For accessibility and general karma, here is an excerpt of the same
data as a textual table:

height/m | avg |city
-|-|-
2.0 |7.8 |6.9
3.0 |5.7 |5.6
4.0 |4.1 |4.6
5.0 |3.1 |3.8
6.0 |2.4 |3.3
7.0 |2.0 |2.9
8.0 |1.7 |2.5
9.0 |1.4 |2.3
10.0 |1.3 |2.2
12.5 |1.1 |1.9
15.0 |1.1 |1.9
20.0 |1.3 |2.1
25.0 |1.4 |2.1
30.0 |1.3 |1.9
35.0 |1.1 |1.8
40.0 |1.1 |1.9
45.0 |1.3 |2.0
50.0 |1.2 |1.9
55.0 |1.1 |1.8
60.0 |1.1 |1.8
65.0 |1.2 |1.9
70.0 |1.2 |1.9
75.0 |1.2 |1.8
80.0 |1.1 |1.8
85.0 |1.2 |1.9
90.0 |1.2 |1.9
95.0 |1.2 |1.9
100.0 |1.1 |1.8

## Dipole impedance [🔗](#z){.small} {: #z}

Dipole impedance also varies with height.

As we exclusively deal with *resonant* dipoles, all impedances are
purely ohmic, in other words, there is no capacitive or inductive
component, or, in still other words, the impedance has no imaginary
part.

![Two graphs. For numerical data, see below.](/images/2026/resonant_dipoles_impedance.png)
{.big}

For accessibility and general karma, here is an excerpt of the same
data as a textual table:

height/m | Z/Ω avg | Z/Ω city
---------|---------|---------
2.0 |57.5 |80.9
3.0 |54.0 |73.9
4.0 |53.4 |71.6
5.0 |56.2 |71.4
6.0 |60.7 |72.6
7.0 |66.1 |74.6
8.0 |71.7 |76.9
9.0 |77.1 |79.2
10.0 |81.8 |81.1
12.5 |89.4 |83.5
15.0 |89.3 |81.9
20.0 |74.0 |72.3
25.0 |64.3 |68.6
30.0 |72.9 |75.1
35.0 |81.4 |78.7
40.0 |76.9 |74.8
45.0 |69.3 |71.1
50.0 |71.6 |73.5
55.0 |78.0 |76.9
60.0 |77.4 |75.6
65.0 |71.8 |72.5
70.0 |71.4 |73.0
75.0 |76.1 |75.8
80.0 |77.3 |75.8
85.0 |73.3 |73.4
90.0 |71.6 |73.0
95.0 |74.9 |75.1
100.0 |77.0 |75.8


## Gain for a DX QSO [🔗](#dx_gain){.small} {: #dx_gain}

For DX QSOs, flat radiation is generally beneficial.  Ground gain
helps, too, which is very height-dependent.

We somewhat arbitrarily assume the ionosphere has an apparent height
of 400 km, and we'll reach that DX station if the first hop carries
our signals back to ground 2000 km from home.

For this, our radio waves need to be emitted at an elevation of 17°
above the horizon.  So we ask our antenna simulation: What is the
directional gain at that elevation, in dBi? We are interested in the
"best" direction, perpendicular to the dipole wire.  And we want to
know directional gain depending on antenna height.

Here is the result:

![Two graphs. For numerical data, see below.](/images/2026/resonant_dipoles_dx_gain.png)
{.big}

For accessibility and general karma, here is an excerpt of the same
data as a textual table:

Height/m | dBi avg | dBi city
-|-|-
2.0 |-9.2 |-7.1
3.0 |-6.6 |-5.4
4.0 |-4.7 |-4.1
5.0 |-3.4 |-3.0
6.0 |-2.5 |-2.2
7.0 |-1.7 |-1.4
8.0 |-1.1 |-0.7
9.0 |-0.5 |-0.1
10.0 |0.0 |0.4
12.5 |1.4 |1.7
15.0 |2.7 |3.0
20.0 |5.4 |5.2
25.0 |7.2 |6.4
30.0 |7.3 |6.6
35.0 |7.1 |6.6
40.0 |7.2 |6.6
45.0 |7.0 |6.1
50.0 |5.8 |4.8
55.0 |3.7 |2.8
60.0 |1.0 |0.1
65.0 |-3.1 |-4.1
70.0 |-12.9 |-9.7
75.0 |-8.5 |-5.7
80.0 |-1.5 |-0.8
85.0 |2.4 |2.4
90.0 |4.8 |4.5
95.0 |6.0 |5.6
100.0 |6.8 |6.4

## NVIS gain [🔗](#nvis_gain){.small} {: #nvis_gain}

Not everybody is interested in far-away DX stations.  For the
opposite, "nearly vertical incident skywave" NVIS, we need radiation
straight up.

Again, the gain in that direction depends on antenna height.  Here is
the data:

![Two graphs. For numerical data, see below.](/images/2026/resonant_dipoles_nvis_gain.png)
{.big}

For accessibility and general karma, here is an excerpt of the same
data as a textual table:

height/m | dBi avg | dBi city
-|-|-
2.0 |-0.0 |0.3
3.0 |2.4 |1.8
4.0 |4.0 |2.8
5.0 |5.0 |3.6
6.0 |5.6 |4.1
7.0 |5.9 |4.4
8.0 |6.0 |4.5
9.0 |6.0 |4.4
10.0 |5.8 |4.3
12.5 |4.9 |3.4
15.0 |3.0 |1.6
20.0 |-6.5 |-1.9
25.0 |3.1 |3.0
30.0 |6.3 |4.7
35.0 |4.4 |2.7
40.0 |-3.8 |-1.9
45.0 |1.0 |1.8
50.0 |6.0 |4.7
55.0 |5.3 |3.6
60.0 |-1.0 |-1.0
65.0 |-1.7 |0.5
70.0 |5.5 |4.4
75.0 |5.9 |4.2
80.0 |1.3 |0.2
85.0 |-4.8 |-0.8
90.0 |4.6 |3.9
95.0 |6.2 |4.5
100.0 |3.0 |1.4

## Other sources [🔗](#other_sources){.small} {: #other_sources}

This ends the study of resonant half-wave dipoles of different heights.

It was done using my Python software
[antenna-simulation-driver](https://pypi.org/project/antenna-simulation-driver/),
available via Pypi.  That software does not have all "batteries
included", it needs `nec2++` to be installed.  See the software's
[README](https://gitlab.com/4ham/antenna_simulation_driver/-/blob/main/README.md?ref_type=heads)
for details.

This text you just read is intended as a good, convenient entrance to
get to know one of the things the `antenna-simulation-driver` software
can do.  If you want to know how it was done, you are invited to
download, read, and maybe run the [Jupyter notebook
source](/antennas/resonant-dipoles/index.ipynb) that produced the
graphs and numbers (recommended name `resonant_dipoles.ipynb`).  The
showcase page has [instructions how to view and maybe
run](/antennas/antenna_simulation_driver_showcase/#jupyter).  It also
has further examples of what else can be done with the software.

For a first glance into how this height parameter study was done, you
can also try a [pre-rendered
version](/antennas/resonant-dipoles/index.ipynb) of the notebook.  I
find the formatting rather crappy, so I don't fully recommend it.

### Details, for the record [🔗](#gory_details){.small} {: #gory_details}

The study was organized as a Jupyter notebook, so besides Python 3.13,
we used the "usual suspects" installed with `pip`:

```
numpy
notebook
pandas
matplotlib
scipy
```

In case you need to know (you probably don't), the versions of those
pieces of software and the dependencies pulled in by them were, in
`requirements.txt` format:

```
antenna-simulation-driver==0.3.0
anyio==4.14.2
argon2-cffi==25.1.0
argon2-cffi-bindings==25.1.0
arrow==1.4.0
asttokens==3.0.2
async-lru==2.3.0
attrs==26.1.0
babel==2.18.0
beautifulsoup4==4.15.0
bleach==6.4.0
certifi==2026.7.22
cffi==2.1.1
charset-normalizer==3.5.1
comm==0.2.3
contourpy==1.3.3
cycler==0.12.1
debugpy==1.8.21
decorator==5.3.1
defusedxml==0.7.1
executing==2.2.1
fastjsonschema==2.22.2
fonttools==4.63.0
fqdn==1.5.1
h11==0.16.0
httpcore==1.0.9
httpx==0.28.1
idna==3.19
ipykernel==7.3.0
ipython==9.16.1
ipython-pygments-lexers==1.1.1
isoduration==20.11.0
jedi==0.20.0
jinja2==3.1.6
json5==0.15.0
jsonpointer==3.1.1
jsonschema==4.26.0
jsonschema-specifications==2025.9.1
jupyter-builder==1.2.2
jupyter-client==8.9.1
jupyter-core==5.9.1
jupyter-events==0.12.1
jupyter-lsp==2.3.1
jupyter-server==2.20.0
jupyter-server-terminals==0.5.4
jupyterlab==4.6.3
jupyterlab-pygments==0.3.0
jupyterlab-server==2.28.0
kiwisolver==1.5.0
lark==1.3.1
markupsafe==3.0.3
matplotlib==3.11.1
matplotlib-inline==0.2.2
mistune==3.3.4
nbclient==0.11.0
nbconvert==7.17.1
nbformat==5.11.1
nest-asyncio2==1.7.2
notebook==7.6.2
notebook-shim==0.2.4
numpy==2.5.2
packaging==26.3
pandas==3.0.5
pandocfilters==1.5.1
parso==0.8.7
pexpect==4.9.0
pillow==12.3.0
platformdirs==4.11.3
prometheus-client==0.26.0
prompt-toolkit==3.0.53
psutil==7.2.2
ptyprocess==0.7.0
pure-eval==0.2.3
pycparser==3.0
pygments==2.21.0
pyparsing==3.3.2
python-dateutil==2.9.0.post0
python-json-logger==4.2.0
pyyaml==6.0.3
pyzmq==27.1.0
referencing==0.37.0
requests==2.34.2
rfc3339-validator==0.1.4
rfc3986-validator==0.1.1
rfc3987-syntax==1.1.0
rpds-py==2026.6.3
scipy==1.18.0
send2trash==2.1.0
setuptools==82.0.1
six==1.17.0
soupsieve==2.9.2
stack-data==0.6.3
terminado==0.18.1
tinycss2==1.5.1
tornado==6.5.8
traitlets==5.16.1
typing-extensions==4.16.0
tzdata==2026.3
uri-template==1.3.0
urllib3==2.7.0
wcwidth==0.8.2
webcolors==25.10.0
webencodings==0.6.1
websocket-client==1.9.0
```

## Discussion opportunity  [🔗](#comments){.small} {: #comments}

If you want to comment or discuss this piece and have a Fediverse
account, feel invited to answer [my pertinent
toot](https://mastodon.radio/@dj3ei/117219768253058390).


