Previous Thread
Next Thread
Print Thread
Page 3 of 5 1 2 3 4 5
Re: Netlist: 280-ZZZAP sound problems [Re: Colin Howell] #117294 05/01/20 07:50 PM
Joined: Feb 2007
Posts: 498
C
couriersud Offline
Senior Member
Offline
Senior Member
C
Joined: Feb 2007
Posts: 498
Good catch! From an academic point of view I agree. However, there is always a death to die. I opted for speed instead of (sometimes spurious) accuracy. Netlist is about being bold in leaving away detail.

The cheekyms noise circuit is basically a BJT with the collector not connected and the noise of the B-E is amplified. In cheekyms a simple voltage source driven by a function is used to replace this. Having the lfsr in pfunction was a hack to get noise working. I will remove it again since it causing grief.

You are right, in this setup a new random value is created whenever the function is called. A better implementation would be an AFUNC driven by a CLOCK. That would address the time stepping issue. But this approach mean less performance. But it would be worth a try.

Even better would be fast NOISE device. Open for suggestions :-)

But please, no rand(). I had so much fun with different hash implementations across platforms and standard libraries that I will never again rely on implementation details.

Re: Netlist: 280-ZZZAP sound problems [Re: couriersud] #117295 05/01/20 09:02 PM
Joined: Jun 2003
Posts: 48
C
Colin Howell Offline OP
Member
OP Offline
Member
C
Joined: Jun 2003
Posts: 48
Well, the thing that bothers me about the short repetition cycle is the fact that you can hear it, which is a problem if the noise-based sound effect is long enough and fairly constant. Stops sounding like real noise at that point.

It shouldn't be any slower on modern hardware to have a 32-bit LFSR or some other implementation with a 32-bit period, should it? And if varying implementations across platforms is a problem, wouldn't using your own implementation of a standard pseudorandom generator function be enough?

Re: Netlist: 280-ZZZAP sound problems [Re: Colin Howell] #117296 05/01/20 09:53 PM
Joined: Feb 2007
Posts: 498
C
couriersud Offline
Senior Member
Offline
Senior Member
C
Joined: Feb 2007
Posts: 498
Originally Posted by Colin Howell
It shouldn't be any slower on modern hardware to have a 32-bit LFSR or some other implementation with a 32-bit period, should it?

No issue, even 64bit will work.

Originally Posted by Colin Howell
And if varying implementations across platforms is a problem, wouldn't using your own implementation of a standard pseudorandom generator function be enough?

That's the reason for the lfsr implemenation:-)
I'll think about something better.

Re: Netlist: 280-ZZZAP sound problems [Re: Colin Howell] #117297 05/02/20 06:48 AM
Joined: Feb 2004
Posts: 2,145
Vas Crabb Online Content
Very Senior Member
Online Content
Very Senior Member
Joined: Feb 2004
Posts: 2,145
You can use the C++11 standard library's pseudo-random number generation module. The Mersenne twister has a very long period and will always give the same output given the same entropy.

Re: Netlist: 280-ZZZAP sound problems [Re: Colin Howell] #117298 05/02/20 08:04 AM
Joined: Feb 2007
Posts: 498
C
couriersud Offline
Senior Member
Offline
Senior Member
C
Joined: Feb 2007
Posts: 498
I would love to do so. But state saving kicks in here :-(
To save the state, I could do a binary save of the variable. But that's not portable at all. I could use the "<<" and ">>" operators to get into a string but than have a string with unpredictable length. That is something the state save system doesn't handle.
Any help welcome here. Currently the overhead on save state makes it easier to implement the algo myself.

Re: Netlist: 280-ZZZAP sound problems [Re: Colin Howell] #117299 05/02/20 08:28 PM
Joined: Sep 2004
Posts: 387
A
AaronGiles Offline
Senior Member
Offline
Senior Member
A
Joined: Sep 2004
Posts: 387
Something like TinyMT might make sense here. He has a 32-bit and 64-bit version, both with minimal state. The code is pretty small and BSD, so you could probably just rip it off and insert it into your framework. Happy to look into it if you're interested.

https://github.com/MersenneTwister-Lab/TinyMT

Re: Netlist: 280-ZZZAP sound problems [Re: Colin Howell] #117302 05/03/20 12:24 AM
Joined: Feb 2007
Posts: 498
C
couriersud Offline
Senior Member
Offline
Senior Member
C
Joined: Feb 2007
Posts: 498
I now have written a MT implementation from scratch following the wikipedia entry and adopted it to be compatible to the c++11 standard. It delivers the same sequence as the std:: counterpart.

It compiles as a random provider for std::normal_distribution.

This will be implemented as a voltage source which is externally clocked. This way you can have one clock triggering a number of noise source.
Can be extended to current and conductivity noise and other distributions. This is getting too academic :-)

Re: Netlist: 280-ZZZAP sound problems [Re: couriersud] #117303 05/03/20 01:45 AM
Joined: Sep 2004
Posts: 387
A
AaronGiles Offline
Senior Member
Offline
Senior Member
A
Joined: Sep 2004
Posts: 387
You're having too much fun. ;-)

I started down the path of making a prandom.h in plib which would have support for multiple random number sources (including TinyMT and your 16-bit LFSR) so that they could be selectable at compile time for whatever needs. Thought that might be handy.

Re: Netlist: 280-ZZZAP sound problems [Re: Colin Howell] #117308 05/03/20 03:26 PM
Joined: Feb 2007
Posts: 498
C
couriersud Offline
Senior Member
Offline
Senior Member
C
Joined: Feb 2007
Posts: 498
commit b2c40086e6b003121e61719da93944f4e360e33d
Branches: master, origin/master

netlist: Add two noise sources. [Couriersud]

The two sources act as voltage sources, though noise may also be
injected as conductivy or current noise.

SYS_NOISE_MT_U: Mersenne Twister uniform noise
SYS_NOISE_MT_N: Mersenne Twister normal noise

nld_sys_noise is templated:

Code
	
using NETLIB_NAME(sys_noise_mt_u) =
	NETLIB_NAME(sys_noise)<plib::mt19937_64, plib::uniform_distribution_t>;

Thus the approach is scalable. The implementation is state save aware,
and thus reproducible results are guaranteed.

An example use case is provided as well, see examples/noise.cpp.

Re: Netlist: 280-ZZZAP sound problems [Re: Colin Howell] #117326 05/13/20 11:59 PM
Joined: Jun 2003
Posts: 48
C
Colin Howell Offline OP
Member
OP Offline
Member
C
Joined: Jun 2003
Posts: 48
I know it's been a while since you heard from me; out of disappointment with the result, I sort of put this on the back burner for a while. I've included the most recent version of the netlist I've developed below. (Sorry about the 800 lines of source. I would have made it an attachment, but those seem to be disabled.) This netlist does work, after a fashion. I'm not really satisfied with it, but I'm not sure how much else can be squeezed out. Even with a whole bunch of speedups: *lots* of frontiers, reduced opamp gain on the oscillators, static timestepping, and reduced RELTOL, VNTOL, and ACCURACY, I can only get 140-145% speedup out of 280zzzap running unthrottled without frameskipping on my 2.5 GHz Core i7 (Mid 2014 Macbook Pro). It does run and is playable on my system, but that's very little headroom left from what is otherwise a very low-impact driver, and I wouldn't expect it to be accepted. Trying other speedups (trying different solvers or matrix sorting methods, turning on parallelism) didn't help at all. Also, I'm not very happy with the "BOOM" sound, since I only hear a burst of noise with no sense of an initial "boom". The circuit looks correct; it may be that my little laptop speakers just don't have enough bass response, I'm not sure.

There are 16 opamps in this netlist, as there are in the original sound hardware. I may be able to remove the two final ones at the output stage, but that's still a lot of opamps. The MC3340 voltage-controlled amplifier/attenuator, which is an important part of the engine sound circuits, is also a problem: it has 10 BJTs in it, which has to hurt performance. I assume it's possible to make a stripped down sham-MC3340 circuit with equivalent behavior, but I'm not sure how to do so.

I haven't yet tried your new noise circuits or Zener diode implementation; I wanted to show this progress first.

Code
// license:CC0
// copyright-holders:Colin Douglas Howell

#include "netlist/devices/net_lib.h"

static NETLIST_START(mc3340)

	// A netlist description of the Motorola MC3340 Electronic Attenuator.
	// This IC is actually a voltage-controlled attenuator/amplifier.  It
	// can produce a small amount of positive gain (about 12-13 dB, or
	// about a factor of 4 in voltage), but its main purpose is to
	// attentuate an input signal by the voltage level of a second control
	// signal; higher control voltages lead to greater attenuation. The
	// netlist here is based on the circuit schematic given in Motorola's
	// own data books, mainly the most recent ones published in the 1990s
	// (e.g. _Motorola Analog/Interface ICs Device Data, Vol. II_ (1996),
	// p. 9-67). However, the 1990s schematics are missing one crossover
	// connection which is present in older schematics published in the
	// 1970s (e.g. Motorola Linear Integrated Circuits (1979), p. 5-130).
	// This missing connection has been included in this netlist; without
	// it, the circuit only generates a very weak output signal.

	// The Motorola schematics do not label components, so I've created my
	// own labeling scheme based on numbering components from left to
	// right, top to bottom, with resistors also getting their value
	// (expressed European-style to avoid decimal points) as part of the
	// name.

	// I have not provided a model for the transistors here; instead I
	// left them as the generic default for NPN. All the transistor models
	// currently in the netlist library are for discrete transistors and
	// would not be very appropriate for those on an IC. The default
	// values seem similar to those of SPICE, whose device model defaults
	// were deliberately chosen to resemble IC-based devices.

	// Incidentally, the MC3340 has the same circuit internally as an
	// older Motorola device, the MFC6040, which was replaced by the
	// MC3340 in the mid-1970s. The two chips differ only in packaging.
	// (Noting this in case a system containing the older chip ever shows
	// up in MAME.)

	RES(R1_5K1, RES_K(5.1))

	RES(R2_4K7, RES_K(4.7))

	QBJT_EB(Q1, "NPN")

	RES(R3_750, RES_R(750))
	RES(R4_10K, RES_K(10))

	QBJT_EB(Q2, "NPN")

	RES(R5_750, RES_R(750))
	RES(R6_3K9, RES_K(3.9))

	RES(R7_5K1, RES_K(5.1))
	RES(R8_20K, RES_K(20))

	RES(R9_510, RES_R(510))

	QBJT_EB(Q3, "NPN")

	QBJT_EB(Q4, "NPN")

	QBJT_EB(Q5, "NPN")

	RES(R10_1K3, RES_K(1.3))

	QBJT_EB(Q6, "NPN")

	RES(R11_5K1, RES_K(5.1))

	QBJT_EB(Q7, "NPN")

	QBJT_EB(Q8, "NPN")

	RES(R12_1K5, RES_K(1.5))

	RES(R13_6K2, RES_K(6.2))

	QBJT_EB(Q9, "NPN")

	RES(R14_5K1, RES_K(5.1))

	QBJT_EB(Q10, "NPN")

	RES(R15_5K1, RES_K(5.1))

	RES(R16_200, RES_R(200))

	RES(R17_5K1, RES_K(5.1))

	DIODE(Dinternal, 1N914)

	RES(R18_510, RES_R(510))

	ALIAS(MC3340_VCC, R1_5K1.1)
	NET_C(R1_5K1.1, Q1.C, Q2.C, R7_5K1.1, Q3.C, Q4.C, Q7.C,
		R13_6K2.1, Q10.C, R17_5K1.1)
	NET_C(R1_5K1.2, R2_4K7.1, Q1.B)
	NET_C(R2_4K7.2, GND)

	NET_C(Q1.E, R3_750.1, R5_750.1)
	NET_C(R3_750.2, R4_10K.1, Q2.B)
	NET_C(R4_10K.2, GND)

	NET_C(R5_750.2, R6_3K9.1, Q3.B)
	ALIAS(MC3340_CONTROL, R6_3K9.2)

	ALIAS(MC3340_INPUT, Q5.B)

	NET_C(MC3340_INPUT, R8_20K.1)
	NET_C(R7_5K1.2, R8_20K.2, R9_510.1)
	NET_C(R9_510.2, GND)

	NET_C(Q4.E, Q6.E, Q5.C)
	NET_C(Q5.E, R10_1K3.1)
	NET_C(R10_1K3.2, GND)

	NET_C(Q6.B, Q7.B, Q2.E, R11_5K1.1)
	NET_C(R11_5K1.2, GND)

	NET_C(Q7.E, Q9.E, Q8.C)
	NET_C(Q8.E, R12_1K5.1)
	NET_C(R12_1K5.2, GND)

	NET_C(Q4.B, Q9.B, Q3.E, R14_5K1.1)
	NET_C(R14_5K1.2, GND)

	NET_C(Q6.C, R13_6K2.2, Q9.C, Q10.B)

	ALIAS(MC3340_ROLLOFF, Q10.B)

	NET_C(Q10.E, R16_200.1, R15_5K1.1)
	NET_C(R15_5K1.2, GND)
	ALIAS(MC3340_OUTPUT, R16_200.2)

	NET_C(R17_5K1.2, Dinternal.A, Q8.B)
	NET_C(Dinternal.K, R18_510.1)
	NET_C(R18_510.2, GND)

NETLIST_END()


static NETLIST_START(zzzap_schematics)

	RES(R22, RES_R(470))

	DIODE(D1, 1N914)

	NET_C(I_V5.Q, R22.1)
	NET_C(I_F4_5.Q, R22.2, D1.A)

	// The 4-bit accelerator pedal input is converted to an analog voltage
	// by the first LM3900 op-amp H5_3, whose output is passed to the
	// second op-amp H5_4. H5_4's output voltage serves as an "engine
	// speed" signal.  With the engine on (ENGINE SOUND *low*) this signal
	// ramps up as capacitor C18 charges, with the rise slowing as time
	// passes. It ramps faster with a greater accelerator level, and ramps
	// faster in low gear (LO SHIFT high) than in high gear (HI SHIFT
	// high). If ENGINE SOUND goes high, CD4016 switch G5_A (G5 pins 1, 2,
	// 13) is closed and capacitor C18 is discharged, dropping the voltage
	// enough to cut off the engine sound entirely.

	// Although the schematics don't show the CD4016s' power input,
	// they need 5-volt power to respond at the proper voltage levels.
	CD4016_DIP(G5)
	NET_C(G5.7, GND)
	NET_C(G5.14, I_V5.Q)
	NET_C(GND, G5.10, G5.11, G5.12)

	LM3900(H5_3)
	LM3900(H5_4)

	RES(R42, RES_K(1))
	RES(R43, RES_K(1))
	RES(R44, RES_K(1))
	RES(R45, RES_K(1))
	RES(R62, RES_K(1))
	RES(R61, RES_K(1))

	RES(R51, RES_K(480))  // 470 Kohm in later Laguna and SS Race
	RES(R46, RES_M(2))  // 2.2 Mohm in later Laguna and SS Race
	RES(R47, RES_M(1))
	RES(R48, RES_K(480))  // 470 Kohm in later Laguna and SS Race
	RES(R49, RES_K(240))

	RES(R50, RES_K(100))
	// SS Race also has a 1 uF capacitor in parallel with R50.
	RES(R53, RES_K(47))
	RES(R52, RES_K(10))
	RES(R56, RES_R(270))

	RES(R54, RES_K(560))
	RES(R55, RES_M(4.7))

	RES(R57, RES_M(2.7))
	RES(R58, RES_K(560))

	RES(R59, RES_K(560))
	RES(R60, RES_K(10))

	CAP(C18, CAP_U(47))  // 22 uF in later Laguna and SS Race
	NET_C(C18.2, GND)

	CAP(C19, CAP_U(2.2))

	DIODE(D4, 1N914)
	DIODE(D5, 1N914)

	NET_C(I_V5.Q, R42.1, R43.1, R44.1, R45.1, R62.1, R61.1, R51.1,
		R55.1, R57.1)

	NET_C(I_F5_2.Q, R42.2, R46.1)
	NET_C(I_F5_5.Q, R43.2, R47.1)
	NET_C(I_F5_7.Q, R44.2, R48.1)
	NET_C(I_F5_10.Q, R45.2, R49.1)
	NET_C(H5_3.PLUS, R46.2, R47.2, R48.2, R49.2, R51.2)
	NET_C(H5_3.MINUS, R50.2)
	NET_C(H5_3.OUT, R50.1, R53.1, D4.K)
	// SS Race also has a 1 uF capacitor in parallel with R50.
	NET_C(R53.2, R52.1, C18.1, R56.2, R54.1)
	NET_C(R52.2, D4.A)
	NET_C(H5_4.PLUS, R54.2, R55.2)
	NET_C(H5_4.MINUS, R58.2, R57.2, G5.4)
	NET_C(H5_4.OUT, D5.A, R59.1)  // see below for further connections...
	NET_C(D5.K, R58.1)
	NET_C(C19.1, R59.2, R60.2)

	NET_C(G5.1, GND)
	NET_C(G5.2, R56.1)
	NET_C(G5.13, I_F4_5.Q)  // ENGINE SOUND (high for *off*)

	NET_C(G5.5, R62.2, I_F5_12.Q)  // HI SHIFT

	NET_C(G5.3, G5.8, C19.2)
	NET_C(G5.9, R60.1)
	NET_C(G5.6, R61.2, I_F5_15.Q)  // LO SHIFT

	// Engine sound oscillators. There are three of these, at different
	// frequencies; all three are triangle-wave oscillators whose frequency
	// is controlled by the voltage signal output from LM3900 op-amp H5_4.
	// Each oscillator is a cascaded pair of LM3900s and a CD4016 switch.
	// The switch feeds into the non-feedback input of the first op-amp,
	// whose output is also the final oscillator output; the second op-amp
	// acts as a Schmitt trigger on the first op-amp's output, generating
	// a square wave that controls the switch. Two of the oscillators are
	// combined to drive the signal input of an MC3340 voltage-controlled
	// amplifier/attenuator; one has four times the frequency of the
	// other, producing a ragged waveform.  The third oscillator, whose
	// frequency is somewhat above the faster of the first two, drives the
	// MC3340's control input to amplitude-modulate the signal input from
	// the first two oscillators.  Greater voltages on this control signal
	// produce greater attenuation, and thus the final signal has a
	// "hilly" profile.

	// Like the other CD4016, this one needs 5 volt power.
	CD4016_DIP(J4)
	NET_C(J4.7, GND)
	NET_C(J4.14, I_V5.Q)
	NET_C(GND, J4.6, J4.8, J4.9)

	// First oscillator (bottommost in schematics).
	// Frequency on schematic is 76 Hz, but the modeled maximum (in low
	// gear) is 87.02 Hz.
	// With speedups, this increases to 111.73 Hz.

	SUBMODEL(LM3900_lowgain, J5_2)
	SUBMODEL(LM3900_lowgain, J5_1)
//	LM3900(J5_2)
//	LM3900(J5_1)

	RES(R36, RES_K(560))
	RES(R37, RES_K(270))
	RES(R38, RES_K(100))
	RES(R39, RES_K(470))
	RES(R40, RES_K(270))
	RES(R41, RES_K(10))
	NET_C(R41.2, GND)

//	CAP(C17, CAP_U(0.022))
	// Oscillator capacitor increased to counter higher frequency from
	// emulation speedups (reduced LM3900 gain, use of frontiers):
	CAP(C17, CAP_U(0.02825))

	DIODE(D3, 1N914)

	NET_C(H5_4.OUT, R36.1, R37.1, R31.1, R32.1, R29.1, R30.1)
	// ... these are the remaining connections from H5_4.OUT.

	// Note the connections to this oscillator's CD4016 switch at J4 have
	// mislabeled pin numbers on the schematics for 280-ZZZAP and both
	// Laguna Racer versions; they are shown as pins 3, 4, 5, which are
	// for switch B, the same switch which is used by the middle
	// oscillator. The Super Speed Race schematic correctly shows this
	// oscillator using pins 10, 11, 12, which are for switch D of the
	// CD4016 (located at B1 in that game). It seems very unlikely that
	// the earlier games had two oscillators sharing the same switch; that
	// shouldn't work at all. I assume that this was a schematic error
	// which was not caught until much later.

	NET_C(R37.2, J4.10)
	NET_C(J4.11, J5_2.PLUS)
	NET_C(R36.2, J5_2.MINUS, C17.1)
	NET_C(J5_2.OUT, C17.2, R38.1, D3.A)
	NET_C(R38.2, J5_1.MINUS)
	NET_C(J5_1.OUT, R40.1, J4.12)
	NET_C(I_V5.Q, R39.1)
	NET_C(J5_1.PLUS, R39.2, R40.2)
	NET_C(R41.1, D3.K, D2.K, C16.1)

	// Second oscillator (middle in schematics).
	// Frequency on schematic is 315 Hz, but the modeled maximum (in low
	// gear) is 341.87 Hz.
	// With speedups, this increases to 399.91 Hz.

	SUBMODEL(LM3900_lowgain, J3_3)
	SUBMODEL(LM3900_lowgain, J3_4)
//	LM3900(J3_3)
//	LM3900(J3_4)

	RES(R31, RES_K(300))
	RES(R32, RES_K(150))
	RES(R33, RES_K(100))
	RES(R34, RES_K(470))
	RES(R35, RES_K(270))

//	CAP(C15, CAP_U(0.01))
	// Oscillator capacitor increased to counter higher frequency from
	// emulation speedups (reduced LM3900 gain, use of frontiers):
	CAP(C15, CAP_U(0.0117))
	CAP(C16, CAP_U(10))

	DIODE(D2, 1N914)

	NET_C(R32.2, J4.4)
	NET_C(J4.3, J3_3.PLUS)
	NET_C(R31.2, J3_3.MINUS, C15.1)
	NET_C(J3_3.OUT, C15.2, R33.1, D2.A)
	NET_C(R33.2, J3_4.MINUS)
	NET_C(J3_4.OUT, R35.1, J4.5)
	NET_C(I_V5.Q, R34.1)
	NET_C(J3_4.PLUS, R34.2, R35.2)
	NET_C(C16.2, MC3340_INPUT)  // to MC3340 H2 pin 1

	// Third oscillator (topmost in schematics).
	// Frequency on schematic is 428 Hz, but the modeled maximum (in low
	// gear) is 463.61 Hz.
	// With speedups, this increases to 520.16 Hz.
	// This is the amplitude-modulation oscillator.

	SUBMODEL(LM3900_lowgain, J3_2)
	SUBMODEL(LM3900_lowgain, J3_1)
//	LM3900(J3_2)
//	LM3900(J3_1)

	RES(R29, RES_K(220))
	RES(R30, RES_K(110))  // 100 Kohm in later Laguna and SS Race
	RES(R28, RES_K(100))
	RES(R26, RES_K(470))
	RES(R27, RES_K(270))

	RES(R25, RES_K(3.3))
	NET_C(R25.2, GND)

	RES(R23, RES_K(10))
	NET_C(R23.1, I_V12.Q)

//	CAP(C14, CAP_U(0.01))
	// Oscillator capacitor increased to counter higher frequency from
	// emulation speedups (reduced LM3900 gain, use of frontiers):
	CAP(C14, CAP_U(0.01122))
	CAP(C13, CAP_U(10))

	NET_C(R30.2, J4.1)
	NET_C(J4.2, J3_2.PLUS)
	NET_C(R29.2, J3_2.MINUS, C14.1)
	NET_C(J3_2.OUT, C14.2, R28.1, C13.1)
	NET_C(R28.2, J3_1.MINUS)
	NET_C(J3_1.OUT, R27.1, J4.13)
	NET_C(I_V5.Q, R26.1)
	NET_C(J3_1.PLUS, R26.2, R27.2)
	NET_C(D1.K, R23.2, C13.2, R25.1, MC3340_CONTROL)  // to MC3340 H2 pin 2

	// The MC3340 output is the complete engine sound which is sent to the
	// final mix.


	// The noise generator circuit for 280-ZZZAP and Laguna Racer is based
	// on a reverse-biased 9.1-volt 1N5239 Zener diode. 12-volt power is
	// passed through a 100-Kohm resistor and then through the diode to a
	// LM3900 Norton op-amp input, generating a noisy reference current
	// for the LM3900 of about 25 microamps. (The current drops about 2.5
	// volts through the resistor, 9 volts through the Zener, and half a
	// volt through the LM3900 input to ground, and the current is limited
	// by the resistor.) The op-amp then amplifies the noise in that
	// current to generate more intense noise for the other circuits.

	// The netlist library does not yet support Zener diodes or their
	// noise behavior, so I simulate it with this current source.

	// Super Speed Race generates its noise with a linear-feedback shift
	// register on the main motherboard, but it processes the noise signal
	// through similar circuits.

	CS(FC, 0)
	PARAM(FC.FUNC, "25e-6 + 1e-8 * rand()")
	// The op-amp appears to be set up to expect only a fraction of a
	// microamp of noise current, because much more than that will
	// saturate it. Random current of 1e-8 gives +/- 0.7 V centered
	// around 3 V.

	RES(RNOISE0, RES_K(100))
	CAP(CNOISE0, CAP_U(10))
	NET_C(CNOISE0.2, GND)

	NET_C(I_V12.Q, RNOISE0.1)
	NET_C(RNOISE0.2, CNOISE0.1, FC.P)

	LM3900(H4_2)

	RES(RNOISE1, RES_K(56))
	RES(RNOISE2, RES_K(47))
	RES(RNOISE3, RES_K(1))

	CAP(CNOISE, CAP_U(10))

	NET_C(CNOISE.1, RNOISE1.1, RNOISE2.1)
	NET_C(CNOISE.2, GND)
	NET_C(H4_2.MINUS, RNOISE1.2)
	NET_C(H4_2.PLUS, FC.N)
	NET_C(H4_2.OUT, RNOISE2.2, RNOISE3.1, C1.1)
	NET_C(RNOISE3.2, GND)

	// In Super Speed Race, which lacks the noise generator described
	// above, the noise signal enters at the point leading into capacitor
	// C1.

	CAP(C1, CAP_U(10))

	NET_C(C1.2, R1.1)

	// The noise generator is followed by a single-amplifier active
	// low-pass filter with a corner frequency of about 6.3 kHz, a very
	// broad Q of 0.014, and a gain of about 0.8. This filter basically
	// attenuates the noise's highest frequencies.

	RES(R1, RES_K(330))  // 680 Kohm in Super Speed Race.

	LM3900(H4_1)

	CAP(C2, CAP_P(6800))
	RES(R2, RES_K(10))
	RES(R3, RES_K(820))
	RES(R4, RES_K(270))
	CAP(C3, CAP_P(220))

	NET_C(R1.2, C2.1, R2.1, R4.1)
	NET_C(C2.2, GND)
	NET_C(H4_1.MINUS, R2.2, C3.1)
	NET_C(I_V5.Q, R3.1)
	NET_C(H4_1.PLUS, R3.2)
	NET_C(H4_1.OUT, C3.2, R4.2, R5.1, R17.1, C5.1, C4.1)

	// The filtered noise is passed to three different circuits, each of
	// which is also an active-filter type.

	// First noise circuit: NOISE CR 1

	// This is a two-amplifier active bandpass filter with a center
	// frequency of about 1 kHz and a high Q value of 25, giving a
	// narrow bandwidth of 40 Hz. The gain is about 15.

	// The result is a high-pitched "tire skid" screeching sound.

	// The circuit appears to be taken almost verbatim from page 19 of
	// National Semiconductor's Application Note 72 about the LM3900, with
	// only minor changes in the values of a few components to alter the
	// DC bias.

	CD4016_DIP(G4)
	NET_C(G4.7, GND)
	NET_C(G4.14, I_V5.Q)
	NET_C(GND, G4.10, G4.11, G4.12)

	LM3900(H4_3)

	RES(R5, RES_K(39))
	RES(R6, RES_R(62))
	RES(R7, RES_K(82))
	RES(R8, RES_K(39))

	CAP(C7, CAP_U(0.1))
	CAP(C8, CAP_U(0.1))

	NET_C(R5.2, R6.1, C7.1, C8.1, R12.1)
	NET_C(R6.2, GND)
	NET_C(H4_3.MINUS, C7.2, R8.1)
	NET_C(I_V5.Q, R7.1)
	NET_C(H4_3.PLUS, R7.2)
	NET_C(H4_3.OUT, R8.2, C8.2, R9.1)

	// Super Speed Race has an extra CD4016 switch (with the same control
	// line as the one downstream from here) and a 0.1 uF capacitor
	// between H4_3.OUT and R9.1 here.

	LM3900(H4_4)

	RES(R9, RES_K(39))
	RES(R10, RES_K(62))  // 240 Kohm in Super Speed Race.
	RES(R11, RES_K(100))  // 120 Kohm in later Laguna and SS Race
	RES(R12, RES_K(62))

	NET_C(H4_4.MINUS, R9.2, R11.1)
	NET_C(I_V5.Q, R10.1)
	NET_C(H4_4.PLUS, R10.2)
	NET_C(H4_4.OUT, R11.2, R12.2, G4.4)
	NET_C(G4.3, R63.1)  // NOISE CR 1
	NET_C(G4.5, I_F4_7.Q)

	// Second noise circuit: NOISE CR 2

	// This circuit is peculiar. It's structured like a single-amplifier
	// active low-pass filter, with a corner frequency of about 1 kHz and
	// a gain of 100--but its Q factor turns out to be a small *negative*
	// number. (I'm not sure what effect this has on a filter, but it
	// might indicate instability.)

	// The result is saturated, clipped noise, a bit like randomized
	// square waves, with frequencies mainly below 1 kHz.

	// I don't why the circuit was designed this way, or whether it was
	// deliberate or a design or production error which the makers decided
	// they liked or at least could accept. It doesn't look like they
	// fixed it later; this same circuit is unchanged in the schematics
	// for all three games.

	RES(R17, RES_K(10))

	CAP(C5, CAP_U(10))
	CAP(C4, CAP_U(0.022))

	LM3900(H5_2)

	RES(R16, RES_K(1.5))
	RES(R15, RES_K(15))
	RES(R14, RES_M(2.7))
	RES(R13, RES_K(150))

	CAP(C6, CAP_U(0.01))
	CAP(C9, CAP_U(0.001))

	NET_C(C4.2, R16.1)
	NET_C(R16.2, C6.1, R15.1, R13.1)
	NET_C(C6.2, GND)
	NET_C(H5_2.MINUS, R15.2, C9.1)
	NET_C(I_V5.Q, R14.1)
	NET_C(H5_2.PLUS, R14.2)
	NET_C(H5_2.OUT, C9.2, R13.2, G4.8)
	NET_C(G4.9, R64.1)  // NOISE CR 2
	NET_C(G4.6, I_F4_10.Q)

	// Third noise circuit: BOOM

	// This is a single-amplifier active bandpass filter with a center
	// frequency of about 60 Hz and a high Q value of about 19, giving a
	// narrow 3 Hz bandwidth. The gain is also very high, a little over
	// 200.

	// The filter is normally cut off from the noise signal, and thus it
	// remains quiet. When the BOOM signal is activated, CD4016 switch
	// G4_A opens, letting in the noise to be filtered and amplified until
	// the switch is cut off again, generating a loud sort of "boom".
	// (The sound doesn't have much decay, though; it gets cut abruptly.)

	LM3900(H5_1)

	RES(R18, RES_K(2.2))  // 20 Kohm in Super Speed Race.
	RES(R19, RES_K(1))
	RES(R20, RES_M(3.3))
	RES(R21, RES_M(1))  // 1.5 Mohm in Super Speed Race.

	CAP(C10, CAP_U(0.1))
	CAP(C11, CAP_U(0.1))

	NET_C(R17.2, C5.2, G4.1)
	NET_C(G4.2, R18.1)
	NET_C(I_F4_2.Q, G4.13)
	NET_C(R18.2, R19.1, C10.1, C11.1)
	NET_C(R19.2, GND)
	NET_C(H5_1.MINUS, C10.2, R21.1)
	NET_C(I_V5.Q, R20.1)
	NET_C(H5_1.PLUS, R20.2)
	NET_C(H5_1.OUT, R21.2, C11.2, R65.1)  // BOOM

	// Final mix and amplification:

	RES(R63, RES_K(12))  // 3 Kohm in Super Speed Race.
	RES(R64, RES_K(150))
	RES(R65, RES_K(12))
	RES(R66, RES_K(33))

	CAP(C20, CAP_U(10))
	CAP(C21, CAP_U(10))

	NET_C(R63.2, R64.2, R65.2, C20.1)
	NET_C(MC3340_OUTPUT, R66.1)
	NET_C(R66.2, C21.1)

	LM3900(J5_3)
	LM3900(J5_4)

	RES(R67, RES_K(2))
	CAP(C22, CAP_U(10))
	RES(R68, RES_K(220))
	RES(R74, RES_K(220))

	NET_C(I_V5.Q, R67.1)
	NET_C(R67.2, C22.1, R68.1, R74.1)
	NET_C(C22.2, GND)
	NET_C(J5_3.PLUS, R68.2)
	NET_C(J5_4.PLUS, R74.2)

	RES(R69, RES_K(100))
	RES(R70, RES_K(10))  // actually a potentiometer, at max. volume
	CAP(C23, CAP_U(10))
	CAP(C24, CAP_U(0.1))

	NET_C(R70.2, C23.2)
	NET_C(J5_3.MINUS, C20.2, C21.2, R69.1, R70.1)
	NET_C(J5_3.OUT, C23.1, R69.2, C24.1)

	RES(R73, RES_K(100))
	RES(R75, RES_K(100))

	NET_C(C24.2, R73.1)
	NET_C(J5_4.MINUS, R73.2, R75.1)
	NET_C(J5_4.OUT, R75.2)

	ALIAS(OUTPUT, J5_3.OUT)
//	LOG(LOG_OUTPUT, OUTPUT)

NETLIST_END()


static NETLIST_START(LM3900_lowgain)
	OPAMP(A, "OPAMP(TYPE=3 VLH=0.5 VLL=0.03 FPF=2k UGF=2.5M SLEW=1M RI=10M RO=100 DAB=0.0015)")

	DIODE(D1, "D(IS=6e-15 N=1)")
	DIODE(D2, "D(IS=6e-15 N=1)")
	CCCS(CS1, 1) // Current Mirror

	ALIAS(VCC, A.VCC)
	ALIAS(GND, A.GND)
	ALIAS(OUT, A.OUT)

	ALIAS(PLUS, CS1.IP)
	NET_C(D1.A, CS1.IN)
	NET_C(A.GND, D1.K)

	CS(CS_BIAS, 10e-6)
	NET_C(A.VCC, CS_BIAS.P)

	ALIAS(MINUS, CS1.OP)
	NET_C(CS1.ON, A.GND)

	CCVS(VS1, 1000) // current-to-voltage gain
	// ^^ any greater is numerically unstable with static timestepping at
	// 48 kHz
//	CCVS(VS1, 10000) // current-to-voltage gain
	// ^^ any greater is numerically unstable with default dynamic
	// timestepping at 48 kHz
//	CCVS(VS1, 200000) // current-to-voltage gain
	NET_C(CS1.OP, VS1.IP)
	NET_C(VS1.IN, CS_BIAS.N, D2.A)
	NET_C(D2.K, A.GND)
	NET_C(VS1.OP, A.MINUS)
	NET_C(VS1.ON, A.PLUS, A.GND)
NETLIST_END()


NETLIST_START(zzzap)

	SOLVER(Solver, 48000)
	PARAM(Solver.RELTOL, 1e-2)  // default 1e-3  (faster, but costs quality)
	PARAM(Solver.VNTOL, 5e-3)  // default 1e-7  (faster, but costs quality)
	PARAM(Solver.ACCURACY, 1e-3)  // default 1e-7
//	PARAM(Solver.DYNAMIC_TS, 1)
//	PARAM(Solver.DYNAMIC_LTE, 1e-4)  // default 1e-5
//	PARAM(Solver.DYNAMIC_MIN_TIMESTEP, 1e-8)  // default 1e-6

	ANALOG_INPUT(I_V12, 12)
	ANALOG_INPUT(I_V5, 5)

	LOCAL_SOURCE(mc3340)
	INCLUDE(mc3340)

	// The MC3340 gets 12-volt power in 280-ZZZAP and Laguna Racer.
	// In Super Speed Race it gets 5-volt power.
	NET_C(I_V12.Q, MC3340_VCC)

	LOCAL_LIB_ENTRY(LM3900_lowgain)

	LOCAL_SOURCE(zzzap_schematics)
	INCLUDE(zzzap_schematics)

	LOGIC_INPUT(I_F5_2, 0, "74XX")  // PEDAL_BIT0
	LOGIC_INPUT(I_F5_5, 0, "74XX")  // PEDAL_BIT1
	LOGIC_INPUT(I_F5_7, 0, "74XX")  // PEDAL_BIT2
	LOGIC_INPUT(I_F5_10, 0, "74XX")  // PEDAL_BIT3
	LOGIC_INPUT(I_F4_5, 0, "74XX")  // ENGINE SOUND OFF
	LOGIC_INPUT(I_F5_12, 0, "74XX")  // HI SHIFT
	LOGIC_INPUT(I_F5_15, 0, "74XX")  // LO SHIFT
					// both shifts off when engine off

	ALIAS(I_PEDAL_BIT0, I_F5_2.IN)
	ALIAS(I_PEDAL_BIT1, I_F5_5.IN)
	ALIAS(I_PEDAL_BIT2, I_F5_7.IN)
	ALIAS(I_PEDAL_BIT3, I_F5_10.IN)
	ALIAS(I_ENGINE_SOUND_OFF, I_F4_5.IN)
	ALIAS(I_HI_SHIFT, I_F5_12.IN)
	ALIAS(I_LO_SHIFT, I_F5_15.IN)

	// Although the schematics don't show the LM3900s' power input,
	// they seem to need 5-volt power to get the proper results.
	NET_C(I_V5.Q, H5_3.VCC, H5_4.VCC, J5_2.VCC, J5_1.VCC,
	      J3_3.VCC, J3_4.VCC, J3_2.VCC, J3_1.VCC)
	NET_C(GND, H5_3.GND, H5_4.GND, J5_2.GND, J5_1.GND,
	      J3_3.GND, J3_4.GND, J3_2.GND, J3_1.GND)

	NET_C(I_V5.Q, I_F5_2.VCC, I_F5_5.VCC, I_F5_7.VCC, I_F5_10.VCC)
	NET_C(GND, I_F5_2.GND, I_F5_5.GND, I_F5_7.GND, I_F5_10.GND)

	NET_C(I_V5.Q, I_F4_5.VCC, I_F5_12.VCC, I_F5_15.VCC)
	NET_C(GND, I_F4_5.GND, I_F5_12.GND, I_F5_15.GND)

	LOGIC_INPUT(I_F4_2, 0, "74XX")  // BOOM
	LOGIC_INPUT(I_F4_7, 0, "74XX")  // NOISE CR 1
	LOGIC_INPUT(I_F4_10, 0, "74XX")  // NOISE CR 2

	ALIAS(I_BOOM, I_F4_2.IN)
	ALIAS(I_NOISE_CR_1, I_F4_7.IN)
	ALIAS(I_NOISE_CR_2, I_F4_10.IN)

	NET_C(I_V5.Q, H4_2.VCC, H4_1.VCC, H4_3.VCC, H5_2.VCC,
		H5_1.VCC, H4_4.VCC, J5_3.VCC, J5_4.VCC)

	NET_C(GND, H4_2.GND, H4_1.GND, H4_3.GND, H5_2.GND,
		H5_1.GND, H4_4.GND, J5_3.GND, J5_4.GND)

	NET_C(I_V5.Q, I_F4_2.VCC, I_F4_7.VCC, I_F4_10.VCC)
	NET_C(GND, I_F4_2.GND, I_F4_7.GND, I_F4_10.GND)

	// Cut after output of noise generator. Seems to work.
	OPTIMIZE_FRONTIER(C1.1, RES_M(1), 50)

	// Cut of skid screech generator. Seem to work.
	OPTIMIZE_FRONTIER(R5.1, RES_K(39), 50)

// for some reason this cut seems to cause sudden voltage jumps on skids
//	OPTIMIZE_FRONTIER(R63.1, RES_K(12), 50)

	// Cuts after boom and NOISE CR 2 generators. Seem to work.
	OPTIMIZE_FRONTIER(R64.1, RES_K(150), 50)
	OPTIMIZE_FRONTIER(R65.1, RES_K(12), 50)

	// Cut after engine sound generation. Seems to work, but may need
	// further checking.
	OPTIMIZE_FRONTIER(R66.1, RES_K(33), 50)

	// Cuts before MC3340 inputs. Seem to work, though may need further
	// checking.
	OPTIMIZE_FRONTIER(C16.1, RES_M(1), 50)
	OPTIMIZE_FRONTIER(C13.1, RES_M(1), 50)

	// Cuts before engine sound op-amp oscillators. Seem to work, though
	// may need further checking.
	OPTIMIZE_FRONTIER(R36.1, RES_K(560), 50)
	OPTIMIZE_FRONTIER(R37.1, RES_K(270), 50)
	OPTIMIZE_FRONTIER(R31.1, RES_K(300), 50)
	OPTIMIZE_FRONTIER(R32.1, RES_K(150), 50)
	OPTIMIZE_FRONTIER(R29.1, RES_K(220), 50)
	OPTIMIZE_FRONTIER(R30.1, RES_K(110), 50)

	// Cuts within engine sound op-amp oscillators, to speed convergence
	// rather than to partition matrices. These require retuning the
	// oscillators to keep the proper frequencies.
	OPTIMIZE_FRONTIER(R38.1, RES_K(100), 50)
	OPTIMIZE_FRONTIER(R40.1, RES_K(270), 50)
	OPTIMIZE_FRONTIER(R33.1, RES_K(100), 50)
	OPTIMIZE_FRONTIER(R35.1, RES_K(270), 50)
	OPTIMIZE_FRONTIER(R28.1, RES_K(100), 50)
	OPTIMIZE_FRONTIER(R27.1, RES_K(270), 50)

NETLIST_END()

Last edited by Colin Howell; 05/14/20 12:37 AM. Reason: Forgot to rename my low-gain opamp variant.
Page 3 of 5 1 2 3 4 5

Who's Online Now
3 registered members (RomKnight, robcfg, 1 invisible), 68 guests, and 2 spiders.
Key: Admin, Global Mod, Mod
ShoutChat Box
Comment Guidelines: Do post respectful and insightful comments. Don't flame, hate, spam.
Forum Statistics
Forums9
Topics8,775
Posts115,464
Members4,899
Most Online890
Jan 17th, 2020
Powered by UBB.threads™ PHP Forum Software 7.7.3