Your premise is flawed. LTspice has a feature called a "FREQ table", which was mainly included for PSpice compatibility. The syntax and explanation of its basic use can be found here:
https://ltwiki.org/?title=Undocumented_LTspice#B-Sources
https://ltwiki.org/index.php?title=B_sources_(complete_reference)
The jist is you can define a voltage/current source using a linearly interpolated table of (frequency, magnitude, phase) triplets. Think of it as a frequency domain PWL source. Using it to define a resistor (or more generally, an impedance) is a little tricky. But if you know the tricks, it can be done.
I'm going to show the first example using the most generalized form because it makes the most sense in terms of the syntax. The component we're going to use is the current form of the B-source (bi
in symbol library). We're going to set its value to I=V(out,0)/1
which is the voltage across it V(out,0)
divided by 1
(it'll make sense why I included this 1
later). If you step back now, you'll see that this component represents a 1Ω resistor. Now, the way the FREQ table works is it'll multiply this expression by each value (magnitude/phase) at each frequency. So if we want the resistance to change at 1k, 10k, and 100k we can tack this onto the end of the I=V(out,0)/1
expression, or I personally prefer to add it to the next value line, i.e. Value2
.
MAG FREQ=(1k,{1/1k},0) (10k,{1/2k},0) (100k,{1/3k},0)
The default units for the magnitude are in dB, so the MAG
keyword sets it to non-dB. The magnitudes are defined in 1/Z
form because we want the Z
to multiply with V(out,0)/1
to result in V(out,0)/Z
. An alternative to using {1/Z}
is using {Z**-1}
but I think the former is easier to look at. The curly braces are needed to force LTspice to evaluate the expression to a number. All the phases are zero for this "resistor". Simulating, we get this which is exactly what we wanted:
NOTE: Keep in mind that values outside of the table get extrapolated to the left and right, which is why you get horizontal lines there.
As many people know, LTspice includes something called a "behavioral resistor" which is used whenever you define a resistance in the form R=<expression>
. Actually, what LTspice does under the hood is converts this to a behavioral current source, exactly in the same way we did above. So a behavioral resistor with R=1
is exactly the same as our I=V(out,0)/1
current source. The upside is that you don't have to manually define the voltage across it. The downside is that the syntax is goofy when using the FREQ table with a behavioral resistor, and it's because the FREQ table applies its values to the expression AFTER it's converted to a current source. So even though you define the resistor as R=1
, you still need to put your values in the form 1/Z
like we did before. Long story short, if you want to do the same exactly thing we did above but use a behavioral resistor component, it will look like this:

Since this can be used to define any kind of impedance, you can do capacitors and inductors too. Here is an example defining a capacitor in FREQ table form in order to match an actual capacitor of 100nF. Just as before, you would define the magnitude of the impedance as 1/Z
. Since |Z|=2*π*f*C
for a capacitor, we put the magnitudes in the form of 2*π*f*C
. Phase of a capacitor is 90º, so we put 90 for all the phases. Notice with just 4 points defined, the plots overlap almost completely within the frequency decades containing defined values.

One big caveat that should be known is that LTspice treats the FREQ table much like its Laplace
feature. Therefore, this blurb from the LTspice Help file mostly applies to FREQ tables, especially the part regarding time domain solutions (which applies to .tran
simulations):
If an optional Laplace transform is defined, that transform is applied
to the result of the behavioral current or voltage. The Laplace
transform must be a function solely of s. The Boolean XOR operator, ^,
is understood to mean exponentiation, **, when used in a Laplace
expression. The frequency response at frequency f is found by
substituting s with sqrt(-1)2pi*f. The time domain behavior is found
from the sum of the instantaneous current(or voltage) with the
convolution of the history of this current(or voltage) with the
impulse response. Numerical inversion of a Laplace transfer function
to the time domain impulse response is a potentially compute-bound
process and a topic of current numerical research. In LTspice, the
impulse response is found from the FFT of a discrete set points in
frequency domain response. This process is prone to the usual
artifacts of FFT's such as spectral leakage and picket fencing that is
common to discrete FFT's. LTspice uses a proprietary algorithm that
exploits that it has an exact analytical expression for the frequency
domain response and chooses points and windows to cause such artifacts
to diffract precisely to zero. However, LTspice must guess an
appropriate frequency range and resolution. It is recommended that the
LTspice first be allowed to make a guess at this. The length of the
window and number of FFT data points used will be reported in the .log
file. You can then adjust the algorithm's choices by explicitly
setting nfft and window length. The reciprocal of the value of the
window is the frequency resolution. The value of nfft times this
resolution is the highest frequency considered. Note that the
convolution of the impulse response with the behavioral source is also
potentially a compute bound process.
Basically, what this means is that any .tran
simulations containing FREQ tables and/or Laplace functions can result in numerical artifacts and funky results. LTspice also gives you two parameters nfft
and window
which you can tweak to try and get better behavior from the source in question.
Is there a FOSS simulator that can be used instead of LTspice? I love
the program as much as anybody but the closed source limitations are
really a big drag.
I really like ngspice, but it does not have the FREQ table feature implemented yet. There is a post in this thread by an ngspice developer asking for someone's contribution in creating the code. If you like, you can give it a shot.
https://forum.kicad.info/t/import-target-function-for-ngspice/26907/5
Last thing I want to point out. Usually the reason why people ask the type question you are is because they are intending to import S-parameters into SPICE. There is a command line program called s2spice
created by a user on the LTspice Google Groups (accessing files requires an account) which creates a subcircuit from an S-parameters file. A bunch of the RF-heads on the group use this program for their work.
https://groups.io/g/LTspice/files/z_yahoo/Tut/S-Parameter/s2spice.doc
https://groups.io/g/LTspice/files/z_yahoo/Tut/S-Parameter/S-Parameter%20to%20SPICE/s2spice101.exe
More recently, someone on the groups ported it into a GUI program. That version can be found here:
https://github.com/transmitterdan/s2spice