Re: Netlist: 280ZZZAP sound problems
[Re: Colin Howell]
#117294
05/01/20 07:50 PM

Joined: Feb 2007
Posts: 498
couriersud
Senior Member

Senior Member
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 BE 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: 280ZZZAP sound problems
[Re: couriersud]
#117295
05/01/20 09:02 PM

Joined: Jun 2003
Posts: 48
Colin Howell
OP
Member

OP
Member
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 noisebased 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 32bit LFSR or some other implementation with a 32bit 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: 280ZZZAP sound problems
[Re: Colin Howell]
#117296
05/01/20 09:53 PM

Joined: Feb 2007
Posts: 498
couriersud
Senior Member

Senior Member
Joined: Feb 2007
Posts: 498 
It shouldn't be any slower on modern hardware to have a 32bit LFSR or some other implementation with a 32bit period, should it? No issue, even 64bit will work. 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: 280ZZZAP sound problems
[Re: Colin Howell]
#117297
05/02/20 06:48 AM

Joined: Feb 2004
Posts: 2,145
Vas Crabb
Very Senior Member

Very Senior Member
Joined: Feb 2004
Posts: 2,145 
You can use the C++11 standard library's pseudorandom number generation module. The Mersenne twister has a very long period and will always give the same output given the same entropy.



Re: Netlist: 280ZZZAP sound problems
[Re: Colin Howell]
#117298
05/02/20 08:04 AM

Joined: Feb 2007
Posts: 498
couriersud
Senior Member

Senior Member
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: 280ZZZAP sound problems
[Re: Colin Howell]
#117299
05/02/20 08:28 PM

Joined: Sep 2004
Posts: 387
AaronGiles
Senior Member

Senior Member
Joined: Sep 2004
Posts: 387 
Something like TinyMT might make sense here. He has a 32bit and 64bit 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/MersenneTwisterLab/TinyMT



Re: Netlist: 280ZZZAP sound problems
[Re: Colin Howell]
#117302
05/03/20 12:24 AM

Joined: Feb 2007
Posts: 498
couriersud
Senior Member

Senior Member
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: 280ZZZAP sound problems
[Re: couriersud]
#117303
05/03/20 01:45 AM

Joined: Sep 2004
Posts: 387
AaronGiles
Senior Member

Senior Member
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 16bit LFSR) so that they could be selectable at compile time for whatever needs. Thought that might be handy.



Re: Netlist: 280ZZZAP sound problems
[Re: Colin Howell]
#117308
05/03/20 03:26 PM

Joined: Feb 2007
Posts: 498
couriersud
Senior Member

Senior Member
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:
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: 280ZZZAP sound problems
[Re: Colin Howell]
#117326
05/13/20 11:59 PM

Joined: Jun 2003
Posts: 48
Colin Howell
OP
Member

OP
Member
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 140145% 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 lowimpact 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 voltagecontrolled 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 shamMC3340 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. // license:CC0
// copyrightholders: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 voltagecontrolled attenuator/amplifier. It
// can produce a small amount of positive gain (about 1213 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. 967). 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. 5130).
// 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 Europeanstyle 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 ICbased devices.
// Incidentally, the MC3340 has the same circuit internally as an
// older Motorola device, the MFC6040, which was replaced by the
// MC3340 in the mid1970s. 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 4bit accelerator pedal input is converted to an analog voltage
// by the first LM3900 opamp H5_3, whose output is passed to the
// second opamp 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 5volt 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 trianglewave oscillators whose frequency
// is controlled by the voltage signal output from LM3900 opamp H5_4.
// Each oscillator is a cascaded pair of LM3900s and a CD4016 switch.
// The switch feeds into the nonfeedback input of the first opamp,
// whose output is also the final oscillator output; the second opamp
// acts as a Schmitt trigger on the first opamp's output, generating
// a square wave that controls the switch. Two of the oscillators are
// combined to drive the signal input of an MC3340 voltagecontrolled
// 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 amplitudemodulate 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 280ZZZAP 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 amplitudemodulation 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 280ZZZAP and Laguna Racer is based
// on a reversebiased 9.1volt 1N5239 Zener diode. 12volt power is
// passed through a 100Kohm resistor and then through the diode to a
// LM3900 Norton opamp 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 opamp 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 linearfeedback shift
// register on the main motherboard, but it processes the noise signal
// through similar circuits.
CS(FC, 0)
PARAM(FC.FUNC, "25e6 + 1e8 * rand()")
// The opamp 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 1e8 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 singleamplifier active
// lowpass 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 activefilter type.
// First noise circuit: NOISE CR 1
// This is a twoamplifier 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 highpitched "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 singleamplifier
// active lowpass filter, with a corner frequency of about 1 kHz and
// a gain of 100but 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 singleamplifier 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=6e15 N=1)")
DIODE(D2, "D(IS=6e15 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, 10e6)
NET_C(A.VCC, CS_BIAS.P)
ALIAS(MINUS, CS1.OP)
NET_C(CS1.ON, A.GND)
CCVS(VS1, 1000) // currenttovoltage gain
// ^^ any greater is numerically unstable with static timestepping at
// 48 kHz
// CCVS(VS1, 10000) // currenttovoltage gain
// ^^ any greater is numerically unstable with default dynamic
// timestepping at 48 kHz
// CCVS(VS1, 200000) // currenttovoltage 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, 1e2) // default 1e3 (faster, but costs quality)
PARAM(Solver.VNTOL, 5e3) // default 1e7 (faster, but costs quality)
PARAM(Solver.ACCURACY, 1e3) // default 1e7
// PARAM(Solver.DYNAMIC_TS, 1)
// PARAM(Solver.DYNAMIC_LTE, 1e4) // default 1e5
// PARAM(Solver.DYNAMIC_MIN_TIMESTEP, 1e8) // default 1e6
ANALOG_INPUT(I_V12, 12)
ANALOG_INPUT(I_V5, 5)
LOCAL_SOURCE(mc3340)
INCLUDE(mc3340)
// The MC3340 gets 12volt power in 280ZZZAP and Laguna Racer.
// In Super Speed Race it gets 5volt 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 5volt 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 opamp 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 opamp 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 lowgain opamp variant.




3 registered members (RomKnight, robcfg, 1 invisible),
68
guests, and 2
spiders. 
Key:
Admin,
Global Mod,
Mod


Forums9
Topics8,775
Posts115,464
Members4,899

Most Online890 Jan 17th, 2020


