diff --git a/include/chowdsp_wdf/wdft/wdft_sources.h b/include/chowdsp_wdf/wdft/wdft_sources.h index 2c28767..da1ab0d 100644 --- a/include/chowdsp_wdf/wdft/wdft_sources.h +++ b/include/chowdsp_wdf/wdft/wdft_sources.h @@ -97,6 +97,91 @@ namespace wdft T R_value = (T) 1.0e-9; }; + /** WDF Voltage source with series capacitance */ + template + class CapacitiveVoltageSourceT final : public BaseWDF + { + public: + /** Creates a new resistive voltage source. + * @param value: initial resistance value, in Ohms + */ + explicit CapacitiveVoltageSourceT (T value = NumericType (1.0e-6), T fs = (T) 48000) + : C_value (value), + fs (fs) + + { + calcImpedance(); + } + + /** Prepares the capacitor to operate at a new sample rate */ + void prepare (T sampleRate) + { + fs = sampleRate; + propagateImpedanceChange(); + + reset(); + } + + void reset() + { + z = (T) 0; + v_1 = (T) 0; + } + + /** Sets the capacitance value of the series resistor, in Farads. */ + void setCapacitanceValue (T newC) + { + if (newC == C_value) + return; + + C_value = newC; + propagateImpedanceChange(); + } + + /** Computes the impedance of the WDF capacitor, + * 1 + * Z_C = -------------- + * 2 * f_s * C + */ + inline void calcImpedance() override + { + wdf.R = (T) 1.0 / ((T) 2.0 * C_value * fs); + wdf.G = (T) 1.0 / wdf.R; + } + + /** Sets the voltage of the voltage source, in Volts */ + void setVoltage (T newV) + { + v_0 = newV; + } + + /** Accepts an incident wave into a WDF resistive voltage source. */ + inline void incident (T x) noexcept + { + wdf.a = x; + z = wdf.a; + } + + /** Propogates a reflected wave from a WDF resistive voltage source. */ + inline T reflected() noexcept + { + wdf.b = z + v_0 - v_1; + v_1 = v_0; + return wdf.b; + } + + WDFMembers wdf; + + private: + T C_value = (T) 1.0e-6; + + T z {}; + T v_0 {}; + T v_1 {}; + + T fs; + }; + /** WDF Current source (non-adaptable) */ template class IdealCurrentSourceT final : public RootWDF diff --git a/tests/CombinedComponentTest.cpp b/tests/CombinedComponentTest.cpp index 89fe02b..92b7073 100644 --- a/tests/CombinedComponentTest.cpp +++ b/tests/CombinedComponentTest.cpp @@ -1,82 +1,147 @@ #include #include +#include using namespace chowdsp::wdft; TEST_CASE ("Combined Component Test") { - SECTION ("Resistor/Capacitor Series") + // SECTION ("Resistor/Capacitor Series") + // { + // static constexpr auto r_val = 2000.0f; + // static constexpr auto c_val = 2.0e-6f; + // + // ResistorT r1 { r_val }; + // CapacitorT c1 { c_val }; + // WDFSeriesT s1 { r1, c1 }; + // + // ResistorCapacitorSeriesT rc1 { r_val, c_val }; + // + // float inputs[] = { 0.0f, 1.0f, -1.0f, 2.0f, -3.0f }; + // for (auto& a : inputs) + // { + // s1.incident (a); + // const auto ref = s1.reflected(); + // + // rc1.incident (a); + // const auto actual = rc1.reflected(); + // + // REQUIRE (ref == Approx { actual }.margin (1.0e-4f)); + // } + // } + // + // SECTION ("Resistor/Capacitor Parallel") + // { + // static constexpr auto r_val = 2000.0f; + // static constexpr auto c_val = 2.0e-6f; + // + // ResistorT r1 { r_val }; + // CapacitorT c1 { c_val }; + // WDFParallelT p1 { r1, c1 }; + // + // ResistorCapacitorParallelT rc1 { r_val, c_val }; + // + // float inputs[] = { 0.0f, 1.0f, -1.0f, 2.0f, -3.0f }; + // for (auto& a : inputs) + // { + // p1.incident (a); + // const auto ref = p1.reflected(); + // + // rc1.incident (a); + // const auto actual = rc1.reflected(); + // + // REQUIRE (ref == Approx { actual }.margin (1.0e-4f)); + // } + // } + // + // SECTION ("Resistor/Capacitor/Voltage Source Series") + // { + // static constexpr auto r_val = 2000.0f; + // static constexpr auto c_val = 2.0e-6f; + // static constexpr auto source_v = 1.5f; + // + // ResistiveVoltageSourceT rv1 { r_val }; + // rv1.setVoltage (source_v); + // CapacitorT c1 { c_val }; + // WDFSeriesT s1 { rv1, c1 }; + // + // ResistiveCapacitiveVoltageSourceT rc1 { r_val, c_val }; + // rc1.setVoltage (source_v); + // rc1.reset(); + // + // float inputs[] = { 0.0f, 1.0f, -1.0f, 2.0f, -3.0f }; + // for (auto& a : inputs) + // { + // s1.incident (a); + // const auto ref = s1.reflected(); + // + // rc1.incident (a); + // const auto actual = rc1.reflected(); + // + // REQUIRE (ref == Approx { actual }.margin (1.0e-4f)); + // } + // } + + SECTION ("Capacitive Voltage Source") { - static constexpr auto r_val = 2000.0f; static constexpr auto c_val = 2.0e-6f; + static constexpr auto source_v = 1.5f; - ResistorT r1 { r_val }; - CapacitorT c1 { c_val }; - WDFSeriesT s1 { r1, c1 }; - - ResistorCapacitorSeriesT rc1 { r_val, c_val }; - - float inputs[] = { 0.0f, 1.0f, -1.0f, 2.0f, -3.0f }; - for (auto& a : inputs) + struct Ref { - s1.incident (a); - const auto ref = s1.reflected(); - - rc1.incident (a); - const auto actual = rc1.reflected(); - - REQUIRE (ref == Approx { actual }.margin (1.0e-4f)); - } - } - - SECTION ("Resistor/Capacitor Parallel") - { - static constexpr auto r_val = 2000.0f; - static constexpr auto c_val = 2.0e-6f; - - ResistorT r1 { r_val }; - CapacitorT c1 { c_val }; - WDFParallelT p1 { r1, c1 }; - - ResistorCapacitorParallelT rc1 { r_val, c_val }; - - float inputs[] = { 0.0f, 1.0f, -1.0f, 2.0f, -3.0f }; - for (auto& a : inputs) + ResistiveVoltageSourceT rv1 { 1.0e3f }; + CapacitorT c1 { 1.0e-6f }; + WDFSeriesT s1 { rv1, c1 }; + IdealVoltageSourceT v0 { s1 }; + + void reset() + { + c1.reset(); + v0.setVoltage (0.0f); + } + + float process (float v) + { + rv1.setVoltage (v); + v0.incident (s1.reflected()); + const auto y = voltage (rv1) + voltage (c1); + s1.incident (v0.reflected()); + return y; + } + }; + Ref ref_circuit; + ref_circuit.reset(); + + struct Test { - p1.incident (a); - const auto ref = p1.reflected(); - - rc1.incident (a); - const auto actual = rc1.reflected(); - - REQUIRE (ref == Approx { actual }.margin (1.0e-4f)); - } - } - - SECTION ("Resistor/Capacitor/Voltage Source Series") - { - static constexpr auto r_val = 2000.0f; - static constexpr auto c_val = 2.0e-6f; - static constexpr auto source_v = 1.5f; - - ResistiveVoltageSourceT rv1 { r_val }; - rv1.setVoltage (source_v); - CapacitorT c1 { c_val }; - WDFSeriesT s1 { rv1, c1 }; - - ResistiveCapacitiveVoltageSourceT rc1 { r_val, c_val }; - rc1.setVoltage (source_v); - rc1.reset(); + CapacitiveVoltageSourceT cv1 { 1.0e-6f }; + ResistorT r1 { 1.0e3f }; + WDFSeriesT s1 { cv1, r1 }; + IdealVoltageSourceT v0 { s1 }; + + void reset() + { + cv1.reset(); + v0.setVoltage (0.0f); + } + + float process (float v) + { + cv1.setVoltage (v); + v0.incident (s1.reflected()); + const auto y = voltage (cv1) + voltage (r1); + s1.incident (v0.reflected()); + return y; + } + }; + Test test_circuit; + test_circuit.reset(); float inputs[] = { 0.0f, 1.0f, -1.0f, 2.0f, -3.0f }; for (auto& a : inputs) { - s1.incident (a); - const auto ref = s1.reflected(); - - rc1.incident (a); - const auto actual = rc1.reflected(); - + const auto ref = ref_circuit.process (a); + const auto actual = test_circuit.process (a); REQUIRE (ref == Approx { actual }.margin (1.0e-4f)); } }