{"id":19195258,"url":"https://github.com/quartiq/miqro-sim","last_synced_at":"2026-02-03T12:32:15.080Z","repository":{"id":229198220,"uuid":"629581948","full_name":"quartiq/miqro-sim","owner":"quartiq","description":"MIQRO pulse generator simulator","archived":false,"fork":false,"pushed_at":"2025-10-15T10:43:59.000Z","size":357,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-01-27T16:49:52.091Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/quartiq.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-04-18T15:45:27.000Z","updated_at":"2025-10-15T10:44:03.000Z","dependencies_parsed_at":"2024-03-22T18:33:02.745Z","dependency_job_id":"99fa4d06-9153-48b3-905c-ef4a8ba99043","html_url":"https://github.com/quartiq/miqro-sim","commit_stats":null,"previous_names":["quartiq/miqro-sim"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/quartiq/miqro-sim","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quartiq%2Fmiqro-sim","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quartiq%2Fmiqro-sim/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quartiq%2Fmiqro-sim/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quartiq%2Fmiqro-sim/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/quartiq","download_url":"https://codeload.github.com/quartiq/miqro-sim/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quartiq%2Fmiqro-sim/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29045913,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-03T10:09:22.136Z","status":"ssl_error","status_checked_at":"2026-02-03T10:09:16.814Z","response_time":96,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-09T12:09:19.510Z","updated_at":"2026-02-03T12:32:15.068Z","avatar_url":"https://github.com/quartiq.png","language":"Python","readme":"# MIQRO simulator\n\nThis is a small simulator for the MIQRO Phaser gateware and its ARTIQ interface. It's intended for experimentation and quick evaluation of the capabilities and the API. The output from the simulation can directly be used as input when integrating the differential equation of one or multiple qubits.\n\nThis work is sponsored in part by the Federal Ministry of Education and Research (BMBF) under contract 13N15524.\n\n## Resources\n\nThe ARTIQ MIQRO coredevice driver documentation in the [ARTIQ Manual](https://m-labs.hk/artiq/manual-beta/core_drivers_reference.html#artiq.coredevice.phaser.Miqro) and here [miqro.py](miqro.py) describes the functionality and the signal flow.\n\n## Architecture\n\n![MIQRO Architecture diagram](img/miqro_diagram.png)\n\n\n## Data flow description\n\nA Miqro instance represents one RF output. The DSP components are fully\ncontained in the Phaser gateware. The output is generated by with\nthe following data flow:\n\n### Oscillators\n\n* There are `n_osc = 16` oscillators with oscillator indices `0..n_osc-1`.\n* Each oscillator outputs one tone at any given time\n  * I/Q (quadrature, a.k.a. complex) 2x16 bit signed data\n    at `tau = 4 ns` sample intervals, 250 MS/s, Nyquist 125 MHz, bandwidth 200 MHz\n    (from `f = -100..+100 MHz`, taking into account the interpolation anti-aliasing\n    filters in subsequent interpolators),\n  * 32 bit frequency (`f`) resolution (~ 1/16 Hz),\n  * 16 bit unsigned amplitude (`a`) resolution\n  * 16 bit phase offset (`p`) resolution\n* The output phase `p'` of each oscillator at time `t` (boot/reset/initialization of the\n    device at `t=0`) is then `p' = f*t + p (mod 1 turn)` where `f` and `p` are the (currently\n    active) profile frequency and phase offset.\n* Note: The terms  \"phase coherent\" and \"phase tracking\" are defined to refer to this\n    choice of oscillator output phase `p'`. Note that the phase offset `p` is not relative to\n    (on top of) previous phase/profiles/oscillator history.\n    It is \"absolute\" in the sense that frequency `f` and phase offset `p` fully determine\n    oscillator output phase `p'` at time `t`. This is unlike typical DDS behavior.\n* Frequency, phase, and amplitude of each oscillator are configurable by selecting one of\n    `n_profile = 32` profile with indices `0..n_profile-1`. This selection is fast and can be done for\n    each pulse. The phase coherence defined above is guaranteed for each\n    profile individually.\n* Note: one profile per oscillator (usually profile index 0) should be reserved\n    for the NOP (no operation, identity) profile, usually with zero amplitude.\n* Data for each profile for each oscillator can be configured\n    individually. Storing profile data should be considered \"expensive\". \"expensive\" does not mean it is\n    impossible, just that it may take a significant amount of time and\n    resources to execute such that it may be impractical when used often or\n    during fast pulse sequences. They are intended for use in calibration and\n    initialization.\n\n### Summation\n\n* The oscillator outputs are added together (wrapping addition).\n* The user must ensure that the sum of oscillators outputs does not exceed the\n    data range. In general that means that the sum of the amplitudes must not\n    exceed one.\n\n### Shaper\n\n* The summed complex output stream is then multiplied with a the complex-valued\n    output of a triggerable shaper.\n* Triggering the shaper corresponds to passing a pulse from all oscillators to\n    the RF output.\n* Selected profiles become active simultaneously (on the same output sample) when\n    triggering the shaper with the first shaper output sample.\n* The shaper reads (replays) window samples from a memory of size `n_window = 1 \u003c\u003c 10`.\n* The window memory can be segmented by choosing different start indices\n    to support different windows.\n* Each window memory segment starts with a header determining segment\n    length and interpolation parameters.\n* The window samples are interpolated by a factor (rate change) between 1 and\n    `r = 1 \u003c\u003c 12`.\n* The interpolation order is constant, linear, quadratic, or cubic. This\n    corresponds to interpolation modes from rectangular window (1st order CIC)\n    or zero order hold) to Parzen window (4th order CIC or cubic spline).\n* This results in support for single shot pulse lengths (envelope support) between\n    tau and a bit more than `r * n_window * tau = (1 \u003c\u003c 12 + 10) tau ~ 17 ms`.\n* Windows can be configured to be head-less and/or tail-less, meaning, they\n    do not feed zero-amplitude samples into the shaper before and after\n    each window respectively. This is used to implement pulses with arbitrary\n    length or CW output.\n\n### Overall properties\n\n* The DAC may upconvert the signal by applying a frequency offset f1 with\n    phase p1.\n* In the Upconverter Phaser variant, the analog quadrature upconverter\n    applies another frequency of f2 and phase p2.\n* The resulting phase of the signal from one oscillator at the SMA output is\n    `(f + f1 + f2)*t + p + s(t - t0) + p1 + p2 (mod 1 turn)`\n    where `s(t - t0)` is the phase of the interpolated\n    shaper output, and `t0` is the trigger time (fiducial of the shaper).\n    Unsurprisingly the frequency is the derivative of the phase.\n* Group delays between pulse parameter updates are matched across oscillators,\n    shapers, and channels.\n* The minimum time to change profiles and phase offsets is ~128 ns (estimate, TBC).\n    This is the minimum pulse interval.\n    The sustained pulse rate of the RTIO PHY/Fastlink is one pulse per Fastlink frame\n    (may be increased, TBC).\n\n## Simulator output\n\nGiven the [example experiment](example.py):\n\n```python\n\nclass Example(EnvExperiment):\n    def build(self):\n        self.phaser0 = miqro.Phaser()\n        self.miqro0 = self.phaser0.channel0.miqro\n\n    @kernel\n    def setup(self):\n        # Configure example data for some profiles on some oscillators\n        # e.g.: profile 3 on oscillator 11 will be 3 MHz, 0.3 amplitude full scale,\n        # -0.3 turn (coherent) phase\n        for osc in [0, 4, 11]:\n            for profile in [1, 2, 3]:\n                self.miqro0.set_profile(\n                    osc,\n                    profile,\n                    frequency=1 * MHz * (osc - 8),\n                    amplitude=0.1 * profile,\n                    phase=-0.1 * profile,\n                )\n        # Configure some window data and interpolation parameters\n        iq = [(1, 0), (1, 0), (0, 1), (0, 1)]\n        # Pulse shape will be:\n        # * n = len(iq) = 4 samples full scale\n        # * Note the window has a pi/2 phase shift for the second half.\n        # * r = 128 cubic (Parzen window) interpolation:\n        #   Each window memory sample will last r tau = 512 ns and those samples\n        #   will see cubic interpolation like this:\n        #   Repeat each input sample r = 128 times, convolve the sequence of\n        #   n * r samples with a rectangular window of length r = 128.\n        #   Do that order = 3 times.\n        # * The output of the shaper is thus a rise to full scale,\n        #   and then a pi/2 phase shift, then a tail to zero again, all \"smooth\"\n        #   in the sense of cubic interpolation: a continuous second derivative\n        #   of I and Q (piecewise constant third derivative).\n        # * Total pulse duration (shape support) is ((n + order) * r - order) * tau = 3.572 µs.\n        self.miqro0.set_window(start=0, iq=iq, period=128 * 4 * ns, order=3)\n\n    @kernel\n    def pulse(self):\n        # Choose example profiles and phase offsets\n        # profiles[oscillator index] = profile index\n        profiles = [0] * 16\n        profiles[0] = 1\n        profiles[4] = 2\n        profiles[11] = 3\n        # Choose window start address\n        window = 0x000\n        # Trigger the pulse\n        # This will load frequencies and amplitudes for the oscillators,\n        # compute the initial oscillator phases, add the offsets,\n        # load the window samples, interpolate them and multiply the window with\n        # the sum of the oscillator outputs, all in gateware with matched latency accross\n        # all data paths. The DAC will interpolate further (by 4),\n        # shift everything by frequency f1 and then the IQ mixer will shift\n        # further by f2.\n        # The encoded pulse words can just as well be computed offline with `encode()` and then emitted with `pule_mu()` for even higher rates.\n        self.miqro0.pulse(window, profiles)\n\n    @kernel\n    def run(self):\n        # self.phaser0.init()\n        # self.miqro0.reset()\n        self.setup()\n        self.pulse()\n```\n\n![MIQRO simulator output](img/miqro_sim_output.png)\n\n## Actual gateware output\n\nFor a 16-tone pulse train (limited in phase noise, noise floor, dynamic range, and distortion by measurement equipment):\n\n![MIQRO scope analysis](img/miqro_wide_16cw.png)\n\n![MIQRO spectrum](img/miqro_16tone_cic4_impulse_4gs.png)\n\n![MIQRO upconverter spectrum](img/miqro_upconverter_16cw.png)\n\n## Simulator accuracy/features\n\nThe API and features described and implemented here may be slightly different from the actual gateware/ARTIQ implementation. Check back before relying on it.\n\nDifferences are:\n\n* Integer quantization of samples not implemented\n* NCO/DDS spurs, phase truncation not modelled\n* IQ data overflow not implemented\n* Overall latency not implemented\n* Rounding not implemented\n* Window head/tail features not implemented\n* Lots of ARTIQ features (DMA, other devices, device db, datasets, ...)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fquartiq%2Fmiqro-sim","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fquartiq%2Fmiqro-sim","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fquartiq%2Fmiqro-sim/lists"}