Skip to content

Commit

Permalink
Add resync example and docs
Browse files Browse the repository at this point in the history
  • Loading branch information
nHackel committed Dec 13, 2024
1 parent 2a8da4a commit cefe237
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 2 deletions.
3 changes: 2 additions & 1 deletion docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ makedocs(
"Sequence Ramping" => "examples/seqRamping.md",
"Cluster" => "examples/cluster.md",
"Batch" => "examples/batch.md",
"Continous Signal Acquisition" => "examples/producerConsumer.md"],
"Continous Signal Acquisition" => "examples/producerConsumer.md",
"Resync" => "examples/resync.md",],
"FPGA Development" => "fpga.md",
"Development Tips" => "devtips.md",
#"Getting Started" => "overview.md",
Expand Down
Binary file added docs/src/assets/resync.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 21 additions & 0 deletions docs/src/examples/resync.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Resync Example

In this example we add a resync signal to a [sequence](sequence.md) to create a signal that resynchronizes phase and frequency of the DACs after every frame. This can be used to change the frequency and phase of a signal during measurement. While the resynchronization is synchronous due to the sequences, the actual new frequency and phase information is asynchronous as they are transmitted via SCPI.

The example constructs a sequence with no offset and the very last step has the resync flag enabled. Note that during the resync-step the DAC outputs zero.

## Julia Client

This and all other examples are located in the ```examples``` [directory](https://github.com/tknopp/RedPitayaDAQServer/tree/master/src/examples/julia)

````@eval
# Adapted from https://github.com/JuliaDocs/Documenter.jl/issues/499
using Markdown
Markdown.parse("""
```julia
$(open(f->read(f, String), "../../../src/examples/julia/resync.jl"))
```
""")
````

![Resync Example Results](../assets/resync.png)
2 changes: 1 addition & 1 deletion docs/src/generation.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ As the LUT used by the FPGA image is small in comparison with the main memory an

Comparable to the sample transmission of the acquisition, this updating of the LUT is also a process with timing uncertainty as it is affected by the scheduling and execution of the RedPitayas CPU. While during the sample transmission samples could be lost because they were overwritten, in the signal generation wrong signals could be output because the server was too slow in updating the values. Here, the server tracks similar performance metrics and also features a status flag `lostSteps` for exactly this case. In its current implementation a safe step rate is at 12 kHz.

Sequences and their steps also have additional features. A step can be marked such that during its duration the signal is set to 0. Furthermore, a step can be marked such that it triggers the ramp down. To make this easier to manage the server actually manages three sequences, that can be set individually: A ramp up, regular and ramp down sequence. The ramp up sequence is moved to the FPGA LUT at the acquisition start, followed by the regular sequence. Afterwards the ramp down sequence is started and during its execution the ramp down flag is set.
Sequences and their steps also have additional features. A step can be marked such that during its duration the signal is set to 0. Furthermore, a step can be marked such that it triggers the ramp down. To make this easier to manage the server actually manages three sequences, that can be set individually: A ramp up, regular and ramp down sequence. The ramp up sequence is moved to the FPGA LUT at the acquisition start, followed by the regular sequence. Afterwards the ramp down sequence is started and during its execution the ramp down flag is set. Steps can also be marked to resync the fast DACs. During a resync, the signals are set to 0 and afterwards start again with their set phase and frequency. This can be used to change frequency and phase during measurements and s.t. the new phase and frequency is synchronous to the steps.

## Calibration
Similar to the signal acquisition, there are also calibration scale ``c_{i, scale}`` and offset ``c_{i, offset}`` values for the signal generation. These are stored in the EEPROM of the RedPitaya and can be updated by a client. The calibration values are always applied, even when the master trigger is off.
Expand Down
1 change: 1 addition & 0 deletions docs/src/scpi.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ During an active trigger the buffer is periodically updated by the server. If th
| RP:DAC:SEQ:CHan? | | Return the number of sequence channel | | |
| RP:DAC:SEQ:LUT | steps, repetitions | Instruct the server to receive a LUT over the data socket | C | RP:DAC:SEQ:LUT 10,2 |
| RP:DAC:SEQ:LUT:ENaBle | | Instruct the server to receive an enable LUT over the data socket of the same shape as the regular LUT| C | |
| RP:DAC:SEQ:LUT:ReSYNC | | Instruct the server to receive a resync LUT over the data socket of the same shape as the regular LUT| C | |
| RP:DAC:SEQ:LUT:UP | steps, repetitions | Instruct the server to receive a ramp up LUT over the data socket | C | |
| RP:DAC:SEQ:LUT:DOWN | steps, repetitions | Instruct the server to receive a ramp down LUT over the data socket | C | |
| RP:DAC:SEQ:CLEAR | | Clear the set sequence values from the FPGA buffer | C | |
Expand Down
78 changes: 78 additions & 0 deletions src/examples/julia/resync.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using RedPitayaDAQServer
using CairoMakie

# obtain the URL of the RedPitaya
include("config.jl")

rp = RedPitaya(URLs[1])
serverMode!(rp, CONFIGURATION)

dec = 32
modulus = 124800
base_frequency = 125000000
periods_per_step = 5
samples_per_period = div(modulus, dec)
periods_per_frame = 50
frame_period = dec*samples_per_period*periods_per_frame / base_frequency
steps_per_frame = div(50, periods_per_step)

decimation!(rp, dec)
samplesPerPeriod!(rp, samples_per_period)
periodsPerFrame!(rp, periods_per_frame)

for i in 1:2
frequencyDAC!(rp, i, 1, base_frequency / modulus)
signalTypeDAC!(rp, i, 1, "SINE")
amplitudeDAC!(rp, i, 1, 0.2)
phaseDAC!(rp, i, 1, 0)
end
triggerMode!(rp, INTERNAL)

# Sequence Configuration
clearSequence!(rp)
stepsPerFrame!(rp, steps_per_frame)
seqChan!(rp, 2)
lut = reshape(fill(0.0f0, steps_per_frame), 1, :)
lut = repeat(lut, outer = 2)
enable = collect(fill(true, steps_per_frame))
enable = reshape(enable, 1, :)
enable = repeat(enable, outer = 2)
# In the last step of each frame we resync the DACs
resync = vcat(fill(false, steps_per_frame - 1), [true])
resync = reshape(resync, 1, :)
resync = repeat(resync, outer = 2)
seq = SimpleSequence(lut, 2, enable, resync)
sequence!(rp, seq)

samples_per_frame = samples_per_period * periods_per_frame
target = samples_per_frame * 0.3 # After a third of a frame we want to switch frequency

serverMode!(rp, ACQUISITION)
masterTrigger!(rp, true)

# Wait until we reach the target sample
curr = currentWP(rp)
while curr < target
# NOP
global curr = currentWP(rp)
sleep(0.01)
end

# Update the phase and frequency of the second channel
frequencyDAC!(rp, 2, 1, base_frequency / (2*modulus))
phaseDAC!(rp, 2, 1, pi)

data = readFrames(rp, 0, 2)

masterTrigger!(rp, false)
serverMode!(rp, CONFIGURATION)


fig = Figure()
lines(fig[1, 1], vec(data[:, 2, :, 1]), axis = (ylabel = "First Frame", title = "All Periods"))
lines(fig[1, 2], vec(data[:, 2, 1:5, 1]), axis = (ylabel = "First Frame", title = "First Periods"))
lines(fig[2, 1], vec(data[:, 2, :, 2]), axis = (ylabel = "Second Frame",))
lines(fig[2, 2], vec(data[:, 2, 1:5, 2]), axis = (ylabel = "Second Frame",))

save(joinpath(@__DIR__(), "images", "resync.png"), fig)
fig

0 comments on commit cefe237

Please sign in to comment.