Open oberstet opened 11 months ago
The matlab interface can define custom excitation's. I'm not sure if the C++ code has an API-interface exposed for it at this point (I need to check). If it does, the python wrapper for it would be a one-liner (as for all the other excitation) definitions.
But I'm always puzzled why anybody really wants this. I've been doing RF simulation with FDTD for decades now and I have never ever needed anything else than a Gaussian pulse. Any other pulse is just less efficient and will only result in longer simulation time for absolutely zero additional information. I'm sure that there are some oddball corner case were another excitation pulse/signal could be helpful/useful, but currently I would have no idea what that could be. But I'm always open to learn something new ;)
Anyways, since openEMS has this ability, we should make it available in the C++ and python API. Please feel free to add the missing pieces and open a Pull Request in the openEMS repository ;)
I just checked, the C++ does not expose the interface, but should be easy to add... See it as a small task to get into the openEMS code? ;)
alright;) let's see
(cpy311_7) oberstet@intel-nuci7:~/scm/3rdparty/openEMS$ find . -name "*.cpp" -exec grep -Hi "gauss" {} \;
./openems.cpp: exc->SetupGaussianPulse(f0, fc);
./openems.cpp:void openEMS::SetGaussExcite(double f0, double fc)
./openems.cpp: m_Exc->SetupGaussianPulse(f0, fc);
./FDTD/excitation.cpp:void Excitation::SetupGaussianPulse(double f0, double fc)
./FDTD/excitation.cpp: CalcGaussianPulsExcitation(m_f0,m_fc,maxTS);
./FDTD/excitation.cpp:void Excitation::CalcGaussianPulsExcitation(double f0, double fc, int nTS)
./FDTD/excitation.cpp: cerr << "Operator::CalcGaussianPulsExcitation: Requested excitation pusle would be " << Length << " timesteps or " << Length * dT << " s long. Cutting to max number of timesteps!" << endl;
https://github.com/thliebig/openEMS/blob/5f36e7f3a2367123f00999491a069aed50c6f244/FDTD/excitation.h https://github.com/thliebig/openEMS/blob/5f36e7f3a2367123f00999491a069aed50c6f244/FDTD/excitation.cpp
actually, it doesn't seem too hard. I mean, adding it right to above class - there doesn't seem to be means for custom user, after compile addition of excitation functions
I am wondering, there is a Excitation::DumpCurrentExcite
... but there is no Excitation::LoadCurrentExciteFromDump
... if there would be, plus a Python wrapper, that might actually be a lot more flexible ... than a Excitation::CalcGaussianShapedWhiteNoiseExcitation
... what do you think?
Any other pulse is just less efficient and will only result in longer simulation time for absolutely zero additional information.
I don't think this is true. For me, and again I have zero RF experience, I just understand "numbers" to a degree, a gaussian shaped white noise excitation is the natural solution to the following.
I want an excitation that excites at all frequencies all the time (while the excitation is running), and I want the excitation start with 0 energy, reach a max half time, and disappear to 0 energy again, with the energy envelope being a smooth function of time (eg differentiable), and I want to be able to freely control the overall time (excitation energy 0 to energy 0)
the natural solution is a gaussian envelope (rgd energy by time, spectral power density) over white noise. there are some details, since the gauss curve only touches 0 for infinity .. and we don't have that much time ... so lets cutoff (step function) at -60dB ... or cutoff at 2x var(gauss) ... or something.
fwiw, I we had a
void Excitation::CalcGaussianShapedWhiteNoiseExcitation(... whatever param ..., int nTS)
the power spectrum would not be real white noise (infinite frequencies, straight flat spectrum), but it would be limited by
nTS
) andI'm not sure if the latter is limited by lumped port geometry, material or what.
FDTD_FLOAT seems likely a float32 .. and hence the swing is limited by maximum dynamic range a 32 bit float can catch ... sure, it's probably good enough for sub GHz;) I am just saying. you might not see THz or PHz or whatever frequencies in the spectrum. so it is not perfect white noise .. but probably RF_GOOD_ENOUGH =)
btw, there are indeed
Excitation::SetupCustomExcite
Excitation::CalcCustomExcitation
which allows to provide a string defining a custom excitation function based on
http://warp.povusers.org/FunctionParser/fparser.html
I haven't seen it in the Python API though, and it isn't going to cut it for the white noise thing, and also not for loading previously stored excitation dumps ...
here is a sketch https://github.com/thliebig/openEMS/pull/129 ... only the skeleton so it could be discussed whether such a thing is wanted by the project anyways, if PRs are welcome, and if so, exactly how it should integrate etc
I am unsure about: code style and docs though as well, otherwise I would have added function docs with statements of what it is supposed to do before starting any implementation work ...
rgd the energy cutoffs ... the cutoffs to the gaussian envelope, the natural way of talking about "how far out" or "how unlikely" isn't "dB", but multiples of standard deviations, see eg https://introcs.cs.princeton.edu/python/appendix_gaussian/
one can transform those into dBs .. if I haven't goofed up sth, it should boil down to:
>>> import math
>>>
>>> for k in range(9):
... percentage = 1 - (1 - math.erf(k / math.sqrt(2)))
... db = int(round(math.log10(1 - percentage) * 10))
... print("k={} standard deviations: {} or {} dB".format(k, str(round(percentage * 100, 20)) + " %", db))
...
k=0 standard deviations: 0.0 % or 0 dB
k=1 standard deviations: 68.26894921370858 % or -5 dB
k=2 standard deviations: 95.44997361036415 % or -13 dB
k=3 standard deviations: 99.73002039367398 % or -26 dB
k=4 standard deviations: 99.99366575163337 % or -42 dB
k=5 standard deviations: 99.99994266968562 % or -62 dB
k=6 standard deviations: 99.99999980268247 % or -87 dB
k=7 standard deviations: 99.99999999974403 % or -116 dB
k=8 standard deviations: 99.99999999999987 % or -149 dB
-149 dB ... is really going too far .. maybe it makes sense (practically) to take "5 standard deviations" which correspond to -62 dB? what do you think?
Well I was talking about a Pull request for the missing Custom Excite API. I don't think that I will add a noise excitation any time soon. I do not see any practical use case for FDTD??? And in any case, if someone wants to play with noise excitation and different variants of it, this is what the custom excite might be good for.
Well I was talking about a Pull request for the missing Custom Excite API.
ok, understood. fwiw, if I find time, I'm going to expose it as well, added the bits in this PR (sorry, seems like the discussion is here, but the code is there, I've got confused;) anyways: https://github.com/thliebig/openEMS/pull/129
I don't think that I will add a noise excitation any time soon. I do not see any practical use case for FDTD???
right, ok. it might be a foolish idea of mine;) no worries, should I continue this, I'm just gonna run from my fork, np.
And in any case, if someone wants to play with noise excitation and different variants of it, this is what the custom excite might be good for.
are you interested in having a new excite able to read voltage/current from files previously generated ones using DumpVoltageExcite
/DumpCurrentExcite
? are you interested in having those functions exposed in Python as well?
unfortunately, I've started working on all of these in one PR .. but I could certainly sort that out and keep only what you want - should I find time and actually manage to make sth work that is;=
Sorry this thread got lost on me. Having a function to read an excitation signal would be useful I guess as then everyone can easily create whatever excitation function is desired. But that function would need to be able to interpolate as the file not necessarily should have the same sampling steps?
Please remember there is no separate voltage/current excitation signal... It needs to be the same signal just sampled at different times... (off by half a timestep)
great, thanks for noticing and commenting!
couple of comments back from my side:
But that function would need to be able to interpolate as the file not necessarily should have the same sampling steps?
I would not mix that into the responsibilities of the load function, but put the burden completely on the user of such a function.
IOWs: the user must supply excitation data with
Ideally, the data should be read/written in an open standard format for general IQ data.
A quick search turned up a format called SigMF
https://pysdr.org/content/iq_files.html
The SigMF file itself is just the pure raw IQ in numpy (array of complex128 or what). obviously that has been recognized by the PySDR guys
SigMF and Annotating IQ Files Since the IQ file itself doesn’t have any metadata associated with it, it’s common to have a 2nd file, containing information about the signal, with the same filename but a .txt or other file extension. This should at a minimum include the sample rate used to collect the signal, and the frequency to which the SDR was tuned.
Personally, I think what would be even better, and an extension:
both the raw IQ data file, and the metadata file, and e.g. a human-readable text file (a README.txt) should then be ZIP'ed into one archive file
the 3 files contained in such a IQ ZIP should then have standard/predefined names, like
The most simple (and minimal) way to use the SigMF standard to describe a binary IQ file you have created is to rename the .iq file to .sigmf-data and create a new file with the same name but .sigmf-meta extension, and make sure the datatype field in the meta file matches the binary format of your data file.
for example, one qpsk_in_noise.zip with contents:
signal.sigmf-data
signal.sigmf-meta
README.txt
here is more info about SigMF:
fwiw, and here is what an AI says about SigMF - which sounds mostly cool/good/correct to me. Just that I very much prefer the native binary signal formatting that PySDR uses: numpy complex128! rather than "XML or JSON format". at least for the IQ data.
one major reason is: I can mmap
a native binary with numpy complex128 and start running native code on that without any additional memory usage or pressure from parsing and recreating a run-time repr. of the IQ data
for the metadata, I'd definitely prefer JSON rather than XML, and in fact maybe YAML instead of JSON, but that's just because writing is much nicer in YAML ... anyways, details.
Q:
Can you describe (in technical detail) the open file format "SigMF" for storing/transporting general "IQ sample" data?
A:
SigMF (Signal Metadata Format) is an open file format designed for storing and transporting general "IQ sample" data, commonly used in software-defined radio (SDR) applications and other signal processing tasks. The format aims to provide a standardized way to describe and exchange signal datasets along with their associated metadata. Here's a technical description of the SigMF format:
File Structure:
Metadata:
global
metadata: Information applicable to the entire dataset.captures
metadata: Information specific to individual captures within the dataset.sample_rate
: Sampling rate of the IQ samples.center_frequency
: Center frequency of the signal.data_type
: Data type of the IQ samples (e.g., complex64, complex128).description
: Brief description of the signal.annotations
: Additional notes or annotations related to the signal.author
: Name of the person or entity who captured the data.license
: Licensing information for the data.timestamp
: Timestamp indicating when the data was captured.Data:
data_type
in the metadata.Usage:
Extensibility:
In summary, SigMF is a flexible and extensible file format for storing and transporting IQ sample data, providing a standardized way to describe signal datasets and their associated metadata. Its adoption helps promote interoperability and facilitates collaboration in the field of software-defined radio and signal processing.
one final thought: what about multi-channel IQ data?
say I have 4 excitation ports defined in my openEMS model (and no, I haven't done that yet even though I am very much interested .. for phased arrays and such ..)
can I load IQ excitation data for all 4 ports from 1 file and run the excitation on all ports synchronized / in parallel?
Q:
How would I use SigML for multi-channel IQ data e.g. in the context of Phased Arrays?
A:
In the context of phased arrays or multi-channel IQ data, SigMF can be extended to accommodate the specific requirements of handling multiple channels. Here's how you could use SigMF for multi-channel IQ data:
Metadata Extension:
Channelized Data:
Channel Enumeration:
Timestamp Synchronization:
Array Geometry:
Data Representation:
By extending SigMF in this way, you can effectively represent multi-channel IQ data in the context of phased arrays or similar applications. This enables standardized storage, exchange, and analysis of multi-channel RF datasets, facilitating interoperability and collaboration among researchers and developers working in the field.
Right. I hadn't thought of storing phased array geometry metadata ..
Wow this is going very wild here? IQ data? The FDTD method is a time-domain method. It has no concept of frequencies or complex numbers what so ever.
The only thing that would make any kind of sense to read in as en excitation signal (from a file) would be a simple ASCII file with two columns, one is time, the second is the time-signal, e.g. a Gaussian pulse or whatever the user desires and that the FDTD method can handle, e.g. the signal must be band-limitied...
And I repeat, only a single, simple, scalar time-signal is possible, nothing multi-channel, nothing complex or anything of that sort.
I think that there is still a major misconception about what FDTD is, what it can do and what it is supposed to do....
I think it would be better we do this in a github Discussion not as an issue? And then we sort out what the feature request actually is. If it is something related to simulation setup or more to a higher level data post-processing, e.g. in a circuit simulation where IQ and multi-channel and all that is another story...
IQ data? The FDTD method is a time-domain method. It has no concept of frequencies or complex numbers what so ever.
Not sure I am following, isn't
It needs to be the same signal just sampled at different times... (off by half a timestep)
hinting at 90° (the "half timestep"), and isn't
there is no separate voltage/current excitation signal.
just "a detail" .. as in: it's 2 vectors of real numbers?
but in any case, you are right, probably better in a discussion format .. lemme know / pls link here once/if you start one ..
btw: as repo owner you should also be able to convert this whole issue in aggregate into a discussion preserving the contents above .. using one button click (top right usually .. "convert to discussion" or sth)
During a discussion here https://github.com/thliebig/openEMS-Project/discussions/152#discussioncomment-7730788, the question of whether it is possible, and if so, how to create and use a custom excitation in openEMS.
If that is possible or even supported, ideally from Python, but if not I'd be good with a way using C++ as well (fwiw, if so I might find time to add Python wrappers then as well).
Here is the concrete question:
In openEMS, and also in the Python API of openEMS, there are a few built-in excitation functions, like e.g.
SetGaussExcite
.Is it possible to use openEMS with a custom excitation function, such as for example a continuous white noise spectrum shaped by a single Gaussian envelope over a multi-second time scale and with the source of randomness to generate the white noise coming from a PRNG instance seeded from a user supplied value?