Initial ARSS. Need to improve and add functions.

This commit is contained in:
2026-03-02 14:48:21 +09:00
commit 775668afdb
20 changed files with 1610 additions and 0 deletions
+83
View File
@@ -0,0 +1,83 @@
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 (01), 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 elementwise 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