- Ku band satellite downlink budget
- Radar equation and detection threshold
- FFT of an amplitude modulated signal
- Trunk dimensioning with Erlang B
- BER of a BPSK link and link margin
- Single error correction with a Hamming (7,4) code
- QPSK receiver sensitivity from a target BER
- Shannon capacity and Rayleigh outage of a radio link
- Antenna impedance seen through a coaxial line
- Radiation resistance and efficiency of a short CB whip
Ku band satellite downlink budget
Budget a 12 GHz satellite downlink: free-space path loss over 38000 km, gain of a 75 cm dish, impedance of the LNB seen through a short lossy line (complex tanh), reflection coefficient, return and mismatch losses, noise kTB, C/N, Shannon capacity, and the rejection of the adjacent channel by a Chebyshev filter.
#1. Ku band downlink: 12 GHz, slant range 38000 km, satellite EIRP 52 dBW; -> "[f]" (unit prefix 12 G none); -> "[d]" (unit convert 38000 "km" "m"); -> "[lam]" (math calc (concat (const get "c") "/" [f])); -> "[fspl]" (math calc (concat "20*log10(4*pi*" [d] "/" [lam] ")")); #2. Receive dish 75 cm, aperture efficiency 0.6; -> "[Gr]" (math calc (concat "10*log10(0.6*(pi*0.75/" [lam] ")^2)")); #3. LNB 60+15i seen through 3 cm of 50 ohm line, gamma l = 0.002+0.6i: Zin = Z0 ZL + Z0 th / Z0 + ZL th; -> "[th]" (complex tanh "0.002+0.6i"); -> "[zin]" (complex mul 50 (complex div (complex add "60+15i" (complex mul 50 [th])) (complex add 50 (complex mul "60+15i" [th])))); #4. Reflection coefficient, return loss and mismatch loss; -> "[gam]" (complex div (complex sub [zin] 50) (complex add [zin] 50)); -> "[gp]" (json load select "rx_gam" (complex to_polar [gam]) /r); -> "[ml]" (math calc (concat "-10*log10(1-" (complex abs [gam]) "^2)")); #5. Carrier with 0.5 dB rain and pointing, noise kTB with Tsys 120 K in 27 MHz; -> "[C]" (math calc (concat "52-" [fspl] "+" [Gr] "-" [ml] "-0.5")); -> "[N]" (math calc (concat "10*log10(" (const get "k") "*120*27e6)")); -> "[cn]" (math calc (concat [C] "-" [N])); #6. Shannon capacity, and rejection of the adjacent channel at 1.5 x cutoff by a 5th order 0.5 dB Chebyshev filter; -> "[cap]" (math calc (concat "27e6*ln(1+10^(" [cn] "/10))/ln(2)/1e6")); -> "[rej]" (math calc "10*log10(1+(sqrt(10^0.05-1)*chebyshev_t(5, 1.5))^2)"); concat "lambda = " (math round [lam] 5) " m, FSPL = " (math round [fspl] 2) " dB, Gr = " (math round [Gr] 2) " dBi, Zin = " [zin] ", |Gamma| = " (math round [gp] 4) ", return loss " (math round (math calc (concat "-20*log10(" (complex abs [gam]) ")")) 2) " dB, mismatch " (math round [ml] 3) " dB, C = " (math round [C] 2) " dBW, N = " (math round [N] 2) " dBW, C/N = " (math round [cn] 2) " dB, Shannon " (math round [cap] 1) " Mbit/s, adjacent channel -" (math round [rej] 1) " dB"
lambda = 0.02498 m, FSPL = 205.63 dB, Gr = 37.27 dBi, Zin = 67.38454427045765-7.732448772562608i, |Gamma| = 0.1617, return loss 15.82 dB, mismatch 0.115 dB, C = -116.97 dBW, N = -133.49 dBW, C/N = 16.52 dB, Shannon 149.1 Mbit/s, adjacent channel -26.7 dB
- Add the rain attenuation of ITU-R P.618 for your site
- Compute the VSWR (1 + |Gamma|)/(1 - |Gamma|) with
complex abs
Radar equation and detection threshold
For an X band radar (100 kW, 35 dB, 1 MHz), get the SNR needed for Pd 0.9 and Pfa 1e-6 with 10 integrated pulses (Albersheim), the maximum range on a 1 m2 target, and the detection threshold on the sum of 10 square-law pulses (gamma law).
#1. X band radar: 9.4 GHz, Pt 100 kW, G 35 dB, B 1 MHz, F 4 dB, losses 6 dB, target 1 m2, 10 pulses; -> "[lam]" (unit calc "_c/(9.4 GHz)" "m"); -> "[n]" 10; #2. Albersheim: SNR per pulse for Pd 0.9 and Pfa 1e-6 with 10 pulses integrated; -> "[A]" (math calc "ln(0.62/1e-6)"); -> "[Bb]" (math calc "ln(0.9/0.1)"); -> "[snr]" (math calc "-5*log10([n])+(6.2+4.54/sqrt([n]+0.44))*log10([A]+0.12*[A]*[Bb]+1.7*[Bb])"); #3. Radar equation: maximum range; -> "[R]" (math calc (concat "(1e5*10^7*" [lam] "^2*1/((4*pi)^3*" (const get "k") "*290*1e6*10^0.4*10^0.6*10^(" [snr] "/10)))^0.25")); #4. Square law detector: threshold on the sum of 10 pulses for Pfa 1e-6, gamma law of shape 10; -> "[th]" (num solve "1-gamma_inc(10, x)-1e-6" "x" 1 60); -> "[rt]" (math calc "sqrt(-2*ln(1e-6))"); concat "SNR per pulse = " (math round [snr] 2) " dB, Rmax = " (math round (unit convert [R] "m" "km") 1) " km = " (math round (unit convert [R] "m" "nmi") 1) " nmi, threshold on 10 pulses = " (math round [th] 3) " noise powers, single pulse envelope threshold = " (math round [rt] 3) " sigma"
SNR per pulse = 4.99 dB, Rmax = 44.9 km = 24.2 nmi, threshold on 10 pulses = 32.71 noise powers, single pulse envelope threshold = 5.257 sigma
- Draw the noise envelope with
plot histogram(stat dist_random "weibull" "[2, 1.4142135623730951]" 5000) 40 - Find the range for a 0.1 m2 drone target
FFT of an amplitude modulated signal
Sample one second of an AM signal (50 Hz carrier, 5 Hz message, index 0.5) at 256 Hz, compute its FFT, read the carrier and sideband amplitudes from the bins, and plot the spectrum with these values marked.
#1. AM signal: carrier 50 Hz, message 5 Hz, index 0.5, 256 samples at 256 Hz; -> "[x]" (matrix col (num table "(1+0.5*cos(2*pi*5*t))*cos(2*pi*50*t+0.3)" "t" 0 0.99609375 0.00390625) 2); #2. FFT: bins of 1 Hz, the amplitude of a bin is 2 |X| / N; json load "rx_fft" (num fft [x]); -> "[a50]" (math calc (concat "2*" (complex abs (json select "rx_fft" /[50])) "/256")); -> "[a45]" (math calc (concat "2*" (complex abs (json select "rx_fft" /[45])) "/256")); -> "[a55]" (math calc (concat "2*" (complex abs (json select "rx_fft" /[55])) "/256")); #3. Draw the spectrum: carrier 1 at 50 Hz, sidebands m/2 = 0.25 at 45 and 55 Hz, marked from the FFT bins; plot spectrum [x] 256; plot add (plot points "[45, 50, 55]" (concat "[" [a45] ", " [a50] ", " [a55] "]"))
The chart is shown in the Plot tab of the editor.
- Recover the signal with
num ifftand compare with the samples - Add a Hann window with
dsp windowand see the leakage when the carrier is 50.5 Hz
Trunk dimensioning with Erlang B
A PABX of 240 extensions offers 0.12 Erlang per extension. Find the smallest number of trunks giving a blocking probability under 1 pct with the Erlang B formula, written with the incomplete gamma function, and the maximum traffic this trunk group accepts at 1 pct.
#1. Offered traffic of a PABX: 240 extensions at 0.12 Erlang each, target GoS 1 pct; -> "[A]" (math round (* 240 0.12) 2); #2. Erlang B with the incomplete gamma: B = A^N e^-A / N! / Q of N+1 and A; -> "[N]" 1; -> "[B]" 1; while (> [B] 0.01) { -> "[N]" (+ [N] 1); -> "[B]" (math calc "exp([N]*ln([A])-[A]-lgamma([N]+1))/gamma_incc([N]+1,[A])"); }; #3. Traffic that this trunk group can carry at exactly 1 pct blocking; -> "[Amax]" (num solve (concat "exp(" [N] "*ln(x)-x-lgamma(" [N] "+1))/gamma_incc(" [N] "+1,x)-0.01") "x" 1 100); #4. Carried traffic and occupancy of the trunks; -> "[carried]" (math calc "[A]*(1-[B])"); concat "offered " [A] " E -> " [N] " trunks, blocking " (math round (* 100 [B]) 3) " pct | carried " (math round [carried] 2) " E, occupancy " (math round (* 100 (/ [carried] [N])) 1) " pct | " [N] " trunks accept up to " (math round [Amax] 2) " E at 1 pct"
offered 28.8 E -> 40 trunks, blocking 0.922 pct | carried 28.53 E, occupancy 71.3 pct | 40 trunks accept up to 29.01 E at 1 pct
- Use
lgammaandgamma_inccfor Erlang C (call centres with a queue). - Tabulate B for N = 30 to 45 with
num tableto draw the GoS curve.
BER of a BPSK link and link margin
A 10 Mbit/s BPSK or QPSK link receives C/N0 = 84 dBHz. Find the Eb/N0 needed for a bit error rate of 1e-6 with Pb = 0.5 erfc of sqrt Eb/N0, the link margin, the BER actually reached and the bandwidth with a root raised cosine roll-off of 0.35.
#1. BPSK and QPSK bit error rate Pb = 0.5 erfc of sqrt Eb/N0; -> "[ber]" "0.5*erfc(sqrt(10^(x/10)))"; #2. Required Eb/N0 in dB for a BER of 1e-6; -> "[req]" (num solve (concat [ber] "-1e-6") "x" 0 20); #3. Link: C/N0 = 84 dBHz at 10 Mbit/s, implementation loss 1.5 dB; -> "[ebn0]" (math calc "84-10*log10(10e6)-1.5"); -> "[pb]" (math eval [ber] (concat "{\"x\": " [ebn0] "}")); #4. Occupied bandwidth with a root raised cosine roll-off of 0.35; -> "[bw_bpsk]" (math calc "10e6*(1+0.35)"); -> "[bw_qpsk]" (math calc "10e6/2*(1+0.35)"); concat "required Eb/N0 = " (math round [req] 2) " dB | available " (math round [ebn0] 2) " dB, margin " (math round (- [ebn0] [req]) 2) " dB, BER = " (math round_sig [pb] 3) " | bandwidth BPSK " (math round (/ [bw_bpsk] 1e6) 2) " MHz, QPSK " (math round (/ [bw_qpsk] 1e6) 2) " MHz"
required Eb/N0 = 10.53 dB | available 12.5 dB, margin 1.97 dB, BER = 0.00000000123 | bandwidth BPSK 13.5 MHz, QPSK 6.75 MHz
- Draw the BER curves with
plot chartand "log_y": true. - Add a coding gain of 5 dB (LDPC) and check the new margin.
Single error correction with a Hamming (7,4) code
A 4-bit data nibble is protected by a Hamming (7,4) code, one bit is flipped by the channel, and the receiver computes the syndrome to locate and correct it, using only bitwise operations.
#1. Data nibble 1011, codeword positions 1 to 7 from the MSB, data at 3 5 6 7; -> "[d]" 11; json load "rx_p4f_pos" "[3, 5, 6, 7]"; -> "[cw]" 0; -> "[par]" 0; #2. Place each data bit, the XOR of the data positions gives the parity bits; for (-> "[i]" 0) (< [i] 4) (++ "[i]") { -> "[p]" (json select "rx_p4f_pos" (concat "/[" [i] "]")); if (== (math bit_and (math trunc (/ [d] (math power 2 (- 3 [i])))) 1) 1) { -> "[cw]" (math bit_or [cw] (math power 2 (- 7 [p]))); -> "[par]" (math bit_xor [par] [p]); }; }; #3. Parity bits at positions 1, 2 and 4; -> "[cw]" (math bit_or [cw] (+ (* 64 (math bit_and [par] 1)) (+ (* 16 (math bit_and [par] 2)) (* 2 (math bit_and [par] 4))))); #4. The channel flips the bit at position 6; -> "[rx]" (math bit_xor [cw] 2); #5. Syndrome = XOR of the positions of the received 1 bits; -> "[s]" 0; for (-> "[k]" 1) (<= [k] 7) (++ "[k]") { if (== (math bit_and (math trunc (/ [rx] (math power 2 (- 7 [k])))) 1) 1) {-> "[s]" (math bit_xor [s] [k]);}; }; #6. Flip back the bit pointed by the syndrome; -> "[fixed]" (if (> [s] 0) {math bit_xor [rx] (math power 2 (- 7 [s]))} {[rx]}); json unload "rx_p4f_pos"; concat "sent " (string lpad (string bin [cw]) "0" 7) ", received " (string lpad (string bin [rx]) "0" 7) ", syndrome " [s] " -> corrected " (string lpad (string bin [fixed]) "0" 7) (if (== [fixed] [cw]) {" = sent word"} {" mismatch"})
sent 0110011, received 0110001, syndrome 6 -> corrected 0110011 = sent word
- Add an overall parity bit (SECDED, Hamming 8,4) to detect double errors
- Loop over the 7 single-error patterns to verify that every syndrome is unique
QPSK receiver sensitivity from a target BER
For a Gray-coded QPSK link at 2 Mbit/s, find the Eb/N0 that gives a BER of 1e-6 with the inverse error function, check it with erfc, and turn it into a receiver sensitivity with the thermal noise kT0.
#1. Gray-coded QPSK: BER = erfc of sqrt Eb/N0, halved. Target BER 1e-6; -> "[ber]" 0.000001; -> "[ebn0]" (math power (math erf_inv (- 1 (* 2 [ber]))) 2); -> "[ebn0_db]" (* 10 (math log10 [ebn0])); #2. Check: BER back from erfc; -> "[check]" (* 0.5 (math erfc (math sqrt [ebn0]))); #3. Thermal noise density kT0 at 290 K, from the Boltzmann constant; -> "[k]" (string regexp_extract (constant physics_k) "[0-9.]+E-[0-9]+" 0); -> "[n0_dbm]" (math calc "10*log10([k]*290*1000)"); #4. Sensitivity at 2 Mbit/s with a noise figure of 4 dB and 2 dB implementation loss; -> "[sens]" (math calc "[n0_dbm]+10*log10(2e6)+[ebn0_db]+4+2"); concat "Eb/N0 = " (math round [ebn0_db] 2) " dB (BER check " (math round_sig [check] 3) ") | kT0 = " (math round [n0_dbm] 2) " dBm/Hz | sensitivity = " (math round [sens] 1) " dBm"
Eb/N0 = 10.53 dB (BER check 0.00000100) | kT0 = -173.98 dBm/Hz | sensitivity = -94.4 dBm
- Add a convolutional code gain of 5 dB and compare the sensitivity
- Plot the BER curve with
plot functionanderfcbetween 0 and 12 dB
Shannon capacity and Rayleigh outage of a radio link
A 20 MHz microwave channel has a mean SNR of 18 dB and must carry 60 Mbit/s. The script computes the Shannon capacity, the outage probability in Rayleigh fading and the mean SNR needed for 0.1 % outage, with the accurate log1p and expm1 functions.
#1. 20 MHz channel, mean SNR 18 dB, service rate 60 Mbit/s; -> "[B]" 20000000; -> "[snr]" (math power 10 1.8); -> "[R]" 60000000; #2. Shannon capacity C = B log2 of 1 + SNR, with log1p; -> "[C]" (/ (* [B] (math log1p [snr])) (math log 2)); #3. SNR threshold for the rate R and outage probability in Rayleigh fading; -> "[gth]" (- (math power 2 (/ [R] [B])) 1); -> "[pout]" (- 0 (math expm1 (- 0 (/ [gth] [snr])))); #4. Mean SNR for 0.1 pct outage: threshold over minus ln of 1 - p; -> "[snr_req]" (/ [gth] (- 0 (math log1p -0.001))); concat "capacity " (math round (/ [C] 1000000) 1) " Mbit/s | threshold " (math round (* 10 (math log10 [gth])) 2) " dB | Rayleigh outage " (math round (* 100 [pout]) 2) " pct | mean SNR for 0.1 pct outage " (math round (* 10 (math log10 [snr_req]) ) 2) " dB, fade margin " (math round (* 10 (math log10 (/ [snr_req] [gth]))) 2) " dB"
capacity 120 Mbit/s | threshold 8.45 dB | Rayleigh outage 10.5 pct | mean SNR for 0.1 pct outage 38.45 dB, fade margin 30 dB
- Compare with Rician fading by integrating the Marcum Q function with
num integrate - Add space diversity: the outage of 2 independent branches is the square of the outage
Antenna impedance seen through a coaxial line
A 433 MHz antenna of 35 - 20j ohms is fed by 30 cm of 50 ohm coax (velocity factor 0.66). The script transforms the load impedance along the line and computes the reflection coefficient, VSWR, return loss and mismatch loss.
#1. Load 35 - 20j ohms, 50 ohm coax of 0.30 m, velocity factor 0.66, 433 MHz; -> "[Z0]" 50; -> "[ZL]" "35-20i"; -> "[bl]" (math calc "2*pi*433e6*0.30/(0.66*299792458)"); -> "[t]" (math tan [bl]); #2. Input impedance of the lossless line; -> "[num]" (complex add [ZL] (concat (* [Z0] [t]) "i")); -> "[den]" (complex add [Z0] (complex mul [ZL] (concat [t] "i"))); -> "[Zin]" (complex mul [Z0] (complex div [num] [den])); #3. Reflection coefficient, VSWR, return loss and mismatch loss; -> "[g]" (complex abs (complex div (complex sub [ZL] [Z0]) (complex add [ZL] [Z0]))); -> "[vswr]" (/ (+ 1 [g]) (- 1 [g])); concat "line = " (math round (math calc "[bl]*180/pi") 1) " deg | Zin = " (math round (complex re [Zin]) 2) " + j" (math round (complex im [Zin]) 2) " ohm | Gamma = " (math round [g] 4) ", VSWR = " (math round [vswr] 3) ", RL = " (math round (* -20 (math log10 [g])) 2) " dB, ML = " (math round (* -10 (math log10 (- 1 (* [g] [g])))) 3) " dB"
line = 236.3 deg | Zin = 31.07 + j14.01 ohm | Gamma = 0.2863, VSWR = 1.802, RL = 10.86 dB, ML = 0.371 dB
- Find the line length that makes Zin real with
num solveon the imaginary part - Design a single-stub match: stub position and length
Radiation resistance and efficiency of a short CB whip
A 1.2 m whip (radius 5 mm) works at 27.185 MHz over a ground plane. The script takes c, Z0 and pi from the constant library, computes the radiation resistance and the capacitive reactance of the short monopole, the loss of the loading coil (Q = 200) and the radiation efficiency.
#1. Constants c, Z0 and pi, numbers taken from the constant library; -> "[c]" (string regexp_extract (constant physics_c) "[0-9.]+" 0); -> "[z0]" (string regexp_extract (constant physics_z0) "[0-9.]+" 0); -> "[pi]" (string regexp_extract (constant math_pi) "[0-9.]+" 0); -> "[lambda]" (/ [c] 27185000); #2. Short monopole h = 1.2 m: radiation resistance Z0 pi/3 h/lambda squared; -> "[Rr]" (math calc "[z0]*[pi]/3*(1.2/[lambda])^2"); #3. Reactance of the whip, radius 5 mm: -Z0/2pi . ln h/a - 1 . cot kh; -> "[X]" (* (/ [z0] (* -2 [pi])) (* (- (math log (/ 1.2 0.005)) 1) (math cot (math calc "2*[pi]*1.2/[lambda]")))); #4. Loading coil Q = 200 cancels X, ground loss 2 ohm; -> "[Rcoil]" (/ (math abs [X]) 200); -> "[eff]" (/ [Rr] (+ [Rr] (+ [Rcoil] 2))); concat "lambda = " (math round [lambda] 3) " m | Rr = " (math round [Rr] 3) " ohm, X = " (math round [X] 1) " ohm, coil loss = " (math round [Rcoil] 2) " ohm | efficiency = " (math round (* 100 [eff]) 1) " pct = " (math round (* 10 (math log10 [eff])) 2) " dB"
lambda = 11.028 m | Rr = 4.671 ohm, X = -329.7 ohm, coil loss = 1.65 ohm | efficiency = 56.1 pct = -2.51 dB
- Add a capacitive top hat: the radiation resistance grows up to 4 times
- Compute the 2:1 VSWR bandwidth from the Q of the antenna
