Closed ashwinb-git closed 3 years ago
No clue what you are referring to. A code link would be nice.
I didn't use any other sources. I have to admit the code quality is trash, but this started as a small project which I decided was too interesting to not share.
Well, I was looking at your very first commit ('add placeholder files' )so that I can understand the algorithm much better and it helped. The part that I couldn't understand how you wrote your initial loop in' gen.rs'.
``for i in (0..get_length(&spec, duration)).map(|x| x as f64 / onesec) { let rpm = (i / 8.0).powf(0.9) * (rpmhi - rpmlo) + rpmlo;
let x = (get_phasor_freq(rpm) * i) % 1.0;
let mut sample = (exhaust_valve(x) * 1.0 + intake_valve(x) * 1.0 + piston_motion(x) * 0.5 + fuel_ignition(x) * 1.0) as f32;
sample = filter.filter(sample);
let (res, _) = resonance_chamber.step(sample, 0.0);
sample += res;
writer.write_sample((sample * amplitude) as i16).unwrap();
}
}
I understood that the phasor is the sum of all four functions, intake & exhaust valves, piston and fuel. But how did u figure out the number of iterations for the loop ? how to relate the rpm with this phasor equation? I think you rename this variable 'x' as 'piston_location' or something in your latest version. I would also like know how the variable 't' works in the fuel ignition equation. In your first commit you have set a constant called 'ignition scale = 0.1' which is the 't'. Is there a particular reason for selecting this value?
Seems like x in this case is the crankshaft position with the unit "revolutions". Especially in the first commit you can assume I used many fudge values like 0.1 which were just for testing.
yeah, I understand. So for each rpm we just figure out where the crankshaft is and get the corresponding sample right? but i was wondering, for a 4 stroke engine, the intake is active during the first revolution and the exhaust valve during the next. Did u take this into consideration while programming?
The exhaust_valve and intake_valve functions reflect this.
yeah, got it! And now the piston and ignition sound is sent through the cylinder and lp filtered right? cylinder is represented by the waveguide. are waveguides modelled as stack/queues with samples delayed as they are popped out?
A cylinder is an instantaneous emitter of sample amplitudes. Only its inputs and outputs have waveguides. The piston's inptu and output from/to those is modulated by the valve functions. LP (Low-pass) filtering is applied to the crankshaft noise and intake noise. Waveguides are modelled by bidirectional delay lines. The output of one delay line is split into 1. the input of the delay line going the opposite way and 2. the output of the waveguide. This splitting factor is sometimes called alpha.
The paper says "Sound generation starts in the waveguides representing the cylinders". So, shouldn't the cylinder be a waveguide as well? I understand that the piston and fuel sound is the input to the cylinder. And when the intake valve is open, that sound is modulated by the intake valve function sent to the corresponding waveguide. Same goes for the exhaust side as well. According to the paper, when the valves are closed, the energy is fed back to the delay lines. So when both valves are closed, what happens to the sound sample generated in the cylinder?
So when both valves are closed, what happens to the sound sample generated in the cylinder?
It is discarded.
Thanks! Interesting. arent the piston and fuel sound themselves one of the three sound components/outputs? And with the waveguides, I understand that you are using vector arrays to delay each sample. Or how do you delay them?
arent the piston and fuel sound themselves one of the three sound components/outputs?
No, exhaust and intake outpus come from waveguides connected to pistons. Only the engine vibrations output is directly LP-filtered piston noise.
I understand that you are using vector arrays to delay each sample.
Ring buffers, yes (I called them loop buffers at the time)
Thanks! It helped me a lot in designing the intake side. Now for the exhaust side, the samples modulated by the exhaust valve function, go to the straight pipe which is a wave guide right? and then the muffler elements which are also waveguides I think. But I couldn't understand how they are structured.
I couldn't explain it better than Figure 5 on page 4 of the linked paper in the readme.
I understand that the exhaust samples modulated by the ex_valve are sent as inputs to the straight pipe (which is a waveguide). The output from the pipe is sent to all 4 muffler elements and the muffler elements are also 4 waveguides each with a fixed delay right? how did you fix the delay of each muffler element?
Your rhetoric questions are correct. The muffler delays are user settings.
Great! Then all these muffler outputs are added to produce the exhaust sound right? And also how do u set the length of the loop buffers i.e delays for the waveguides in general?
I assume constant speed of sound in all wave guides regardless of pressure and use the speed of sound of air at sea level to mimic the time it takes for a wave to travel a certain distance.
That's a great idea! And I got the way you calculate the number of samples to delay from the code. I have designed the intake side with only one cylinder as of now. Do you play the sound by each sample or do you get all the samples and play it together? (I am using matlab's sound function). I also wanted to know how you control the loop for sound generation?
As with every typical DSP program, sound is processed in batches. The "loop" runs at a constant sample rate.
Alright. I designed one cylinder. And for more cylinders how did you calculate the phase shift of each one?
edit- I designed the entire thing. Thank you so much for your help!
Please understand I am not keen on providing a walkthrough on how to program a generator. Looking at a real engine's crank will give you a good visual answer.
Hey!
Your implementation is really impressive! I was reading the paper and I am trying to implement my own version in Matlab/c++. I was going through your initial commit and had trouble understanding how you established the relation between the variable x and the rpm. So I wanted to ask if you used any other sources besides the paper to write the code ? I am new to rust so its difficult to understand the flow.