Skip to content

Commit 1314027

Browse files
authored
Update antennaizer.html
1 parent b54391f commit 1314027

File tree

1 file changed

+120
-48
lines changed

1 file changed

+120
-48
lines changed

antennas/antennaizer.html

Lines changed: 120 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<head>
55
<meta charset="UTF-8">
66
<meta name="viewport" content="width=device-width, initial-scale=1.0">
7-
<title>Advanced Wire Antenna Designer</title>
7+
<title>Experimental Antenna Calculator</title>
88
<style>
99
body {
1010
font-family: Arial, sans-serif;
@@ -83,8 +83,8 @@
8383
</style>
8484
</head>
8585
<body>
86-
<h1>Advanced Wire Antenna Designer</h1>
87-
86+
<h1>Experimental Antenna Calculator</h1>
87+
<p>This is an experemental antenna calculation tool written largely by Generative AI. Use at your own risk.</p>
8888
<div class="section">
8989
<h2>Input Parameters</h2>
9090
<div id="targetBands">
@@ -185,6 +185,7 @@ <h2>Results</h2>
185185
<script>
186186
let bandFreqCount = 0;
187187
let hybridElementCount = 0;
188+
const suggestedFrequencies = [0.135, 0.472, 1.8, 3.5, 5.3, 7, 10.1, 14, 18, 21, 28, 50, 144, 222, 420, 902, 1240];
188189

189190
function addBandFrequency() {
190191
const bandFrequencies = document.getElementById('bandFrequencies');
@@ -193,14 +194,11 @@ <h2>Results</h2>
193194
div.innerHTML = `
194195
<label>
195196
Band ${bandFreqCount + 1} (MHz):
196-
<input type="number" id="${freqId}" step="0.1" min="0.1" value="${7.1 + bandFreqCount * 7}">
197+
<input type="number" id="${freqId}" step="0.001" min="0.1" value="${bandFreqCount === 0 ? 14 : suggestedFrequencies[bandFreqCount % suggestedFrequencies.length]}">
197198
<button class="remove-btn" onclick="removeBandFrequency(this)">Remove</button>
198199
</label>
199200
`;
200201
bandFrequencies.appendChild(div);
201-
if (bandFreqCount === 0) {
202-
document.getElementById(freqId).value = 14.2; // Default first band
203-
}
204202
bandFreqCount++;
205203
}
206204

@@ -503,7 +501,33 @@ <h2>Results</h2>
503501
const plotHeight = canvas.height - 2 * margin;
504502
const maxSWR = Math.max(...swrValues, 5); // Cap at 5 for visibility
505503

504+
// Sort targetBands and swrValues together
505+
const sortedPairs = targetBands.map((freq, index) => [freq, swrValues[index]])
506+
.sort((a, b) => a[0] - b[0]);
507+
const sortedBands = sortedPairs.map(pair => pair[0]);
508+
const sortedSWR = sortedPairs.map(pair => pair[1]);
509+
510+
// Grid
511+
ctx.strokeStyle = '#ddd';
512+
ctx.lineWidth = 0.5;
513+
sortedBands.forEach((freq, index) => {
514+
const x = margin + (index / (sortedBands.length - 1)) * plotWidth;
515+
ctx.beginPath();
516+
ctx.moveTo(x, margin);
517+
ctx.lineTo(x, canvas.height - margin);
518+
ctx.stroke();
519+
});
520+
[1, 2, 3, 4, 5].forEach(swr => {
521+
const y = canvas.height - margin - (swr / maxSWR) * plotHeight;
522+
ctx.beginPath();
523+
ctx.moveTo(margin, y);
524+
ctx.lineTo(canvas.width - margin, y);
525+
ctx.stroke();
526+
});
527+
506528
// Axes
529+
ctx.strokeStyle = '#000';
530+
ctx.lineWidth = 1;
507531
ctx.beginPath();
508532
ctx.moveTo(margin, margin);
509533
ctx.lineTo(margin, canvas.height - margin);
@@ -521,13 +545,13 @@ <h2>Results</h2>
521545
ctx.restore();
522546

523547
// Ticks and labels
524-
targetBands.forEach((freq, index) => {
525-
const x = margin + (index / (targetBands.length - 1)) * plotWidth;
548+
sortedBands.forEach((freq, index) => {
549+
const x = margin + (index / (sortedBands.length - 1)) * plotWidth;
526550
ctx.beginPath();
527551
ctx.moveTo(x, canvas.height - margin);
528552
ctx.lineTo(x, canvas.height - margin + 5);
529553
ctx.stroke();
530-
ctx.fillText(freq.toFixed(1), x, canvas.height - margin + 15);
554+
ctx.fillText(freq.toFixed(freq < 1 ? 3 : 1), x, canvas.height - margin + 15);
531555
});
532556
[1, 2, 3, 4, 5].forEach(swr => {
533557
const y = canvas.height - margin - (swr / maxSWR) * plotHeight;
@@ -543,13 +567,23 @@ <h2>Results</h2>
543567
ctx.beginPath();
544568
ctx.strokeStyle = '#FF0000';
545569
ctx.lineWidth = 2;
546-
targetBands.forEach((freq, index) => {
547-
const x = margin + (index / (targetBands.length - 1)) * plotWidth;
548-
const y = canvas.height - margin - (swrValues[index] / maxSWR) * plotHeight;
570+
sortedBands.forEach((freq, index) => {
571+
const x = margin + (index / (sortedBands.length - 1)) * plotWidth;
572+
const y = canvas.height - margin - (sortedSWR[index] / maxSWR) * plotHeight;
549573
if (index === 0) ctx.moveTo(x, y);
550574
else ctx.lineTo(x, y);
551575
});
552576
ctx.stroke();
577+
578+
// Data points
579+
ctx.fillStyle = '#0000FF';
580+
sortedBands.forEach((freq, index) => {
581+
const x = margin + (index / (sortedBands.length - 1)) * plotWidth;
582+
const y = canvas.height - margin - (sortedSWR[index] / maxSWR) * plotHeight;
583+
ctx.beginPath();
584+
ctx.arc(x, y, 4, 0, 2 * Math.PI);
585+
ctx.fill();
586+
});
553587
}
554588

555589
function calculateAntenna() {
@@ -608,35 +642,78 @@ <h2>Results</h2>
608642
return `${length.toFixed(2)} m (${feet.toFixed(2)} ft, ${inches.toFixed(2)} in)`;
609643
}
610644

611-
function estimateSWR(length, freq, type) {
612-
const idealLength = type === 'quarterVertical' ?
613-
(speedOfLight / (freq * 1000000)) * 0.25 * velocityFactor :
614-
(speedOfLight / (freq * 1000000)) * 0.5 * velocityFactor;
615-
const deviation = Math.abs(length - idealLength) / idealLength;
616-
return Math.max(1, 1 + deviation * 10);
617-
}
618-
619-
function estimateMultiElementSWR(lengths, freqs, types) {
620-
let totalDeviation = 0;
621-
freqs.forEach((freq, index) => {
622-
const length = lengths[index];
623-
const type = types[index];
645+
function estimateSWR(lengths, freq, type, balunRatio, traps, designFreqs) {
646+
// For single-element antennas, use the single length and design frequency
647+
const length = Array.isArray(lengths) ? lengths[0] : lengths;
648+
const designFreq = Array.isArray(designFreqs) ? designFreqs[0] : designFreqs;
649+
const isMultiElement = Array.isArray(lengths) && lengths.length > 1;
650+
651+
// Base SWR from resonance
652+
let baseSWR = 1;
653+
if (isMultiElement) {
654+
// Multi-element: find closest resonant frequency
655+
const deviations = designFreqs.map((df, i) => {
656+
const idealLength = type[i] === 'quarterVertical' ?
657+
(speedOfLight / (df * 1000000)) * 0.25 * velocityFactor :
658+
(speedOfLight / (df * 1000000)) * 0.5 * velocityFactor;
659+
return Math.abs(lengths[i] - idealLength) / idealLength;
660+
});
661+
const minDeviation = Math.min(...deviations);
662+
baseSWR = 1 + minDeviation * 10;
663+
} else {
624664
const idealLength = type === 'quarterVertical' ?
625-
(speedOfLight / (freq * 1000000)) * 0.25 * velocityFactor :
626-
(speedOfLight / (freq * 1000000)) * 0.5 * velocityFactor;
627-
totalDeviation += Math.abs(length - idealLength) / idealLength;
628-
});
629-
return Math.max(1, 1 + (totalDeviation / freqs.length) * 5).toFixed(1);
665+
(speedOfLight / (designFreq * 1000000)) * 0.25 * velocityFactor :
666+
(speedOfLight / (designFreq * 1000000)) * 0.5 * velocityFactor;
667+
const deviation = Math.abs(length - idealLength) / idealLength;
668+
baseSWR = 1 + deviation * 10;
669+
}
670+
671+
// Balun factor
672+
let balunFactor = 1;
673+
if (useBalun && balunRatio) {
674+
const ratios = {'1:1': 1, '4:1': 4, '9:1': 9};
675+
const impedanceFactor = isMultiElement ? 1 :
676+
(type === 'foldedDipole' ? 4 :
677+
(type === 'offCenterDipole' ? 4 :
678+
(type === 'endFed' || type === 'randomWire' ? 9 : 1)));
679+
balunFactor = Math.abs(ratios[balunRatio] - impedanceFactor) / impedanceFactor + 1;
680+
}
681+
682+
// Trap factor
683+
let trapFactor = 1;
684+
if (useTraps && traps.length > 0) {
685+
traps.forEach(trapFreq => {
686+
const freqRatio = freq / trapFreq;
687+
if (freqRatio > 1) {
688+
// Sharp rise above trap frequency, peaking at 10x base SWR within 5%
689+
const proximity = Math.min(1, Math.max(0, (freqRatio - 1) / 0.05));
690+
trapFactor += 9 * proximity; // Adds up to 9 at 5% above trap
691+
}
692+
});
693+
}
694+
695+
// Resonance dips for multi-element
696+
let resonanceFactor = 1;
697+
if (isMultiElement) {
698+
designFreqs.forEach(df => {
699+
const freqDiff = Math.abs(freq - df) / df;
700+
if (freqDiff < 0.05) {
701+
// Dip towards 1 near resonant frequency
702+
resonanceFactor = Math.min(resonanceFactor, 1 + (freqDiff / 0.05) * (baseSWR - 1));
703+
}
704+
});
705+
}
706+
707+
return Math.max(1, baseSWR * balunFactor * trapFactor * resonanceFactor);
630708
}
631709

632710
function determineBalunRatio(type) {
633711
if (!useBalun) return null;
634712
switch (type) {
635713
case 'endFed':
636714
case 'randomWire':
637-
return '9:1'; // Common for random wire and end-fed
715+
return '9:1';
638716
case 'offCenterDipole':
639-
return '4:1'; // OCFD typically ~200Ω
640717
case 'foldedDipole':
641718
return '4:1';
642719
case 'dipole':
@@ -676,13 +753,13 @@ <h2>Results</h2>
676753
calcResults.push(`- Antenna Type: ${antennaType}`);
677754
calcResults.push(`- Wire Material: ${wireMaterial}`);
678755
calcResults.push(`- Wire Gauge: ${wireGauge} AWG`);
679-
calcResults.push(`- Target Bands: ${targetBands.map(f => f.toFixed(1)).join(', ')} MHz`);
756+
calcResults.push(`- Target Bands: ${targetBands.map(f => f.toFixed(f < 1 ? 3 : 1)).join(', ')} MHz`);
680757
if (balunRatio) {
681758
calcResults.push(`- Balun/UnUn: ${balunRatio}`);
682759
}
683760

684761
if (antennaType === 'dipole') {
685-
const freq = targetBands[0]; // Use lowest band for single-element design
762+
const freq = targetBands[0];
686763
const length = (speedOfLight / (freq * 1000000)) * 0.5 * velocityFactor;
687764
lengths.push(length);
688765
frequencies.push(freq);
@@ -697,7 +774,7 @@ <h2>Results</h2>
697774
});
698775
}
699776
if (balunRatio) results.push(`- Balun (${balunRatio}): At center feedpoint`);
700-
swrValues = targetBands.map(f => estimateSWR(length, f, 'dipole'));
777+
swrValues = targetBands.map(f => estimateSWR(length, f, 'dipole', balunRatio, trapFrequencies, freq));
701778

702779
calcResults.push(`<b>Element 1: Half-Wave Dipole at ${freq} MHz</b>`);
703780
calcResults.push(`- Wavelength (λ) = c / f = ${speedOfLight} / (${freq} × 10⁶) = ${(speedOfLight / (freq * 1000000)).toFixed(2)} m`);
@@ -718,7 +795,7 @@ <h2>Results</h2>
718795
});
719796
}
720797
if (balunRatio) results.push(`- Balun (${balunRatio}): At base feedpoint`);
721-
swrValues = targetBands.map(f => estimateSWR(length * 2, f, 'quarterVertical'));
798+
swrValues = targetBands.map(f => estimateSWR(length * 2, f, 'quarterVertical', balunRatio, trapFrequencies, freq));
722799

723800
calcResults.push(`<b>Element 1: Quarter-Wave Vertical at ${freq} MHz</b>`);
724801
calcResults.push(`- Wavelength (λ) = c / f = ${speedOfLight} / (${freq} × 10⁶) = ${(speedOfLight / (freq * 1000000)).toFixed(2)} m`);
@@ -741,7 +818,7 @@ <h2>Results</h2>
741818
});
742819
}
743820
if (balunRatio) results.push(`- Balun (${balunRatio}): At top center feedpoint`);
744-
swrValues = targetBands.map(f => estimateSWR(length, f, 'foldedDipole'));
821+
swrValues = targetBands.map(f => estimateSWR(length, f, 'foldedDipole', balunRatio, trapFrequencies, freq));
745822

746823
calcResults.push(`<b>Element 1: Folded Dipole at ${freq} MHz</b>`);
747824
calcResults.push(`- Wavelength (λ) = c / f = ${speedOfLight} / (${freq} × 10⁶) = ${(speedOfLight / (freq * 1000000)).toFixed(2)} m`);
@@ -761,7 +838,7 @@ <h2>Results</h2>
761838
});
762839
}
763840
if (balunRatio) results.push(`- UnUn (${balunRatio}): At end feedpoint`);
764-
swrValues = targetBands.map(f => estimateSWR(length, f, 'endFed'));
841+
swrValues = targetBands.map(f => estimateSWR(length, f, 'endFed', balunRatio, trapFrequencies, freq));
765842

766843
calcResults.push(`<b>Element 1: End-Fed Wire at ${freq} MHz</b>`);
767844
calcResults.push(`- Wavelength (λ) = c / f = ${speedOfLight} / (${freq} × 10⁶) = ${(speedOfLight / (freq * 1000000)).toFixed(2)} m`);
@@ -784,11 +861,10 @@ <h2>Results</h2>
784861
});
785862
}
786863
if (balunRatio) results.push(`- UnUn (${balunRatio}): At end feedpoint`);
787-
swrValues = targetBands.map(f => estimateSWR(length, f, 'endFed')); // Approximate as end-fed
864+
swrValues = targetBands.map(f => estimateSWR(length, f, 'randomWire', balunRatio, trapFrequencies, targetBands[0]));
788865

789866
calcResults.push(`<b>Element 1: Random Wire</b>`);
790867
calcResults.push(`- User-Specified Length: ${length.toFixed(2)} m`);
791-
calcResults.push(`- Note: SWR varies significantly; tuner recommended.`);
792868
} else if (antennaType === 'offCenterDipole') {
793869
const freq = targetBands[0];
794870
const length = (speedOfLight / (freq * 1000000)) * 0.5 * velocityFactor;
@@ -806,7 +882,7 @@ <h2>Results</h2>
806882
});
807883
}
808884
if (balunRatio) results.push(`- Balun (${balunRatio}): At off-center feedpoint`);
809-
swrValues = targetBands.map(f => estimateSWR(length, f, 'dipole') * 1.2); // Higher SWR due to OCFD impedance
885+
swrValues = targetBands.map(f => estimateSWR(length, f, 'offCenterDipole', balunRatio, trapFrequencies, freq));
810886

811887
calcResults.push(`<b>Element 1: Off-Center Fed Dipole at ${freq} MHz</b>`);
812888
calcResults.push(`- Wavelength (λ) = c / f = ${speedOfLight} / (${freq} × 10⁶) = ${(speedOfLight / (freq * 1000000)).toFixed(2)} m`);
@@ -834,9 +910,7 @@ <h2>Results</h2>
834910
});
835911
}
836912
if (balunRatio) results.push(`- Balun (${balunRatio}): At common center feedpoint`);
837-
const combinedSWR = estimateMultiElementSWR(lengths, targetBands, types);
838-
results.push(`- Expected SWR across all bands: ${combinedSWR}`);
839-
swrValues = targetBands.map(() => parseFloat(combinedSWR));
913+
swrValues = targetBands.map(f => estimateSWR(lengths, f, types, balunRatio, trapFrequencies, frequencies));
840914
} else if (antennaType === 'hybrid') {
841915
const hybridTypes = [];
842916
for (let i = 0; i < hybridElementCount; i++) {
@@ -884,9 +958,7 @@ <h2>Results</h2>
884958
});
885959
}
886960
if (balunRatio) results.push(`- Balun (${balunRatio}): At common feedpoint`);
887-
const combinedSWR = estimateMultiElementSWR(lengths, targetBands, types);
888-
results.push(`- Expected SWR across all bands: ${combinedSWR}`);
889-
swrValues = targetBands.map(() => parseFloat(combinedSWR));
961+
swrValues = targetBands.map(f => estimateSWR(lengths, f, types, balunRatio, trapFrequencies, frequencies));
890962
}
891963

892964
if (useTraps && trapFrequencies.length > 0) {

0 commit comments

Comments
 (0)