84 lines
3.3 KiB
Matlab
84 lines
3.3 KiB
Matlab
function spur = generate_spur(SpurParams, t, baseSignal)
|
||
%GENERATE_SPUR create spur signals based on a parameter structure
|
||
% spur = GENERATE_SPUR(SpurParams, t, baseSignal)
|
||
% t : time vector (row or column)
|
||
% baseSignal : (optional) complex baseband signal used for some spur
|
||
% mechanisms such as mixer nonlinearity. If omitted the
|
||
% function will only generate independent tones.
|
||
%
|
||
% SpurParams is a struct that may contain any of the following fields
|
||
% .lo : struct with fields amp, freq, phase (optional) -
|
||
% LO-related spur added to phase of signal
|
||
% .mixer : struct with fields alpha2, alpha3 - coefficients for
|
||
% 2nd/3rd order nonlinearity. Requires baseSignal input.
|
||
% .adc : struct with fields amp, freq, phase - tone added after
|
||
% ADC (complex). Does not require baseSignal.
|
||
% .switch : struct with fields amp, freq - square/pulse spur
|
||
% .pulse : struct with fields amp, freq, duty (0–1), phase -
|
||
% periodic gating/pulse train (lock) added to output
|
||
%
|
||
% Example:
|
||
% SpurParams = struct();
|
||
% SpurParams.lo = struct('amp',0.01,'freq',1e6,'phase',0);
|
||
% SpurParams.mixer= struct('alpha2',1e-4,'alpha3',1e-6);
|
||
% SpurParams.adc = struct('amp',1e-3,'freq',2e6,'phase',0);
|
||
% SpurParams.switch = struct('amp',5e-4,'freq',5e5);
|
||
% SpurParams.pulse = struct('amp',0.02,'freq',500e3,'duty',0.1,'phase',0);
|
||
% 위 설정은 LO 스퍼, 믹서 비선형, ADC 톤, 스위칭
|
||
% 잡음에 더해 10% duty pulse train 락킹까지 포함합니다.
|
||
%
|
||
% The returned spur vector has the same dimensions as t. If baseSignal
|
||
% is supplied the mixer nonlinearity is computed element‑wise using that
|
||
% signal; otherwise only independent spur terms are returned.
|
||
|
||
if nargin < 3
|
||
baseSignal = [];
|
||
end
|
||
% ensure t is row for consistent operations
|
||
t = t(:)';
|
||
spur = zeros(size(t));
|
||
|
||
if isfield(SpurParams, 'lo')
|
||
p = SpurParams.lo;
|
||
phase = 0;
|
||
if isfield(p, 'phase'); phase = p.phase; end
|
||
spur = spur + p.amp .* sin(2*pi*p.freq .* t + phase);
|
||
end
|
||
|
||
if isfield(SpurParams, 'mixer') && ~isempty(baseSignal)
|
||
m = SpurParams.mixer;
|
||
% apply polynomial nonlinearity to the provided base signal
|
||
if isfield(m, 'alpha2')
|
||
spur = spur + m.alpha2 .* (baseSignal.^2);
|
||
end
|
||
if isfield(m, 'alpha3')
|
||
spur = spur + m.alpha3 .* (baseSignal.^3);
|
||
end
|
||
end
|
||
|
||
if isfield(SpurParams, 'adc')
|
||
a = SpurParams.adc;
|
||
phase = 0;
|
||
if isfield(a, 'phase'); phase = a.phase; end
|
||
spur = spur + a.amp .* exp(1j*(2*pi*a.freq .* t + phase));
|
||
end
|
||
|
||
if isfield(SpurParams, 'switch')
|
||
s = SpurParams.switch;
|
||
spur = spur + s.amp .* square(2*pi*s.freq .* t);
|
||
end
|
||
|
||
if isfield(SpurParams, 'pulse')
|
||
p = SpurParams.pulse;
|
||
% duty default 50%
|
||
duty = 0.5;
|
||
if isfield(p,'duty'); duty = p.duty; end
|
||
phase = 0;
|
||
if isfield(p,'phase'); phase = p.phase; end
|
||
% generate pulse train (0/1) scaled by amp
|
||
% square with duty cycle multiplied then shifted to [0,1]
|
||
pulse_wave = (square(2*pi*p.freq .* t + phase, duty*100)+1)/2;
|
||
spur = spur + p.amp .* pulse_wave;
|
||
end
|
||
end
|