Skip to content

Commit c71a70d

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

File tree

1 file changed

+83
-66
lines changed

1 file changed

+83
-66
lines changed

antennas/antennaizer.html

Lines changed: 83 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
<!-- This is an experemental antenna calculation tool written largely by Generative AI. Use at your own risk. As this is written by Generative AI, I am disavowing any copyright on it. -->
21
<!DOCTYPE html>
32
<html lang="en">
43
<head>
@@ -84,7 +83,7 @@
8483
</head>
8584
<body>
8685
<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>
86+
<p>This is an experimental antenna calculation tool written largely by Generative AI. Use at your own risk.</p>
8887
<div class="section">
8988
<h2>Input Parameters</h2>
9089
<div id="targetBands">
@@ -499,7 +498,7 @@ <h2>Results</h2>
499498
const margin = 50;
500499
const plotWidth = canvas.width - 2 * margin;
501500
const plotHeight = canvas.height - 2 * margin;
502-
const maxSWR = Math.max(...swrValues, 5); // Cap at 5 for visibility
501+
const maxSWR = Math.max(...swrValues, 10); // Cap at 10 for visibility
503502

504503
// Sort targetBands and swrValues together
505504
const sortedPairs = targetBands.map((freq, index) => [freq, swrValues[index]])
@@ -517,7 +516,7 @@ <h2>Results</h2>
517516
ctx.lineTo(x, canvas.height - margin);
518517
ctx.stroke();
519518
});
520-
[1, 2, 3, 4, 5].forEach(swr => {
519+
[1, 3, 5, 7, 9].forEach(swr => {
521520
const y = canvas.height - margin - (swr / maxSWR) * plotHeight;
522521
ctx.beginPath();
523522
ctx.moveTo(margin, y);
@@ -553,7 +552,7 @@ <h2>Results</h2>
553552
ctx.stroke();
554553
ctx.fillText(freq.toFixed(freq < 1 ? 3 : 1), x, canvas.height - margin + 15);
555554
});
556-
[1, 2, 3, 4, 5].forEach(swr => {
555+
[1, 3, 5, 7, 9].forEach(swr => {
557556
const y = canvas.height - margin - (swr / maxSWR) * plotHeight;
558557
ctx.beginPath();
559558
ctx.moveTo(margin - 5, y);
@@ -622,7 +621,7 @@ <h2>Results</h2>
622621
return;
623622
}
624623
if (wireGauge < 6 || wireGauge > 30) {
625-
alert('Wire gauge should be between 6 and 30 AWG');
624+
alert('Wire gauge should be between 6 WHOLE WIRE GAUGE HERE and 30 AWG');
626625
return;
627626
}
628627

@@ -642,69 +641,87 @@ <h2>Results</h2>
642641
return `${length.toFixed(2)} m (${feet.toFixed(2)} ft, ${inches.toFixed(2)} in)`;
643642
}
644643

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;
644+
function estimateSWR(lengths, freq, type, balunRatio, traps, designFreqs, velocityFactor) {
649645
const isMultiElement = Array.isArray(lengths) && lengths.length > 1;
646+
const singleLength = isMultiElement ? lengths : [lengths];
647+
const singleType = isMultiElement ? type : [type];
648+
const singleDesignFreq = isMultiElement ? designFreqs : [designFreqs];
649+
const c = 299792458; // Speed of light in m/s
650650

651-
// Base SWR from resonance
652651
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 {
664-
const idealLength = type === 'quarterVertical' ?
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-
}
670652

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) {
653+
if (singleType[0] === 'randomWire') {
654+
// Random wire: SWR depends on length and frequency, with multiple resonances
655+
const lambda = c / (freq * 1e6) * velocityFactor;
656+
const lengthInWavelengths = singleLength[0] / lambda;
657+
// Avoid lengths near multiples of 0.5 wavelengths (high impedance)
658+
const fractionalPart = lengthInWavelengths - Math.floor(lengthInWavelengths);
659+
if (Math.abs(fractionalPart - 0.5) < 0.05) {
660+
baseSWR = 10; // Very high SWR near half-wave multiples
661+
} else if (fractionalPart < 0.25 || fractionalPart > 0.75) {
662+
baseSWR = 2 + 5 * Math.abs(fractionalPart - 0.5); // Lower SWR near quarter-wave multiples
663+
} else {
664+
baseSWR = 5 + 5 * Math.abs(fractionalPart - 0.5); // Moderate SWR elsewhere
665+
}
666+
} else if (!useTraps || traps.length === 0) {
667+
// Resonant antennas without traps
668+
if (isMultiElement) {
669+
// Fan dipole or hybrid: minimum SWR across all elements
670+
let minSWR = Infinity;
671+
singleDesignFreq.forEach((df, i) => {
672+
const idealLength = singleType[i] === 'quarterVertical' ?
673+
(c / (df * 1e6)) * 0.25 * velocityFactor :
674+
(c / (df * 1e6)) * 0.5 * velocityFactor;
675+
const freqDeviation = Math.abs(freq - df) / df;
676+
const bwFactor = singleType[i] === 'foldedDipole' ? 0.1 : 0.05; // Folded dipole has wider bandwidth
677+
const elementSWR = 1 + (freqDeviation / bwFactor) ** 2 * 9; // Quadratic rise, max 10
678+
minSWR = Math.min(minSWR, elementSWR);
679+
});
680+
baseSWR = minSWR;
681+
} else {
682+
// Single resonant antenna
683+
const designFreq = singleDesignFreq[0];
684+
const idealLength = singleType[0] === 'quarterVertical' ?
685+
(c / (designFreq * 1e6)) * 0.25 * velocityFactor :
686+
(c / (designFreq * 1e6)) * 0.5 * velocityFactor;
687+
const freqDeviation = Math.abs(freq - designFreq) / designFreq;
688+
const bwFactor = singleType[0] === 'foldedDipole' ? 0.1 : 0.05; // Wider bandwidth for folded dipole
689+
baseSWR = 1 + (freqDeviation / bwFactor) ** 2 * 9; // Quadratic rise, max 10
690+
}
691+
} else {
692+
// With traps: SWR rises sharply above trap frequencies
693+
let trapFactor = 1;
685694
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
695+
if (freq > trapFreq) {
696+
const freqRatio = (freq - trapFreq) / trapFreq;
697+
trapFactor = Math.min(10, 1 + 50 * freqRatio); // Sharp rise, max 10
691698
}
692699
});
700+
if (isMultiElement) {
701+
let minSWR = Infinity;
702+
singleDesignFreq.forEach((df, i) => {
703+
const freqDeviation = Math.abs(freq - df) / df;
704+
const elementSWR = 1 + (freqDeviation / 0.05) ** 2 * 9;
705+
minSWR = Math.min(minSWR, elementSWR);
706+
});
707+
baseSWR = minSWR * trapFactor;
708+
} else {
709+
const designFreq = singleDesignFreq[0];
710+
const freqDeviation = Math.abs(freq - designFreq) / designFreq;
711+
baseSWR = (1 + (freqDeviation / 0.05) ** 2 * 9) * trapFactor;
712+
}
693713
}
694714

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-
});
715+
// Balun mismatch factor
716+
let balunFactor = 1;
717+
if (useBalun && balunRatio) {
718+
const ratios = {'1:1': 1, '4:1': 4, '9:1': 9};
719+
const expectedRatio = singleType[0] === 'foldedDipole' || singleType[0] === 'offCenterDipole' ? 4 :
720+
(singleType[0] === 'endFed' || singleType[0] === 'randomWire' ? 9 : 1);
721+
balunFactor = 1 + Math.abs(ratios[balunRatio] - expectedRatio) / expectedRatio;
705722
}
706723

707-
return Math.max(1, baseSWR * balunFactor * trapFactor * resonanceFactor);
724+
return Math.max(1, Math.min(10, baseSWR * balunFactor)); // Cap SWR at 10
708725
}
709726

710727
function determineBalunRatio(type) {
@@ -774,7 +791,7 @@ <h2>Results</h2>
774791
});
775792
}
776793
if (balunRatio) results.push(`- Balun (${balunRatio}): At center feedpoint`);
777-
swrValues = targetBands.map(f => estimateSWR(length, f, 'dipole', balunRatio, trapFrequencies, freq));
794+
swrValues = targetBands.map(f => estimateSWR(length, f, 'dipole', balunRatio, trapFrequencies, freq, velocityFactor));
778795

779796
calcResults.push(`<b>Element 1: Half-Wave Dipole at ${freq} MHz</b>`);
780797
calcResults.push(`- Wavelength (λ) = c / f = ${speedOfLight} / (${freq} × 10⁶) = ${(speedOfLight / (freq * 1000000)).toFixed(2)} m`);
@@ -795,7 +812,7 @@ <h2>Results</h2>
795812
});
796813
}
797814
if (balunRatio) results.push(`- Balun (${balunRatio}): At base feedpoint`);
798-
swrValues = targetBands.map(f => estimateSWR(length * 2, f, 'quarterVertical', balunRatio, trapFrequencies, freq));
815+
swrValues = targetBands.map(f => estimateSWR(length, f, 'quarterVertical', balunRatio, trapFrequencies, freq, velocityFactor));
799816

800817
calcResults.push(`<b>Element 1: Quarter-Wave Vertical at ${freq} MHz</b>`);
801818
calcResults.push(`- Wavelength (λ) = c / f = ${speedOfLight} / (${freq} × 10⁶) = ${(speedOfLight / (freq * 1000000)).toFixed(2)} m`);
@@ -818,7 +835,7 @@ <h2>Results</h2>
818835
});
819836
}
820837
if (balunRatio) results.push(`- Balun (${balunRatio}): At top center feedpoint`);
821-
swrValues = targetBands.map(f => estimateSWR(length, f, 'foldedDipole', balunRatio, trapFrequencies, freq));
838+
swrValues = targetBands.map(f => estimateSWR(length, f, 'foldedDipole', balunRatio, trapFrequencies, freq, velocityFactor));
822839

823840
calcResults.push(`<b>Element 1: Folded Dipole at ${freq} MHz</b>`);
824841
calcResults.push(`- Wavelength (λ) = c / f = ${speedOfLight} / (${freq} × 10⁶) = ${(speedOfLight / (freq * 1000000)).toFixed(2)} m`);
@@ -838,7 +855,7 @@ <h2>Results</h2>
838855
});
839856
}
840857
if (balunRatio) results.push(`- UnUn (${balunRatio}): At end feedpoint`);
841-
swrValues = targetBands.map(f => estimateSWR(length, f, 'endFed', balunRatio, trapFrequencies, freq));
858+
swrValues = targetBands.map(f => estimateSWR(length, f, 'endFed', balunRatio, trapFrequencies, freq, velocityFactor));
842859

843860
calcResults.push(`<b>Element 1: End-Fed Wire at ${freq} MHz</b>`);
844861
calcResults.push(`- Wavelength (λ) = c / f = ${speedOfLight} / (${freq} × 10⁶) = ${(speedOfLight / (freq * 1000000)).toFixed(2)} m`);
@@ -861,7 +878,7 @@ <h2>Results</h2>
861878
});
862879
}
863880
if (balunRatio) results.push(`- UnUn (${balunRatio}): At end feedpoint`);
864-
swrValues = targetBands.map(f => estimateSWR(length, f, 'randomWire', balunRatio, trapFrequencies, targetBands[0]));
881+
swrValues = targetBands.map(f => estimateSWR(length, f, 'randomWire', balunRatio, trapFrequencies, targetBands[0], velocityFactor));
865882

866883
calcResults.push(`<b>Element 1: Random Wire</b>`);
867884
calcResults.push(`- User-Specified Length: ${length.toFixed(2)} m`);
@@ -882,7 +899,7 @@ <h2>Results</h2>
882899
});
883900
}
884901
if (balunRatio) results.push(`- Balun (${balunRatio}): At off-center feedpoint`);
885-
swrValues = targetBands.map(f => estimateSWR(length, f, 'offCenterDipole', balunRatio, trapFrequencies, freq));
902+
swrValues = targetBands.map(f => estimateSWR(length, f, 'offCenterDipole', balunRatio, trapFrequencies, freq, velocityFactor));
886903

887904
calcResults.push(`<b>Element 1: Off-Center Fed Dipole at ${freq} MHz</b>`);
888905
calcResults.push(`- Wavelength (λ) = c / f = ${speedOfLight} / (${freq} × 10⁶) = ${(speedOfLight / (freq * 1000000)).toFixed(2)} m`);
@@ -910,7 +927,7 @@ <h2>Results</h2>
910927
});
911928
}
912929
if (balunRatio) results.push(`- Balun (${balunRatio}): At common center feedpoint`);
913-
swrValues = targetBands.map(f => estimateSWR(lengths, f, types, balunRatio, trapFrequencies, frequencies));
930+
swrValues = targetBands.map(f => estimateSWR(lengths, f, types, balunRatio, trapFrequencies, frequencies, velocityFactor));
914931
} else if (antennaType === 'hybrid') {
915932
const hybridTypes = [];
916933
for (let i = 0; i < hybridElementCount; i++) {
@@ -958,7 +975,7 @@ <h2>Results</h2>
958975
});
959976
}
960977
if (balunRatio) results.push(`- Balun (${balunRatio}): At common feedpoint`);
961-
swrValues = targetBands.map(f => estimateSWR(lengths, f, types, balunRatio, trapFrequencies, frequencies));
978+
swrValues = targetBands.map(f => estimateSWR(lengths, f, types, balunRatio, trapFrequencies, frequencies, velocityFactor));
962979
}
963980

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

0 commit comments

Comments
 (0)