forked from grame-cncm/faustlibraries
-
Notifications
You must be signed in to change notification settings - Fork 0
/
wdmodels.lib
2274 lines (2132 loc) · 87.4 KB
/
wdmodels.lib
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
//#################################### wdmodels.lib ##############################################################################
// A library of basic adaptors and methods to help construct Wave Digital Filter models in Faust. Its official prefix is `wd`.
// ## Library Readme
// This library is intended for use for creating Wave Digital (WD) based models of audio circuitry for real-time audio processing within the Faust programming language. The goal is to provide a framework to create real-time virtual-analog audio effects and synthesizers using WD models without the use of C++. Furthermore, we seek to provide access to the technique of WD modeling to those without extensive knowledge of advanced digital signal processing techniques. Finally, we hope to provide a library which can integrate with all aspects of Faust, thus creating a platform for virtual circuit bending.
// The library itself is written in Faust to maintain portability.
//
// This library is heavily based on Kurt Werner's Dissertation, "Virtual Analog Modeling of Audio Circuitry Using Wave Digital Filters." I have tried to maintain consistent notation between the adaptors appearing within thesis and my adaptor code. The majority of the adaptors found in chapter 1 and chapter 3 are currently supported.
//
// For inquires about use of this library in a commercial product, please contact dirk [dot] roosenburg [dot] 30 [at] gmail [dot] com.
// This documentation is taken directly from the [readme](https://github.com/droosenb/faust-wdf-library). Please refer to it for a more updated version.
//
// Many of the more in depth comments within the library include jargon. I plan to create videos detailing the theory of WD models
// For now I recommend Kurt Werner's PhD, [Virtual analog modeling of Audio circuitry using Wave Digital Filters](https://searchworks.stanford.edu/view/11891203).
// I have tried to maintain consistent syntax and notation to the thesis.
// This library currently includes the majority of the adaptors covered in chapter 1 and some from chapter 3.
//
//
// ## Using this Library
//
// Use of this library expects some level of familiarity with WDF techniques, especially simplification and decomposition of electronic circuits into WDF connection trees. I plan to create video to cover both these techniques and use of the library.
//
// ### Quick Start
//
// to get a quick overview of the library, start with the `secondOrderFilters.dsp` code found in `examples`. Make sure that the `wdmodels.lib` is within the compile path. This can be achieved within the [online Faust IDE](https://faustide.grame.fr/) by simply downloading and dragging in `wdmodels.lib` in addition to the example code.
//
// ### A Simple RC Filter Model
//
// Creating a model using this library consists fo three steps. First, declare a set of components. Second, model the relationship between them using a tree. Finally, build the tree using the libraries build functions.
//
// First, a set of components is declared using adaptors from the library. This list of components is created based on analysis of the circuit using WDF techniques, though generally each circuit element (resistor, capacitor, diode, etc.) can be expected to appear within the component set. For example, first order RC lowpass filter would require an unadapted voltage source, a 47k resistor, and a 10nF capacitor which outputs the voltage across itself. These can be declared with:
//
// ```
// vs1(i) = wd.u_voltage(i, no.noise);
// r1(i) = wd.resistor(i, 47*10^3);
// c1(i) = wd.capacitor_Vout(i, 10*10^-9);
// ```
//
// Note that the first argument, i, is left un-parametrized. Components must be declared in this form, as the build algorithm expects to receive adaptors which have exactly one parameter.
//
// Also note that we have chosen to declare a white noise function as the input to our voltage source. We could potentially declare this as a direct input to our model, but to do so is more complicated process which cannot be covered within this tutorial. For information on how to do this see Declaring Model Parameters as Inputs or see various implementations in `examples`.
//
// Second, the declared components and interconnection/structural adaptors (i.e. series, parallel, etc) are arranged into the connection tree which is produced from performing WD analysis on the modeled circuit. For example, to produce our first order RC lowpass circuit model, the following tree is declared:
//
// `tree_lowpass = vs1(i) : WD.series : (r1, c1)`
//
// For more information on how to represent trees in Faust, see Trees in Faust.
//
// Finally, the tree is built using the the `buildtree` function. To build and compute our first order RC lowpass circuit model, we use:
//
// `process = buildtree(tree_lowpass);`
//
// More information about build functions, see Build Functions.
//
// ### Building a Model
//
// After creating a connection tree which consists of WD adaptors, the connection tree must be passed to a build function in order to build the model.
//
// ##### Automatic model building
//
// `buildtree(connection_tree)`
//
// The simplest build function for use with basic models. This automatically implements `buildup`, `builddown`, and `buildout` to create a working model. However, it gives minimum control to the user and cannot currently be used on trees which have parameters declared as inputs.
//
// ##### Manual model building
//
// Wave Digital Filters are an explicit state-space model, meaning they use a previous system state in order to calculate the current output. This is achieved in Faust by using a single global feedback operator. The models feed-forward terms are generated using `builddown` and the models feedback terms are generated using `buildup`. Thus, the most common model implementation (the method used by `buildtree`) is:
//
// `builddown(connection_tree)~buildup(connection_tree) : buildout(connection_tree)`
//
// Since the `~` operator in Faust will leave feedback terms hanging as outputs, `buildout` is a function provided for convenience. It automatically truncates the hanging outputs by identifying leaf components which have an intended output and generating an output matrix.
//
// Building the model manually allows for greater user control and is often very helpful in testing. Also provided for testing are the `getres` and `parres` functions, which can be used to determine the upward-facing port resistance of an element.
//
// ### Declaring Model Parameters as Inputs
//
// When possible, parameters of components should be declared explicitly, meaning they are dependent on a function with no inputs. This might be something as simple as integer(declaring a static component), a function dependent on a UI input (declaring a component with variable value), or even a time-dependent function like an oscillator (declaring an audio input or circuit bending).
//
// However, it is often necessary to declare parameters as input. To achieve this there are two possible methods. The first and recommended option is to create a separate model function and declare parameters which will later be implemented as inputs. This allows inputs to be explicitly declared as component parameters. For example, one might use
//
// ```
// model(in1) = buildtree(tree)
// with {
// ...
// vin(i) = wd.u_voltage(i, in1);
// ...
// tree = vin : ...;
// };
// ```
//
// In order to simulate an audio input to the circuit.
//
// Note that the tree and components must be declared inside a `with {...}` statement, or the model's parameters will not be accessible.
//
// ##### The Empty Signal Operator
//
// The Empty signal operator, `_` should NEVER be used to declare a parameter as in input in a wave-digital model.
//
// Using it will result on breaking the internal routing of the model and thus breaks the model. Instead, use explicit declaration as shown directly above.
//
// ### Trees in Faust
//
// Since WD models use connection trees to represent relationships of elements, a comprehensive way to represent trees is critical. As there is no current convention for creating trees in Faust, I've developed a method using the existing series and parallel/list methods in Faust.
//
// The series operator ` : ` is used to separate parent and child elements. For example the tree
//
// ```
// A
// |
// B
// ```
//
// is represented by `A : B` in Faust.
//
// To denote a parent element with multiple child elements, simply use a list `(a1, a2, ... an)` of children connected to a single parent. For example the tree:
//
// ```
// A
// / \
// B C
//
// ```
// is represented by:
//
// `A : (B, C)`
//
// Finally, for a tree with many levels, simply break the tree into subtrees following the above rules and connect the subtree as if it was an individual node. For example the tree:
//
// ```
// A
// / \
// B C
// / / \
// X Y Z
// ```
//
// can be represented by:
//
// ```
// B_sub = B : X; //B subtree
// C_sub = C : (Y, Z); //C subtree
// tree = A : (B_sub, C_sub); //full tree
// ```
//
// or more simply, using parentheses:
//
// `A : ((B : X), (C : (Y, Z)))`
// ### How Adaptors are Structured
// In wave digital filters, adaptors can be described by the form `b = Sa` where `b` is a vector of output waves `b = (b0, b1, b2, ... bn)`, `a` is a vector of input waves`a = (a0, a1, a2, ... an)`, and `S` is an n x n scattering matrix. `S` is dependent on `R`, a list of port resistances `(R0, R1, R2, ... Rn)`.
//
// The output wave vector `b` can be divided into downward-going and upward-going waves (downward-going waves travel down the connection tree, upward-going waves travel up). For adapted adaptors, with the zeroth port being the upward-facing port, the downward-going wave vector is `(b1, b2, ... bn)` and the upward-going wave vector is `(b0)`. For unadapted adaptors, there are no upward-going waves, so the downward-going wave vector is simply `b = (b0, b1, b2, ... bn)`.
//
// In order for adaptors to be interpretable by the compiler, they must be structured in a specific way.
// Each adaptor is divided into three cases by their first parameter. This parameter, while accessible by the user, should only be set by the compiler/builder.
//
// All other parameters are value declarations (for components), inputs (for voltage or current ins), or parameter controls (for potentiometers/variable capacitors/variable inductors)
//
// ##### first case - downward going waves
//
// `(0, params) => downward-going(R1, ... Rn, a0, a1, ... an)`
// outputs: `(b1, b2, ... bn)`
// this function takes any number of port resistances, the downward going wave, and any number of upward going waves as inputs.
// These values/waves are used to calculate the downward going waves coming from this adaptor.
//
// ##### second case
//
// `(1, params) => upward-going(R1, ... Rn, a1, ... an)`
// outputs : `(b0)`
// this function takes any number of port resistances and any number of upward going waves as inputs
// these values/waves are used to calculate the upward going wave coming from this adaptor.
//
// ##### third case
//
// `(2, params) => port-resistance(R1, ... Rn)`
// outputs: `(R0)`
// this function takes any number of port resistances as inputs
// these values are used to calculate the upward going port resistance of the element.
//
// ##### Unadapted Adaptors
//
// Unadapted adaptor's names will always begin `u_`
// An unadapted adaptor MUST be used as the root of the WD connection tree.
// Unadapted adaptors can ONLY be used as a root of the WD connection tree.
// While unadapted adaptors contain all three cases, the second and third are purely structural.
// Only the first case should contain computational information.
//
// ### How the Build Functions Work
//
// Expect this section to be added soon! It's currently in progress.
//
// ### Acknowledgements
//
// Many thanks to Kurt Werner for helping me to understand wave digital filter models. Without his publications and consultations, the library would not exist.
// Thanks also to my advisors, Rob Owen and Eli Stine whose input was critical to the development of the library.
// Finally, thanks to Romain Michon, Stephane Letz, and the Faust slack for contributing to testing, development, and inspiration when creating the library.
//################################################################################################################################
ba = library("basics.lib");
ro = library("routes.lib");
ma = library("maths.lib");
si = library("signals.lib");
declare name "Faust Wave Digital Model Library";
declare version "0.2.0";
//=============================Algebraic One Port Adaptors=================================
//=========================================================================================
//----------------------`(wd.)resistor`--------------------------
// Adapted Resistor.
//
// A basic node implementing a resistor for use within Wave Digital Filter connection trees.
//
// It should be used as a leaf/terminating element of the connection tree.
//
// #### Usage
//
// ```
// r1(i) = resistor(i, R);
// buildtree( A : r1 );
// ```
//
// Where:
//
// * `i`: index used by model-building functions. Should never be user declared.
// * `R` : Resistance/Impedance of the resistor being modeled in Ohms.
//
// Note:
// The adaptor must be declared as a separate function before integration into the connection tree.
// Correct implementation is shown above.
//
// #### Reference
// K. Werner, "Virtual Analog Modeling of Audio Circuitry Using Wave Digital Filters", 1.2.1
//----------------------------------------------------------
declare resistor author "Dirk Roosenburg";
declare resistor copyright "Copyright (C) 2020 by Dirk Roosenburg <[email protected]>";
declare resistor license "MIT-style STK-4.3 license";
resistor =
case{
(0, R) => !, 0;
(1, R) => _;
(2, R) => R0
with{
R0 = R;
};
};
//----------------------`(wd.)resistor_Vout`--------------------------
// Adapted Resistor + voltage Out.
//
// A basic adaptor implementing a resistor for use within Wave Digital Filter connection trees.
//
// It should be used as a leaf/terminating element of the connection tree.
// The resistor will also pass the voltage across itself as an output of the model.
//
// #### Usage
//
// ```
// rout(i) = resistor_Vout(i, R);
// buildtree( A : rout ) : _;
// ```
//
// Where:
//
// * `i`: index used by model-building functions. Should never be user declared.
// * `R` : Resistance/Impedance of the resistor being modeled in Ohms.
//
// Note:
// The adaptor must be declared as a separate function before integration into the connection tree.
// Correct implementation is shown above.
//
// #### Reference
//
// K. Werner, "Virtual Analog Modeling of Audio Circuitry Using Wave Digital Filters", 1.2.1
//----------------------------------------------------------
declare resistor_Vout author "Dirk Roosenburg";
declare resistor_Vout copyright "Copyright (C) 2020 by Dirk Roosenburg <[email protected]>";
declare resistor_Vout license "MIT-style STK-4.3 license";
resistor_Vout =
case{
(0, R) => 0, _*.5;
(1, R) => _, !;
(2, R) => R0
with{
R0 = R;
};
}with{
rho = 1;
};
//----------------------`(wd.)resistor_Iout`--------------------------
// Resistor + current Out.
//
// A basic adaptor implementing a resistor for use within Wave Digital Filter connection trees.
//
// It should be used as a leaf/terminating element of the connection tree.
// The resistor will also pass the current through itself as an output of the model.
//
// #### Usage
//
// ```
// rout(i) = resistor_Iout(i, R);
// buildtree( A : rout ) : _;
// ```
//
// Where:
//
// * `i`: index used by model-building functions. Should never be user declared.
// * `R` : Resistance/Impedance of the resistor being modeled in Ohms.
//
// Note:
// The adaptor must be declared as a separate function before integration into the connection tree.
// Correct implementation is shown above.
//
// #### Reference
//
// K. Werner, "Virtual Analog Modeling of Audio Circuitry Using Wave Digital Filters", 1.2.1
//----------------------------------------------------------
declare resistor_Iout author "Dirk Roosenburg";
declare resistor_Iout copyright "Copyright (C) 2020 by Dirk Roosenburg <[email protected]>";
declare resistor_Iout license "MIT-style STK-4.3 license";
resistor_Iout =
case{
(0, R) => 0, _*.5/R;
(1, R) => _, !;
(2, R) => R0
with{
R0 = R;
};
};
//----------------------`(wd.)u_voltage`--------------------------
// Unadapted Ideal Voltage Source.
//
// An adaptor implementing an ideal voltage source within Wave Digital Filter connection trees.
//
// It should be used as the root/top element of the connection tree.
// Can be used for either DC (constant) or AC (signal) voltage sources.
//
// #### Usage
//
// ```
// v1(i) = u_Voltage(i, ein);
// buildtree( v1 : B );
// ```
//
// Where:
//
// * `i`: index used by model-building functions. Should never be user declared.
// * `ein` : Voltage/Potential across ideal voltage source in Volts
//
// Note:
// Only usable as the root of a tree
// The adaptor must be declared as a separate function before integration into the connection tree.
// Correct implementation is shown above.
//
// #### Reference
//
// K. Werner, "Virtual Analog Modeling of Audio Circuitry Using Wave Digital Filters", 1.2.2
//----------------------------------------------------------
declare u_voltage author "Dirk Roosenburg";
declare u_voltage copyright "Copyright (C) 2020 by Dirk Roosenburg <[email protected]>";
declare u_voltage license "MIT-style STK-4.3 license";
u_voltage =
case{
(0 , ein) => b0
with{
b0(R0, a0) = 2*R0^(rho-1)*ein -a0;
};
(1, ein) => !, !;
(2, ein) => 0;
}with{
rho = 1;
};
//----------------------`(wd.)u_current`--------------------------
// Unadapted Ideal Current Source.
//
// An unadapted adaptor implementing an ideal current source within Wave Digital Filter connection trees.
//
// It should be used as the root/top element of the connection tree.
// Can be used for either DC (constant) or AC (signal) current sources.
//
// #### Usage
//
// ```
// i1(i) = u_current(i, jin);
// buildtree( i1 : B );
// ```
//
// Where:
//
// * `i`: index used by model-building functions. Should never be user declared.
// * `jin` : Current through the ideal current source in Amps
//
// Note:
// Only usable as the root of a tree.
// The adaptor must be declared as a separate function before integration into the connection tree.
// Correct implementation is shown above.
//
// #### Reference
//
// K. Werner, "Virtual Analog Modeling of Audio Circuitry Using Wave Digital Filters", 1.2.3
//----------------------------------------------------------
declare u_current author "Dirk Roosenburg";
declare u_current copyright "Copyright (C) 2020 by Dirk Roosenburg <[email protected]>";
declare u_current license "MIT-style STK-4.3 license";
u_current =
case{
(0 , jin) => b0
with{
b0(R0, a0) = 2*R0^(rho)*jin + a0;
};
(1, jin) => !, !;
(2, jin) => 0;
}with{
rho = 1;
};
//----------------------`(wd.)resVoltage`--------------------------
// Adapted Resistive Voltage Source.
//
// An adaptor implementing a resistive voltage source within Wave Digital Filter connection trees.
//
// It should be used as a leaf/terminating element of the connection tree.
// It is comprised of an ideal voltage source in series with a resistor.
// Can be used for either DC (constant) or AC (signal) voltage sources.
//
// #### Usage
//
// ```
// v1(i) = resVoltage(i, R, ein);
// buildtree( A : v1 );
// ```
//
// Where:
//
// * `i`: index used by model-building functions. Should never be user declared
// * `R` : Resistance/Impedance of the series resistor in Ohms
// * `ein` : Voltage/Potential of the ideal voltage source in Volts
//
// Note:
// The adaptor must be declared as a separate function before integration into the connection tree.
// Correct implementation is shown above.
//
// #### Reference
//
// K. Werner, "Virtual Analog Modeling of Audio Circuitry Using Wave Digital Filters", 1.2.4
//----------------------------------------------------------
declare resVoltage author "Dirk Roosenburg";
declare resVoltage copyright "Copyright (C) 2020 by Dirk Roosenburg <[email protected]>";
declare resVoltage license "MIT-style STK-4.3 license";
resVoltage =
case{
(0, R, ein) => !, R^(1-rho)*ein;
(1, R, ein) => _;
(2, R, ein) => R0
with {
R0 = R;
};
}with{
rho = 1;
};
//----------------------`(wd.)resVoltage_Vout`--------------------------
// Adapted Resistive Voltage Source + voltage output.
//
// An adaptor implementing an adapted resistive voltage source within Wave Digital Filter connection trees.
//
// It should be used as a leaf/terminating element of the connection tree.
// It is comprised of an ideal voltage source in series with a resistor.
// Can be used for either DC (constant) or AC (signal) voltage sources.
// The resistive voltage source will also pass the voltage across it as an output of the model.
//
// #### Usage
//
// ```
// vout(i) = resVoltage_Vout(i, R, ein);
// buildtree( A : vout ) : _;
// ```
//
// Where:
//
// * `i`: index used by model-building functions. Should never be user declared
// * `R` : Resistance/Impedance of the series resistor in Ohms
// * `ein` : Voltage/Potential across ideal voltage source in Volts
//
// Note:
// The adaptor must be declared as a separate function before integration into the connection tree.
// Correct implementation is shown above.
//
// #### Reference
//
// K. Werner, "Virtual Analog Modeling of Audio Circuitry Using Wave Digital Filters", 1.2.4
//----------------------------------------------------------
declare resVoltage_Vout author "Dirk Roosenburg";
declare resVoltage_Vout copyright "Copyright (C) 2020 by Dirk Roosenburg <[email protected]>";
declare resVoltage_Vout license "MIT-style STK-4.3 license";
resVoltage_Vout =
case{
(0, R, ein) => R^(1-rho)*ein, _*.5 + R^(1-rho)*ein*.5;
(1, R, ein) => _, !;
(2, R, ein) => R0
with {
R0 = R;
};
}with{
rho = 1;
};
//----------------------`(wd.)u_resVoltage`--------------------------
// Unadapted Resistive Voltage Source.
//
// An unadapted adaptor implementing a resistive voltage source within Wave Digital Filter connection trees.
//
// It should be used as the root/top element of the connection tree.
// It is comprised of an ideal voltage source in series with a resistor.
// Can be used for either DC (constant) or AC (signal) voltage sources.
//
// #### Usage
//
// ```
// v1(i) = u_resVoltage(i, R, ein);
// buildtree( v1 : B );
// ```
//
// Where:
//
// * `i`: index used by model-building functions. Should never be user declared
// * `R` : Resistance/Impedance of the series resistor in Ohms
// * `ein` : Voltage/Potential across ideal voltage source in Volts
//
// Note:
// Only usable as the root of a tree.
// The adaptor must be declared as a separate function before integration into the connection tree.
// Correct implementation is shown above.
//
// #### Reference
//
// K. Werner, "Virtual Analog Modeling of Audio Circuitry Using Wave Digital Filters", 1.2.4
//----------------------------------------------------------
declare u_resVoltage author "Dirk Roosenburg";
declare u_resVoltage copyright "Copyright (C) 2020 by Dirk Roosenburg <[email protected]>";
declare u_resVoltage license "MIT-style STK-4.3 license";
u_resVoltage =
case {
(0, R, ein) => b0
with{
b0(R0, a0) = a0*(R - R0)/(R+R0) + ein*(2*R0^rho)/(R + R0);
};
(1, R, ein) => !, !;
(2, R, ein) => 0;
}with{
rho = 1;
};
//----------------------`(wd.)resCurrent`--------------------------
// Unadapted Resistive Current Source.
//
// An adaptor implementing a resistive current source within Wave Digital Filter connection trees.
//
// It should be used as a leaf/terminating element of the connection tree.
// It is comprised of an ideal current source in parallel with a resistor.
// Can be used for either DC (constant) or AC (signal) current sources.
//
// #### Usage
//
// ```
// i1(i) = resCurrent(i, R, jin);
// buildtree( A : i1 );
// ```
//
// Where:
//
// * `i`: index used by model-building functions. Should never be user declared.
// * `R` : Resistance/Impedance of the parallel resistor in Ohms
// * `jin` : Current through the ideal current source in Amps
//
// Note:
// The adaptor must be declared as a separate function before integration into the connection tree.
// Correct implementation is shown above.
//
// #### Reference
//
// K. Werner, "Virtual Analog Modeling of Audio Circuitry Using Wave Digital Filters", 1.2.5
//----------------------------------------------------------
declare resCurrent author "Dirk Roosenburg";
declare resCurrent copyright "Copyright (C) 2020 by Dirk Roosenburg <[email protected]>";
declare resCurrent license "MIT-style STK-4.3 license";
resCurrent =
case {
(0, R, jin) => !, 2*R^(rho)*jin;
(1, R, jin) => _;
(2, R, jin) => R0
with {
R0 = R;
};
}with{
rho = 1; //assume voltage waves
};
//----------------------`(wd.)u_resCurrent`--------------------------
// Unadapted Resistive Current Source.
//
// An unadapted adaptor implementing a resistive current source within Wave Digital Filter connection trees.
//
// It should be used as the root/top element of the connection tree.
// It is comprised of an ideal current source in parallel with a resistor.
// Can be used for either DC (constant) or AC (signal) current sources.
//
// #### Usage
//
// ```
// i1(i) = u_resCurrent(i, R, jin);
// buildtree( i1 : B );
// ```
//
// Where:
//
// * `i`: index used by model-building functions. Should never be user declared.
// * `R` : Resistance/Impedance of the series resistor in Ohms
// * `jin` : Current through the ideal current source in Amps
//
// Note:
// Only usable as the root of a tree.
// The adaptor must be declared as a separate function before integration into the connection tree.
// Correct implementation is shown above.
//
// #### Reference
//
// K. Werner, "Virtual Analog Modeling of Audio Circuitry Using Wave Digital Filters", 1.2.5
//----------------------------------------------------------
declare u_resCurrent author "Dirk Roosenburg";
declare u_resCurrent copyright "Copyright (C) 2020 by Dirk Roosenburg <[email protected]>";
declare u_resCurrent license "MIT-style STK-4.3 license";
u_resCurrent =
case {
(0, R, jin) => b0
with{
b0(R0, a0) = a0*(R - R0)/(R + R0) + jin*(2*R*R0^rho)/(R + R0);
};
(1, R, jin) => !, !;
(2, R, jin) => 0;
}with{
rho = 1; //assume voltage waves
};
//TODO
//add short circuit (1.2.6), add open circuit (1.2.7)
//----------------------`(wd.)u_switch`--------------------------
// Unadapted Ideal Switch.
//
// An unadapted adaptor implementing an ideal switch for Wave Digital Filter connection trees.
//
// It should be used as the root/top element of the connection tree
//
// #### Usage
//
// ```
// s1(i) = u_resCurrent(i, lambda);
// buildtree( s1 : B );
// ```
//
// Where:
//
// * `i`: index used by model-building functions. Should never be user declared.
// * `lambda` : switch state control. -1 for closed switch, 1 for open switch.
//
// Note:
// Only usable as the root of a tree
// The adaptor must be declared as a separate function before integration into the connection tree.
// Correct implementation is shown above.
//
// #### Reference
//
// K. Werner, "Virtual Analog Modeling of Audio Circuitry Using Wave Digital Filters", 1.2.8
//----------------------------------------------------------
declare u_switch author "Dirk Roosenburg";
declare u_switch copyright "Copyright (C) 2020 by Dirk Roosenburg <[email protected]>";
declare u_switch license "MIT-style STK-4.3 license";
u_switch =
case {
(0, lambda) => b0
with{
b0(R0, a0) = a0*lambda;
};
(1, lambda) => !, !;
(2, lambda) => 0;
};
//=============================Reactive One Port Adaptors=================================
//========================================================================================
//TODO - add mobius transform and alpha transform digitizations
//----------------------`(wd.)capacitor`--------------------------
// Adapted Capacitor.
//
// A basic adaptor implementing a capacitor for use within Wave Digital Filter connection trees.
//
// It should be used as a leaf/terminating element of the connection tree.
// This capacitor model was digitized using the bi-linear transform.
//
// #### Usage
//
// ```
// c1(i) = capacitor(i, R);
// buildtree( A : c1 ) : _;
// ```
//
// Where:
//
// * `i`: index used by model-building functions. Should never be user declared.
// * `R` : Capacitance/Impedance of the capacitor being modeled in Farads.
//
// Note:
// The adaptor must be declared as a separate function before integration into the connection tree.
// Correct implementation is shown above.
//
// #### Reference
//
// K. Werner, "Virtual Analog Modeling of Audio Circuitry Using Wave Digital Filters", 1.3.1
//----------------------------------------------------------
declare capacitor author "Dirk Roosenburg";
declare capacitor copyright "Copyright (C) 2020 by Dirk Roosenburg <[email protected]>";
declare capacitor license "MIT-style STK-4.3 license";
capacitor =
case{
(0, R) => _*1;
(1, R) => _;
(2, R) => R0
with {
R0 = t/(2*R);
};
}with{
t = 1/ma.SR; //sampling interval
};
//----------------------`(wd.)capacitor_Vout`--------------------------
// Adapted Capacitor + voltage out.
//
// A basic adaptor implementing a capacitor for use within Wave Digital Filter connection trees.
//
// It should be used as a leaf/terminating element of the connection tree.
// The capacitor will also pass the voltage across itself as an output of the model.
// This capacitor model was digitized using the bi-linear transform.
//
// #### Usage
//
// ```
// cout(i) = capacitor_Vout(i, R);
// buildtree( A : cout ) : _;
// ```
//
// Where:
//
// * `i`: index used by model-building functions. Should never be user declared
// * `R` : Capacitance/Impedence of the capacitor being modeled in Farads
//
// Note:
// The adaptor must be declared as a seperate function before integration into the connection tree.
// Correct implementation is shown above.
//
// #### Reference
//
// K. Werner, "Virtual Analog Modeling of Audio Circuitry Using Wave Digital Filters", 1.3.1
//----------------------------------------------------------
declare capacitor_Vout author "Dirk Roosenburg";
declare capacitor_Vout copyright "Copyright (C) 2020 by Dirk Roosenburg <[email protected]>";
declare capacitor_Vout license "MIT-style STK-4.3 license";
capacitor_Vout =
case{
(0, R) => b0
with{
b0(a1) = a1*1, a1*.5 + (a1')*.5;
};
(1, R) => _, !;
(2, R) => R0
with {
R0 = t/(2*R);
};
}with{
t = 1/ma.SR; //sampling interval
};
//----------------------`(wd.)inductor`--------------------------
// Unadapted Inductor.
//
// A basic adaptor implementing an inductor for use within Wave Digital Filter connection trees.
//
// It should be used as a leaf/terminating element of the connection tree.
// This inductor model was digitized using the bi-linear transform.
//
// #### Usage
//
// ```
// l1(i) = inductor(i, R);
// buildtree( A : l1 );
// ```
//
// Where:
//
// * `i`: index used by model-building functions. Should never be user declared
// * `R` : Inductance/Impedance of the inductor being modeled in Henries
//
// Note:
// The adaptor must be declared as a separate function before integration into the connection tree.
// Correct implementation is shown above.
//
// #### Reference
//
// K. Werner, "Virtual Analog Modeling of Audio Circuitry Using Wave Digital Filters", 1.3.2
//----------------------------------------------------------
declare inductor author "Dirk Roosenburg";
declare inductor copyright "Copyright (C) 2020 by Dirk Roosenburg <[email protected]>";
declare inductor license "MIT-style STK-4.3 license";
inductor =
case{
(0, R) => _*(-1);
(1, R) => _;
(2, R) => R0
with {
R0 = (2*R)/t;
};
}with{
t = 1/ma.SR; //sampling interval
};
//----------------------`(wd.)inductor_Vout`--------------------------
// Unadapted Inductor + Voltage out.
//
// A basic adaptor implementing an inductor for use within Wave Digital Filter connection trees.
//
// It should be used as a leaf/terminating element of the connection tree.
// The inductor will also pass the voltage across itself as an output of the model.
// This inductor model was digitized using the bi-linear transform.
//
// #### Usage
//
// ```
// lout(i) = inductor_Vout(i, R);
// buildtree( A : lout ) : _;
// ```
//
// Where:
//
// * `i`: index used by model-building functions. Should never be user declared
// * `R` : Inductance/Impedance of the inductor being modeled in Henries
//
// Note:
// The adaptor must be declared as a separate function before integration into the connection tree.
// Correct implementation is shown above.
//
// #### Reference
//
// K. Werner, "Virtual Analog Modeling of Audio Circuitry Using Wave Digital Filters", 1.3.2
//----------------------------------------------------------
declare inductor_Vout author "Dirk Roosenburg";
declare inductor_Vout copyright "Copyright (C) 2020 by Dirk Roosenburg <[email protected]>";
declare inductor_Vout license "MIT-style STK-4.3 license";
inductor_Vout =
case{
(0, R) => b0
with{
b0(a1) = a1*(-1), a1*.5 - (a1')*.5;
};
(1, R) => _, !;
(2, R) => R0
with {
R0 = (2*R)/t;
};
}with{
t = 1/ma.SR; //sampling interval
};
//===============================Nonlinear One Port Adaptors==============================
//========================================================================================
//----------------------`(wd.)u_idealDiode`--------------------------
// Unadapted Ideal Diode.
//
// An unadapted adaptor implementing an ideal diode for Wave Digital Filter connection trees.
//
// It should be used as the root/top element of the connection tree.
//
// #### Usage
//
// ```
// buildtree( u_idealDiode : B );
// ```
//
// Note:
// Only usable as the root of a tree
// Correct implementation is shown above.
//
// #### Reference
//
// K. Werner, "Virtual Analog Modeling of Audio Circuitry Using Wave Digital Filters", 3.2.3
//----------------------------------------------------------
declare u_idealDiode author "Dirk Roosenburg";
declare u_idealDiode copyright "Copyright (C) 2020 by Dirk Roosenburg <[email protected]>";
declare u_idealDiode license "MIT-style STK-4.3 license";
u_idealDiode =
case{
(0) => b1
with{
b1(R1, a0) = a0 : abs : *(-1);
};
(1) => !, !;
(2) => 0;
};
//----------------------`(wd.)u_chua`--------------------------
// Unadapted Chua Diode.
//
// An adaptor implementing the chua diode / non-linear resistor within Wave Digital Filter connection trees.
//
// It should be used as the root/top element of the connection tree.
//
// #### Usage
//
// ```
// chua1(i) = u_chua(i, G1, G2, V0);
// buildtree( chua1 : B );
// ```
//
// Where:
//
// * `i`: index used by model-building functions. Should never be user declared
// * `G1` : resistance parameter 1 of the chua diode
// * `G2` : resistance parameter 2 of the chua diode
// * `V0` : voltage parameter of the chua diode
//
// Note:
// Only usable as the root of a tree.
// The adaptor must be declared as a separate function before integration into the connection tree.
// Correct implementation is shown above.
//
// #### Reference
//
// Meerkotter and Scholz, "Digital Simulation of Nonlinear Circuits by Wave Digital Filter Principles"
//----------------------------------------------------------
declare u_chua author "Dirk Roosenburg";
declare u_chua copyright "Copyright (C) 2020 by Dirk Roosenburg <[email protected]>";
declare u_chua license "MIT-style STK-4.3 license";
u_chua =
case{
(0, G1, G2, V0) => b1
with{
b1(R1, a0) = g_1*a0 + 1/2*(g_2 - g_1)*(((a0 + a_0) : abs) - ((a0 - a_0): abs))
with{
g_1 = (1-G1*R1)/(1+G1*R1);
g_2 = (1-G2*R1)/(1+G2*R1);
a_0 = V0*(1+G2*R1);
};
};
(1, G1, G2, V0) => !, !;
(2, G1, G2, V0) => 0;
};
//----------------------`(wd.)lambert`--------------------------
// An implementation of the lambert function.
// It uses Halley's method of iteration to approximate the output.
// Included in the WD library for use in non-linear diode models.
// Adapted from K M Brigg's c++ lambert function approximation.
//
// #### Usage
//
// ```
// lambert(n, itr) : _;
// ```
//
// Where:
// * `n`: value at which the lambert function will be evaluated
// * `itr`: number of iterations before output
//
//----------------------------------------------------------
declare lambert author "Dirk Roosenburg";
declare lambert copyright "Copyright (C) 2020 by Dirk Roosenburg <[email protected]>";
declare lambert license "MIT-style STK-4.3 license";
lambert(z, itr) = ba.if((z<(-em1+.0001)), less_approx, greater_approx)
with{
less_approx = -1.0
+2.331643981597124203363536062168*r
-1.812187885639363490240191647568*q
+1.936631114492359755363277457668*r*q
-2.353551201881614516821543561516*q2
with{