Skip to content

Commit

Permalink
Merge #352
Browse files Browse the repository at this point in the history
352: Refactoring lockin binaries r=ryan-summers a=ryan-summers

This PR merges `lockin-external` and `lockin-internal` into a single binary.

This has also refactored the output configuration to make it more configurable. This was needed to work well with the reference signal generation, as that output should necessarily just override a different setting.

Co-authored-by: Ryan Summers <[email protected]>
Co-authored-by: Robert Jördens <[email protected]>
  • Loading branch information
3 people authored May 6, 2021
2 parents ed34b69 + 97cca48 commit bde0b0a
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 182 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ jobs:
- run: >
zip bin.zip
target/*/release/dual-iir
target/*/release/lockin-external
target/*/release/lockin-internal
target/*/release/lockin
- id: create_release
uses: actions/create-release@v1
env:
Expand Down
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,7 @@ to implement different use cases. Several applications are provides by default
* anti-windup
* derivative kick avoidance

### Lockin external

### Lockin internal
### Lockin

## Minimal bootstrapping documentation

Expand Down
143 changes: 0 additions & 143 deletions src/bin/lockin-internal.rs

This file was deleted.

104 changes: 70 additions & 34 deletions src/bin/lockin-external.rs → src/bin/lockin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,34 @@ use stabilizer::hardware::{
use miniconf::Miniconf;
use stabilizer::net::{Action, MqttInterface};

// A constant sinusoid to send on the DAC output.
// Full-scale gives a +/- 10.24V amplitude waveform. Scale it down to give +/- 1V.
const ONE: i16 = ((1.0 / 10.24) * i16::MAX as f32) as _;
const SQRT2: i16 = (ONE as f32 * 0.707) as _;
const DAC_SEQUENCE: [i16; design_parameters::SAMPLE_BUFFER_SIZE] =
[ONE, SQRT2, 0, -SQRT2, -ONE, -SQRT2, 0, SQRT2];

#[derive(Copy, Clone, Debug, Deserialize, Miniconf)]
enum Conf {
PowerPhase,
FrequencyDiscriminator,
Magnitude,
Phase,
ReferenceFrequency,
LogPower,
InPhase,
Quadrature,
Modulation,
}

#[derive(Copy, Clone, Debug, Miniconf, Deserialize, PartialEq)]
enum LockinMode {
Internal,
External,
}

#[derive(Copy, Clone, Debug, Deserialize, Miniconf)]
pub struct Settings {
afe: [AfeGain; 2],
lockin_mode: LockinMode,

pll_tc: [u8; 2],

Expand All @@ -43,13 +61,15 @@ impl Default for Settings {
Self {
afe: [AfeGain::G1; 2],

lockin_mode: LockinMode::External,

pll_tc: [21, 21], // frequency and phase settling time (log2 counter cycles)

lockin_tc: 6, // lockin lowpass time constant
lockin_harmonic: -1, // Harmonic index of the LO: -1 to _de_modulate the fundamental (complex conjugate)
lockin_phase: 0, // Demodulation LO phase offset

output_conf: [Conf::Quadrature; 2],
output_conf: [Conf::InPhase, Conf::Quadrature],
}
}
}
Expand Down Expand Up @@ -137,29 +157,45 @@ const APP: () = {
c.resources.adcs.1.acquire_buffer(),
];

let dac_samples = [
let mut dac_samples = [
c.resources.dacs.0.acquire_buffer(),
c.resources.dacs.1.acquire_buffer(),
];

let lockin = c.resources.lockin;
let settings = c.resources.settings;

let timestamp =
c.resources.timestamper.latest_timestamp().unwrap_or(None); // Ignore data from timer capture overflows.
let (pll_phase, pll_frequency) = c.resources.pll.update(
timestamp.map(|t| t as i32),
settings.pll_tc[0],
settings.pll_tc[1],
);
let (reference_phase, reference_frequency) = match settings.lockin_mode
{
LockinMode::External => {
let timestamp =
c.resources.timestamper.latest_timestamp().unwrap_or(None); // Ignore data from timer capture overflows.
let (pll_phase, pll_frequency) = c.resources.pll.update(
timestamp.map(|t| t as i32),
settings.pll_tc[0],
settings.pll_tc[1],
);
(
pll_phase,
(pll_frequency
>> design_parameters::SAMPLE_BUFFER_SIZE_LOG2)
as i32,
)
}
LockinMode::Internal => {
// Reference phase and frequency are known.
(
1i32 << 30,
1i32 << (32 - design_parameters::SAMPLE_BUFFER_SIZE_LOG2),
)
}
};

let sample_frequency = ((pll_frequency
>> design_parameters::SAMPLE_BUFFER_SIZE_LOG2)
as i32)
.wrapping_mul(settings.lockin_harmonic);
let sample_phase = settings
.lockin_phase
.wrapping_add(pll_phase.wrapping_mul(settings.lockin_harmonic));
let sample_frequency =
reference_frequency.wrapping_mul(settings.lockin_harmonic);
let sample_phase = settings.lockin_phase.wrapping_add(
reference_phase.wrapping_mul(settings.lockin_harmonic),
);

let output: Complex<i32> = adc_samples[0]
.iter()
Expand All @@ -175,23 +211,23 @@ const APP: () = {
.unwrap()
* 2; // Full scale assuming the 2f component is gone.

let output = [
match settings.output_conf[0] {
Conf::PowerPhase => output.abs_sqr() as _,
Conf::FrequencyDiscriminator => (output.log2() << 24) as _,
Conf::Quadrature => output.re,
},
match settings.output_conf[1] {
Conf::PowerPhase => output.arg(),
Conf::FrequencyDiscriminator => pll_frequency as _,
Conf::Quadrature => output.im,
},
];

// Convert to DAC data.
for i in 0..dac_samples[0].len() {
dac_samples[0][i] = (output[0] >> 16) as u16 ^ 0x8000;
dac_samples[1][i] = (output[1] >> 16) as u16 ^ 0x8000;
for (channel, samples) in dac_samples.iter_mut().enumerate() {
for (i, sample) in samples.iter_mut().enumerate() {
let value = match settings.output_conf[channel] {
Conf::Magnitude => output.abs_sqr() as i32 >> 16,
Conf::Phase => output.arg() >> 16,
Conf::LogPower => (output.log2() << 24) as i32 >> 16,
Conf::ReferenceFrequency => {
reference_frequency as i32 >> 16
}
Conf::InPhase => output.re >> 16,
Conf::Quadrature => output.im >> 16,
Conf::Modulation => DAC_SEQUENCE[i] as i32,
};

*sample = value as u16 ^ 0x8000;
}
}
}

Expand Down

0 comments on commit bde0b0a

Please sign in to comment.