fix: power is RM5, not RM4 — the CW keying was the experiment
An FM carrier could not answer it: constant by definition, so nothing to correlate. CW at 100 W did, because the keying itself varies the output: key down: RM4=25 RM5=207 RM6=13 key up: RM4=25 RM5=0 RM6=0 RM5 follows the RF envelope exactly — it IS the power meter. RM4 sits near 25 whether the key is down or up, so it is not measuring output at all, and reading it as power is what showed 8 W on a 100 W transmission. The operator's hunch was right and my first reading of the ramp was wrong: what I took for a needle rising was RM4 drifting, not tracking. Watts are now derived from that meter (207 = 100 W, measured) instead of the power SETTING scaled by a percentage — the setting says what was asked for, the meter says what left the radio. The bars also hold their peak with a gentle decay. In CW the meters genuinely read zero between elements, so following the raw value made them flash to nothing several times a second; a needle has inertia, and this only ever holds a value the radio really reported.
This commit is contained in:
+2
-2
@@ -3,7 +3,7 @@
|
||||
"version": "0.21.9",
|
||||
"date": "2026-07-28",
|
||||
"en": [
|
||||
"Yaesu console: the SWR bar showed about 80 on a perfect match — it was reading a meter unrelated to the antenna. It now reads the right one and shows the ratio itself (1.0, 1.5…) as the rig does, not a percentage.",
|
||||
"Yaesu console meters are right: power now reads the meter that follows the RF (in watts, measured, not the power setting) and SWR shows the ratio itself. Both were reading the wrong index — the SWR bar sat near 80 on a perfect match. The bars also hold their peak, so CW keying no longer makes them flash to zero.",
|
||||
"CW speed is now one setting wherever you change it: the Yaesu console slider and the CW panel drive the keyer that is actually sending, and the rig own keyer follows so its front panel agrees.",
|
||||
"Antenna Genius: port A no longer jumps onto port B antenna a few seconds after a change. Only one port can hold the transmit antenna, so the switch reports the same one on both — the display now follows each port own receive antenna.",
|
||||
"CW through the Yaesu keyer: a fifth CW engine sends your macros with the radio own keyer (CAT \"KY\"), for the FTDX101 / FT-991A / FT-710 family. An FTDX10 does not accept it — DAKY included — and OpsLog says so, pointing to the serial DTR keyer on the rig second COM port, which works.",
|
||||
@@ -21,7 +21,7 @@
|
||||
"CQ and ITU zones you correct by hand in your profile stay corrected. They are derived from cty.dat, which gives the zones of the whole entity — in a country spanning several, the automatic value is wrong and it came back at every restart. They now only fill in when empty, and recompute when the callsign or grid changes."
|
||||
],
|
||||
"fr": [
|
||||
"Console Yaesu : la barre de ROS indiquait environ 80 sur une antenne parfaitement adaptée — elle lisait un instrument sans rapport avec l'antenne. Elle lit désormais le bon et affiche le rapport lui-même (1,0 ; 1,5…) comme la radio, au lieu d'un pourcentage.",
|
||||
"Les mesures de la console Yaesu sont justes : la puissance lit l'instrument qui suit la HF (en watts mesurés, et non le réglage de puissance) et le ROS affiche le rapport lui-même. Les deux lisaient le mauvais index — la barre de ROS restait vers 80 sur une antenne parfaite. Les barres retiennent aussi leur crête : la manipulation CW ne les fait plus clignoter à zéro.",
|
||||
"La vitesse CW est désormais un réglage unique où que vous la changiez : le curseur de la console Yaesu et le panneau CW pilotent le manipulateur qui émet réellement, et le keyer interne de la radio suit pour que sa façade affiche la même valeur.",
|
||||
"Antenna Genius : le port A ne bascule plus sur l'antenne du port B quelques secondes après un changement. Un seul port peut porter l'antenne d'émission, le switch renvoie donc la même sur les deux — l'affichage suit désormais l'antenne de réception propre à chaque port.",
|
||||
"CW par le keyer Yaesu : un cinquième moteur CW envoie vos macros avec le keyer de la radio (CAT « KY »), pour la famille FTDX101 / FT-991A / FT-710. Un FTDX10 ne l'accepte pas — DAKY compris — et OpsLog le dit en renvoyant vers le keyer série DTR sur son second port COM, qui fonctionne.",
|
||||
|
||||
@@ -19,7 +19,7 @@ type YaesuState = {
|
||||
rf_power: number; mic_gain: number; af_gain: number; rf_gain: number; squelch: number;
|
||||
agc?: string; preamp: number; att: number;
|
||||
nb: boolean; nr: boolean; nr_level: number; narrow: boolean; vox: boolean;
|
||||
split_tx_hz?: number; key_speed?: number; break_in?: boolean; swr?: number;
|
||||
split_tx_hz?: number; key_speed?: number; break_in?: boolean; swr?: number; power_w?: number;
|
||||
};
|
||||
|
||||
const ZERO: YaesuState = {
|
||||
@@ -350,7 +350,10 @@ export function YaesuPanel({ onReportRST, onKeySpeed }: {
|
||||
display={sParts(view.s_meter).label}
|
||||
onClick={onReportRST ? () => { const sp = sParts(view.s_meter); onReportRST(sMeterRST(sp.s, sp.over, view.mode)); } : undefined}
|
||||
title={onReportRST ? t('yaesu.sToRst') : undefined} />
|
||||
<MeterBar label="PWR" value={view.rf_power * view.power_meter / 100} unit="W" lo={0} hi={100} accent="#0ea5e9" />
|
||||
{/* Watts as MEASURED, not the power setting scaled by a percentage:
|
||||
the setting says what was asked for, the meter says what left. */}
|
||||
<MeterBar label="PWR" value={view.power_w ?? 0} unit="W" lo={0} hi={Math.max(100, view.rf_power || 100)} accent="#0ea5e9"
|
||||
display={view.transmitting ? Math.round(view.power_w ?? 0) + 'W' : '—'} />
|
||||
{/* The RATIO, as the rig shows it — a percentage of meter travel is
|
||||
not something an operator can act on. The bar keeps the travel. */}
|
||||
<MeterBar label="SWR" value={view.swr_meter} lo={0} hi={100} accent="#f59e0b"
|
||||
|
||||
@@ -1098,6 +1098,7 @@ export namespace cat {
|
||||
nr_level: number;
|
||||
narrow: boolean;
|
||||
swr: number;
|
||||
power_w: number;
|
||||
vox: boolean;
|
||||
key_speed: number;
|
||||
break_in: boolean;
|
||||
@@ -1131,6 +1132,7 @@ export namespace cat {
|
||||
this.nr_level = source["nr_level"];
|
||||
this.narrow = source["narrow"];
|
||||
this.swr = source["swr"];
|
||||
this.power_w = source["power_w"];
|
||||
this.vox = source["vox"];
|
||||
this.key_speed = source["key_speed"];
|
||||
this.break_in = source["break_in"];
|
||||
|
||||
+57
-12
@@ -58,7 +58,10 @@ type YaesuTXState struct {
|
||||
// SWR is the RATIO (1.0, 1.5…), computed from the reflection coefficient —
|
||||
// what an operator reads on the rig, not a percentage of meter travel.
|
||||
SWR float64 `json:"swr"`
|
||||
VOX bool `json:"vox"`
|
||||
// PowerW is the output in WATTS, taken from the METER rather than from the
|
||||
// power setting — the setting says what was asked for, not what came out.
|
||||
PowerW float64 `json:"power_w"`
|
||||
VOX bool `json:"vox"`
|
||||
// CW-only controls. Read (and shown) only in CW, where MIC and VOX mean
|
||||
// nothing and these are what an operator reaches for.
|
||||
KeySpeed int `json:"key_speed"` // WPM
|
||||
@@ -155,17 +158,24 @@ func (y *Yaesu) readPanel(mode string, split bool, txHz int64) {
|
||||
debugLog.Printf("yaesu: meters at PC=%dW: %s (compare two different power settings)",
|
||||
y.panel.RFPower, strings.Join(raw, " "))
|
||||
}
|
||||
// Measured on an FTDX10 (2026-07-29), a steady carrier for three seconds:
|
||||
// Measured on an FTDX10 (2026-07-29). The FM carrier was inconclusive —
|
||||
// constant by definition — so the answer came from CW at 100 W, where the
|
||||
// keying itself is the experiment:
|
||||
//
|
||||
// RM1=0 RM2=unsupported RM3=0 RM4=9→18→21→22 RM5=208 flat RM6=0
|
||||
// key down: RM4=25 RM5=207 RM6=13
|
||||
// key up: RM4=25 RM5=0 RM6=0
|
||||
//
|
||||
// RM4 is the one that RAMPS with the output, so RM4 is the power meter.
|
||||
// RM5 sat at 208 from the first sample to the last, unmoved by the power —
|
||||
// that is not SWR (the operator's was 1.1) and not a meter that reads
|
||||
// anything we can show; borrowing the FT-991A's table, which puts SWR
|
||||
// there, is exactly what made the bar read 81.
|
||||
if v, ok := y.askNum("RM4;", "RM4", 3); ok {
|
||||
y.panel.PowerMeter = scale255(v)
|
||||
// RM5 follows the RF envelope exactly, so RM5 is the POWER meter. RM4 sits
|
||||
// near 25 whether the key is down or up, so it is not measuring output at
|
||||
// all — reading it as power is what showed 8 W on a 100 W transmission.
|
||||
// Peak-hold. In CW the key is up between elements and the meters genuinely
|
||||
// read 0 there — the log shows RM5 alternating 207, 0, 207 — so following
|
||||
// the raw value makes the bars flicker to nothing several times a second
|
||||
// and the number unreadable. A real meter has needle inertia; this is the
|
||||
// same idea, and it only ever holds a value the radio actually reported.
|
||||
if v, ok := y.askNum("RM5;", "RM5", 3); ok {
|
||||
y.panel.PowerMeter = holdPeak(y.panel.PowerMeter, scale255(v))
|
||||
y.panel.PowerW = float64(holdPeak(int(y.panel.PowerW), int(yaesuWatts(v))))
|
||||
}
|
||||
// SWR is RM6, and a second measurement at a KNOWN mismatch settled both the
|
||||
// index and the scale: 0 at SWR 1.1, then 52 at SWR 1.5. 52/255 = 0.204,
|
||||
@@ -173,8 +183,12 @@ func (y *Yaesu) readPanel(mode string, split bool, txHz int64) {
|
||||
// the raw value is rho scaled to 255, and the ratio follows from physics
|
||||
// rather than from a fitted curve.
|
||||
if v, ok := y.askNum("RM6;", "RM6", 3); ok {
|
||||
y.panel.SWRMeter = scale255(v)
|
||||
y.panel.SWR = swrFromReflection(v)
|
||||
y.panel.SWRMeter = holdPeak(y.panel.SWRMeter, scale255(v))
|
||||
// SWR only means something while power is going out: between CW elements
|
||||
// the reading is 0, which would show as a perfect 1.0 match.
|
||||
if v > 0 {
|
||||
y.panel.SWR = swrFromReflection(v)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Zeroed rather than frozen: a stale SWR bar from the last transmission
|
||||
@@ -694,3 +708,34 @@ func swrFromReflection(raw int) float64 {
|
||||
}
|
||||
return swr
|
||||
}
|
||||
|
||||
// yaesuWatts converts the power-meter reading to watts.
|
||||
//
|
||||
// Single-point calibration, measured rather than assumed: an FTDX10 keying CW at
|
||||
// 100 W reads 207. The PO meter is close enough to linear in power for one point
|
||||
// to carry the scale, and a figure taken from the METER beats the power SETTING,
|
||||
// which says what was asked for and not what left the radio.
|
||||
//
|
||||
// A second point at low power would refine it; until then the number is right at
|
||||
// 100 W and approximate below.
|
||||
const yaesuPowerFullScale = 207.0 // raw reading measured at 100 W
|
||||
|
||||
func yaesuWatts(raw int) float64 {
|
||||
if raw <= 0 {
|
||||
return 0
|
||||
}
|
||||
return float64(raw) * 100.0 / yaesuPowerFullScale
|
||||
}
|
||||
|
||||
// holdPeak gives a meter the inertia a needle has: it jumps to a higher reading
|
||||
// at once and falls back gradually. Without it a CW transmission — key up
|
||||
// between every element — makes the bars flash to zero several times a second.
|
||||
//
|
||||
// The decay is a quarter of the gap per poll, so a real drop in power still
|
||||
// shows within about a second at the default rate.
|
||||
func holdPeak(current, sample int) int {
|
||||
if sample >= current {
|
||||
return sample
|
||||
}
|
||||
return current - (current-sample)/4
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user