Technical Writing
MATLAB Modulation Recognition: Leakage-Free Data and Interpretable Features
A reliable workflow from signal generation and SNR injection through normalization, features and confusion-matrix analysis.
Define the Experiment Before Training
State the class set, symbols per frame, sample rate, pulse shaping, carrier and phase conditions, SNR range and any prior knowledge available at training time. If one class always has different power, length or random seeds, the classifier may learn the generator rather than modulation structure.
Keep Data-Generation Variables Independent
Each sample should record class, SNR, seed and complex baseband sequence. Information symbols, noise, phase/frequency offsets and train/validation/test identities should be independent. Adding different noise to the same clean frame on both sides of the train/test boundary can still leak information; split sample identities first, then generate impairments independently.
Derive AWGN Power from Its Definition
For complex baseband:
signalPower = mean(abs(signal).^2);
noisePower = signalPower / (10^(snrDb / 10));
noise = sqrt(noisePower / 2) .* ...
(randn(size(signal)) + 1j * randn(size(signal)));
noisySignal = signal + noise;
Real and imaginary components each receive half the total complex-noise power. Eb/N0 and Es/N0 require conversion by bits per symbol and sampling assumptions; not every dB parameter is the same SNR.
Normalize to Remove Irrelevant Scale
Per-frame average-power normalization prevents energy alone from separating classes:
z = signal(:);
z = z / sqrt(mean(abs(z).^2) + eps);
zCentered = z - mean(z);
If power variation or AGC error is part of the research question, retain it as an explicit variable instead of normalizing it away.
Combine Amplitude, Phase and Statistics
An interpretable feature set can include amplitude moments and percentiles, peak-to-average ratio, phase-difference statistics, spectral concentration and bandwidth, second- and fourth-order moments, cumulants and radius distribution.
m20 = mean(zCentered.^2);
m40 = mean(zCentered.^4);
c40 = m40 - 3 * m20^2;
phaseStep = diff(unwrap(angle(z)));
phaseMean = mean(phaseStep);
phaseStd = std(phaseStep);
Higher-order estimates need enough samples and degrade under noise. Check NaN, outliers and scale, then fit standardization on training data only.
Keep a Baseline Model
KNN, a linear classifier or a tree reveals whether gains come from the features or a more complex model. An RBF-SVM can then be organized as multiclass ECOC:
learner = templateSVM("KernelFunction", "rbf", "Standardize", true);
svmModel = fitcecoc(XTrain, YTrain, "Learners", learner, "Coding", "onevsone");
prediction = predict(svmModel, XTest);
Select model parameters from training or validation data. Repeated tuning against the test set destroys independent evaluation.
Overall Accuracy Is Not Enough
Inspect overall accuracy per SNR, recall per class, error destinations, confusion matrices across SNR and feature distributions. A single number says how much is wrong; a confusion matrix explains which signal structures are being confused.
Plot Without Overclaiming
PCA and t-SNE are exploratory and a separated 2D picture does not prove robust classification. Prefer feature distributions versus SNR, accuracy-SNR curves, normalization comparisons and waveform/spectrum/constellation views of typical errors.
Record Every Run
Save random seed, MATLAB version, class definitions, sample counts, SNR list, feature names, model parameters and split identities. Store the configuration next to each .mat model.
Extend One Variable at a Time
Frequency offset, sample-rate error, Rayleigh fading, pulse shaping and hardware captures can be added after the baseline is stable. Preserve single-variable comparisons so performance changes remain explainable.