summaryrefslogtreecommitdiff
path: root/plugins/ZamTube/triode.cpp
blob: ec42960833cd4c188c23320762e9ac7c85a35586 (plain)
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
#include <stdio.h>
#include <inttypes.h>
#include <cmath>
#include "triode.h"
using std::abs;
#define DUMP(x) x

T Triode::compute(T a, T R, T Vg, T Vk) {
	T VakGuess = 100.;
	T Vgk = Vg - Vk;
	T Vak = VakGuess;
	int iteration = 0;
	T err = 1e6;

	for (iteration = 0; (fabs(err)/fabs(Vak) > EPSILON) && (iteration <= ITER); iteration++){
		VakGuess = iterateNewtonRaphson(Vak, TOLERANCE, Vgk, a, R);
		err = Vak - VakGuess;
		Vak = VakGuess;
	}
	T b = Vak - R*getIa(Vgk, Vak);

	//printf("Vgate=%f Vk=%f  Vgk=%f b=%f\n", Vgate, Vk, Vgk, b);
	return b;
}

T Triode::getIa(T Vgk, T Vpk) const {
	if (Vpk < 0.0) {
		Vpk = 0.0;
	}
	if (Vgk > 0.0) {
		Vgk = 0.0;
	}

	/* f(x,y) = (y*log(1+kp/mu*exp(1+mu*x/sqrt(kvb+y*y))))^kx
	 *        = (y*log(1+6*exp(1+100*x/sqrt(300+y*y))))^1.4
	 * 
	 * Let y' = y * sqrt(300)
	 * Let x' = x * 100 / sqrt(300)
	 *
	 * f(x',y') = (y'*log(1+6*exp(1+x'/sqrt(1+y'*y'))))^1.4
	 *
	 * When -x'/y' < 17
	 * 	f(x',y') ~= (y' - 3*exp(1)*x')^1.4
	 * 	f(x,y) ~= (y/sqrt(300) - 3*exp(1)*x*sqrt(300)/100)^1.4
	 *
	 * When |x'| is small && y' is large
	 * 	f(x',y') ~= (y'*log(1 + 6*exp(1)))^1.4
	 * 	f(x,y) ~=(y/sqrt(300)*log(1 + 6*exp(1)))^1.4
	 *
	 * Otherwise, use exact solution
	 */
	float f = 0.f;
	float sc = 1e+6 / kg1;
/*
#define G_NEG_SMALL	-1.f
#define P_LARGE		150.f
	float e1 = expf(1.f);
	float r300 = sqrtf(300.f);

	if (-Vgk/Vpk < 17.) {
		f = sc * powf(Vpk / r300 - 3.f * e1 * Vgk * r300 / 100., 1.4f);
	} else if ((Vgk > G_NEG_SMALL) && (Vpk > P_LARGE)) {
		f = sc * powf(Vpk * log1pf(6.f*e1) / r300, 1.4f);
	} else {
*/
		/* exact solution (expensive) */
		float ee1 = Vpk*log1pf(expf(kp*(1./mu+Vgk/sqrtf(kvb+Vpk*Vpk))))/kp;
		if (ee1 < 0) {
			return 0.;
		}
		f = sc * powf(ee1, kx);
//	}
	//printf("Vpk=%f e1=%f exact_e1=%f\n", Vpk, ans, e1, ee1);
	return f;
}

T Triode::iterateNewtonRaphson(T x, T dx, T Vgk, T a, T R) const {
	T xIak = getIa(Vgk, x);
	T dxIak = getIa(Vgk, x + dx);
	T xNew = x - dx*(x + R*xIak - a)/(dx + R*(dxIak - xIak));
	return xNew;
}

Triode::Triode()
{
	/* good for low gain, broken at high gain
	kvb = 300.;
	mu = 103.2;
	kx = 1.26;
	kg1 = 446.0;
	kp = 3.4;
	*/
	
	//12AX7 RSD-1 (custom)
	mu = 100.;
	kx = 1.4;
	kg1 = 446.;
	kp = 600.;
	kvb = 300.;
}