From c026e55ce90dd8e39ed39ce7cca57e01fad13d84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Thu, 4 Jan 2024 16:00:16 +0100 Subject: [PATCH 01/10] iir rework --- Cargo.lock | 3 +-- Cargo.toml | 2 +- src/bin/dual-iir.rs | 24 ++++++++++++++++-------- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8e539dd24..6af016454 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -428,8 +428,7 @@ dependencies = [ [[package]] name = "idsp" version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "454770ee82223cd2580e0cef04b4e5dbe5b60f11600e3cb7e910aaf0d62c99ce" +source = "git+https://github.com/quartiq/idsp.git?branch=iir-rework#31ab7e6fbf0ac86669b79ab4c6b389d7d382836d" dependencies = [ "num-complex 0.4.4", "num-traits", diff --git a/Cargo.toml b/Cargo.toml index 4e1db96cf..7ad1808c7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,7 +50,7 @@ cortex-m-rtic = "1.0" embedded-hal = "0.2.7" num_enum = { version = "0.7.1", default-features = false } paste = "1" -idsp = "0.13" +idsp = { git = "https://github.com/quartiq/idsp.git", branch = "iir-rework" } ad9959 = { path = "ad9959", version = "0.2.1" } serial-settings = {path = "serial-settings"} mcp230xx = "1.0" diff --git a/src/bin/dual-iir.rs b/src/bin/dual-iir.rs index 70e2861fe..0ada22eb7 100644 --- a/src/bin/dual-iir.rs +++ b/src/bin/dual-iir.rs @@ -94,10 +94,9 @@ pub struct Settings { /// * `` specifies which channel to configure. `` := [0, 1] /// * `` specifies which cascade to configure. `` := [0, 1], depending on [IIR_CASCADE_LENGTH] /// - /// # Value - /// See [iir::IIR#miniconf] + /// See [iir::IIR] #[tree(depth(2))] - iir_ch: [[iir::IIR; IIR_CASCADE_LENGTH]; 2], + iir_ch: [[iir::Biquad; IIR_CASCADE_LENGTH]; 2], /// Specified true if DI1 should be used as a "hold" input. /// @@ -150,6 +149,9 @@ pub struct Settings { impl Default for Settings { fn default() -> Self { + let mut i = iir::Biquad::identity(); + i.set_min(-SCALE); + i.set_max(SCALE); Self { // Analog frontend programmable gain amplifier gains (G1, G2, G5, G10) afe: [Gain::G1, Gain::G1], @@ -158,7 +160,7 @@ impl Default for Settings { // The array is `iir_state[channel-index][cascade-index][coeff-index]`. // The IIR coefficients can be mapped to other transfer function // representations, for example as described in https://arxiv.org/abs/1508.06319 - iir_ch: [[iir::IIR::new(1., -SCALE, SCALE); IIR_CASCADE_LENGTH]; 2], + iir_ch: [[i; IIR_CASCADE_LENGTH]; 2], // Permit the DI1 digital input to suppress filter output updates. allow_hold: false, @@ -199,9 +201,10 @@ mod app { afes: (AFE0, AFE1), adcs: (Adc0Input, Adc1Input), dacs: (Dac0Output, Dac1Output), - iir_state: [[iir::Vec5; IIR_CASCADE_LENGTH]; 2], + iir_state: [[[f32; 5]; IIR_CASCADE_LENGTH]; 2], generator: FrameGenerator, cpu_temp_sensor: stabilizer::hardware::cpu_temp_sensor::CpuTempSensor, + hold: iir::Biquad, } #[init] @@ -261,6 +264,7 @@ mod app { iir_state: [[[0.; 5]; IIR_CASCADE_LENGTH]; 2], generator, cpu_temp_sensor: stabilizer.temperature_sensor, + hold: iir::Biquad::hold(), }; // Enable ADC/DAC events @@ -301,7 +305,7 @@ mod app { /// /// Because the ADC and DAC operate at the same rate, these two constraints actually implement /// the same time bounds, meeting one also means the other is also met. - #[task(binds=DMA1_STR4, local=[digital_inputs, adcs, dacs, iir_state, generator], shared=[settings, signal_generator, telemetry], priority=3)] + #[task(binds=DMA1_STR4, local=[digital_inputs, adcs, dacs, iir_state, generator, hold], shared=[settings, signal_generator, telemetry], priority=3)] #[link_section = ".itcm.process"] fn process(c: process::Context) { let process::SharedResources { @@ -316,6 +320,7 @@ mod app { dacs: (dac0, dac1), iir_state, generator, + hold, } = c.local; (settings, telemetry, signal_generator).lock( @@ -324,7 +329,7 @@ mod app { [digital_inputs.0.is_high(), digital_inputs.1.is_high()]; telemetry.digital_inputs = digital_inputs; - let hold = settings.force_hold + let use_hold = settings.force_hold || (digital_inputs[1] && settings.allow_hold); (adc0, adc1, dac0, dac1).lock(|adc0, adc1, dac0, dac1| { @@ -345,7 +350,10 @@ mod app { .iter() .zip(iir_state[channel].iter_mut()) .fold(x, |yi, (ch, state)| { - ch.update(state, yi, hold) + let filter = + if use_hold { &hold } else { ch }; + + filter.update(state, yi) }); // Note(unsafe): The filter limits must ensure that the value is in range. From d002be8e32e3001b01c4a26b929448861e37e17e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Thu, 4 Jan 2024 16:10:12 +0100 Subject: [PATCH 02/10] iir_coefficients: iir rework --- py/stabilizer/iir_coefficients.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/py/stabilizer/iir_coefficients.py b/py/stabilizer/iir_coefficients.py index 7f1c8bc8a..270e881cb 100644 --- a/py/stabilizer/iir_coefficients.py +++ b/py/stabilizer/iir_coefficients.py @@ -300,10 +300,10 @@ async def configure(): # Note: In the future, we will need to Handle higher-order cascades. await interface.set(f"/iir_ch/{args.channel}/0", { "ba": coefficients, - "y_min": stabilizer.voltage_to_machine_units(args.y_min), - "y_max": stabilizer.voltage_to_machine_units(args.y_max), - "y_offset": stabilizer.voltage_to_machine_units( - args.y_offset + forward_gain * args.x_offset) + "u": stabilizer.voltage_to_machine_units( + args.y_offset + forward_gain * args.x_offset), + "min": stabilizer.voltage_to_machine_units(args.y_min), + "max": stabilizer.voltage_to_machine_units(args.y_max), }) asyncio.run(configure()) From 6e2cb572721a8e4927749ebb47bf72da3ebbf145 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 9 Jan 2024 17:31:06 +0100 Subject: [PATCH 03/10] bump --- Cargo.lock | 2 +- src/bin/dual-iir.rs | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6af016454..1d454bcff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -428,7 +428,7 @@ dependencies = [ [[package]] name = "idsp" version = "0.13.0" -source = "git+https://github.com/quartiq/idsp.git?branch=iir-rework#31ab7e6fbf0ac86669b79ab4c6b389d7d382836d" +source = "git+https://github.com/quartiq/idsp.git?branch=iir-rework#71a0944873df564ab706ebacb300f26c7b366c78" dependencies = [ "num-complex 0.4.4", "num-traits", diff --git a/src/bin/dual-iir.rs b/src/bin/dual-iir.rs index 0ada22eb7..ad4661fd5 100644 --- a/src/bin/dual-iir.rs +++ b/src/bin/dual-iir.rs @@ -149,7 +149,7 @@ pub struct Settings { impl Default for Settings { fn default() -> Self { - let mut i = iir::Biquad::identity(); + let mut i = iir::Biquad::IDENTITY; i.set_min(-SCALE); i.set_max(SCALE); Self { @@ -201,10 +201,9 @@ mod app { afes: (AFE0, AFE1), adcs: (Adc0Input, Adc1Input), dacs: (Dac0Output, Dac1Output), - iir_state: [[[f32; 5]; IIR_CASCADE_LENGTH]; 2], + iir_state: [[[f32; 4]; IIR_CASCADE_LENGTH]; 2], generator: FrameGenerator, cpu_temp_sensor: stabilizer::hardware::cpu_temp_sensor::CpuTempSensor, - hold: iir::Biquad, } #[init] @@ -261,10 +260,9 @@ mod app { afes: stabilizer.afes, adcs: stabilizer.adcs, dacs: stabilizer.dacs, - iir_state: [[[0.; 5]; IIR_CASCADE_LENGTH]; 2], + iir_state: [[[0.; 4]; IIR_CASCADE_LENGTH]; 2], generator, cpu_temp_sensor: stabilizer.temperature_sensor, - hold: iir::Biquad::hold(), }; // Enable ADC/DAC events @@ -305,7 +303,7 @@ mod app { /// /// Because the ADC and DAC operate at the same rate, these two constraints actually implement /// the same time bounds, meeting one also means the other is also met. - #[task(binds=DMA1_STR4, local=[digital_inputs, adcs, dacs, iir_state, generator, hold], shared=[settings, signal_generator, telemetry], priority=3)] + #[task(binds=DMA1_STR4, local=[digital_inputs, adcs, dacs, iir_state, generator], shared=[settings, signal_generator, telemetry], priority=3)] #[link_section = ".itcm.process"] fn process(c: process::Context) { let process::SharedResources { @@ -320,7 +318,6 @@ mod app { dacs: (dac0, dac1), iir_state, generator, - hold, } = c.local; (settings, telemetry, signal_generator).lock( @@ -329,7 +326,7 @@ mod app { [digital_inputs.0.is_high(), digital_inputs.1.is_high()]; telemetry.digital_inputs = digital_inputs; - let use_hold = settings.force_hold + let hold = settings.force_hold || (digital_inputs[1] && settings.allow_hold); (adc0, adc1, dac0, dac1).lock(|adc0, adc1, dac0, dac1| { @@ -350,8 +347,11 @@ mod app { .iter() .zip(iir_state[channel].iter_mut()) .fold(x, |yi, (ch, state)| { - let filter = - if use_hold { &hold } else { ch }; + let filter = if hold { + &iir::Biquad::HOLD + } else { + ch + }; filter.update(state, yi) }); From d13f35fc7518cb6abfcc8fbd8077b11a5bb5aa6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 12 Jan 2024 12:38:06 +0100 Subject: [PATCH 04/10] bump --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 1d454bcff..9b11fa097 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -428,7 +428,7 @@ dependencies = [ [[package]] name = "idsp" version = "0.13.0" -source = "git+https://github.com/quartiq/idsp.git?branch=iir-rework#71a0944873df564ab706ebacb300f26c7b366c78" +source = "git+https://github.com/quartiq/idsp.git?branch=iir-rework#d2bd6be52216d0da968a906abb88439d47372239" dependencies = [ "num-complex 0.4.4", "num-traits", From d6f6a84bdab30800254dd92cc8de32324d1d4e53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 15 Jan 2024 16:43:26 +0100 Subject: [PATCH 05/10] bump --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9b11fa097..8d96df4db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -428,7 +428,7 @@ dependencies = [ [[package]] name = "idsp" version = "0.13.0" -source = "git+https://github.com/quartiq/idsp.git?branch=iir-rework#d2bd6be52216d0da968a906abb88439d47372239" +source = "git+https://github.com/quartiq/idsp.git#9e527f34c45817986bb3035bd7a6d9efefd4f071" dependencies = [ "num-complex 0.4.4", "num-traits", diff --git a/Cargo.toml b/Cargo.toml index 7ad1808c7..1bf7731b6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,7 +50,7 @@ cortex-m-rtic = "1.0" embedded-hal = "0.2.7" num_enum = { version = "0.7.1", default-features = false } paste = "1" -idsp = { git = "https://github.com/quartiq/idsp.git", branch = "iir-rework" } +idsp = { git = "https://github.com/quartiq/idsp.git" } ad9959 = { path = "ad9959", version = "0.2.1" } serial-settings = {path = "serial-settings"} mcp230xx = "1.0" From 321d60a0ca6281c6a181abee7801b94ef828f99e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 15 Jan 2024 17:18:23 +0100 Subject: [PATCH 06/10] rleeased idsp --- Cargo.lock | 5 +++-- Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8d96df4db..5d03df9eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -427,8 +427,9 @@ dependencies = [ [[package]] name = "idsp" -version = "0.13.0" -source = "git+https://github.com/quartiq/idsp.git#9e527f34c45817986bb3035bd7a6d9efefd4f071" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f255ee573949fb629362d10aa3abd0a97a7c4950a3b8890b435b8c7516cf38f" dependencies = [ "num-complex 0.4.4", "num-traits", diff --git a/Cargo.toml b/Cargo.toml index 1bf7731b6..35437aad1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,7 +50,7 @@ cortex-m-rtic = "1.0" embedded-hal = "0.2.7" num_enum = { version = "0.7.1", default-features = false } paste = "1" -idsp = { git = "https://github.com/quartiq/idsp.git" } +idsp = "0.14.1" ad9959 = { path = "ad9959", version = "0.2.1" } serial-settings = {path = "serial-settings"} mcp230xx = "1.0" From dd273e5443c2a0ba8a16169373b72b14f35704f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 15 Jan 2024 17:20:02 +0100 Subject: [PATCH 07/10] docs --- src/bin/dual-iir.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/dual-iir.rs b/src/bin/dual-iir.rs index ad4661fd5..8032e7c05 100644 --- a/src/bin/dual-iir.rs +++ b/src/bin/dual-iir.rs @@ -94,7 +94,7 @@ pub struct Settings { /// * `` specifies which channel to configure. `` := [0, 1] /// * `` specifies which cascade to configure. `` := [0, 1], depending on [IIR_CASCADE_LENGTH] /// - /// See [iir::IIR] + /// See [iir::Biquad] #[tree(depth(2))] iir_ch: [[iir::Biquad; IIR_CASCADE_LENGTH]; 2], From 6f337fcf1c5c1fe3a03a850bbf2160da82f4879c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 15 Jan 2024 17:21:27 +0100 Subject: [PATCH 08/10] changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b226864c9..2642e861d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,8 @@ console. ### Changed * Broker is no longer configured at compile time, but is maintained in device memory * MSRV bumped to v1.66 +* The IIR (biquad) filter used for PID action has changed its serialization format. + See also the `iir_coefficients` Python CLI implementation. ## [0.9.0](https://github.com/quartiq/stabilizer/compare/v0.8.1...v0.9.0) From 6db2d25d40dffeeaef143bb1ee46ac5f64914fac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 15 Jan 2024 17:23:20 +0100 Subject: [PATCH 09/10] changelog markdown syntax fix --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2642e861d..713236b93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,7 +37,7 @@ console. * `hitl/streaming.py` no longer requires a prefix * Streaming now supports UDP multicast addresses -## [v0.8.1](https://github.com/quartiq/stabilizer/compare/v0.8.0...v0.8.1) - 2022-11-14) +## [v0.8.1](https://github.com/quartiq/stabilizer/compare/v0.8.0...v0.8.1) - 2022-11-14 * Fixed the python package dependencies From b1acca26c8d819fd1338f28e25e68990d8c27e1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 15 Jan 2024 21:51:05 +0100 Subject: [PATCH 10/10] adapt loopback test --- hitl/loopback.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hitl/loopback.py b/hitl/loopback.py index 3ebaa6600..e0a9b941b 100644 --- a/hitl/loopback.py +++ b/hitl/loopback.py @@ -27,10 +27,10 @@ def static_iir_output(output_voltage): """ machine_units = voltage_to_machine_units(output_voltage) return { - 'y_min': machine_units, - 'y_max': machine_units, - 'y_offset': 0, 'ba': [1, 0, 0, 0, 0], + 'u': 0, + 'min': machine_units, + 'max': machine_units, }