C# Nwaves "DiscreteSignal1 + DiscreteSignal2" superimposing operation results a giant peak from 0 Hz up to 17k+ Hz in the middle - signal-processing

I have two signals (out of wav files), both are mono wav files of 37500 Hz sample rate.
File 1 is output.wav:
File 2 is saved_mono.wav:
I apply superimposing ("+") operation for the two Discrete signals:
// shiftedSignal is output.wav
// outSignal is saved_mono.wav
//This is how I read it:
WaveFile shiftedWav;
using (var stream = new FileStream("output.wav", FileMode.Open))
{
shiftedWav = new WaveFile(stream);
}
DiscreteSignal shiftedSignal = shiftedWav[Channels.Left];
DiscreteSignal mergedSignal = shiftedSignal + outSignal;
waveFileOut = new WaveFile(mergedSignal);
using (var stream = new FileStream("merged.wav", FileMode.Create))
{
waveFileOut.SaveTo(stream);
}
As the result, I have merged.wav file and it has a giant peak in the middle:
Both input wav files have the same sample rate of 37500 and the same bitrate of 600 kbps.
Where did it come from and how do I fix it?
Just to make sure, I tried to concatenate these signals:
DiscreteSignal mergedSignal = shiftedSignal.Concatenate(outSignal);
And it comes out OK:

Related

Bandwidth Speed Test Slower Than Expected

Im trying to create a bandwidth test using Dart using a LibreSpeed server, but for some reason it's reporting a much slower speed than expected. When I test using the web client for LibreSpeed I get around 30mb/s download bandwidth, however with my Dart program I'm only getting around 4mb/s.
The code for the speed test is as follows:
Future<void> start() async {
var rand = Random();
var req = await client.getUrl(Uri.http(_serverAddress, '/garbage.php',
{'r': rand.nextDouble().toString(), 'ckSize': '20'}));
var resp = await req.close();
var bytesDownloaded = 0;
var start = DateTime.now();
await for (var bytes in resp) {
bytesDownloaded += bytes.length;
}
var timeTaken = DateTime.now().difference(start).inSeconds;
var mbsDownloaded = bytesDownloaded / 1000000;
print(
'$mbsDownloaded megabytes downloaded in $timeTaken seconds at a rate of ${mbsDownloaded / timeTaken} mbs per second');
}
I think I'm probably not understanding a crucial reason as to why it appears to be so slow compared to the web client. Can anyone give me any ideas as to what the bottleneck might be?
The problem is confusion between the use of units when measure internet speed. In general terms there are two ways we can measure the speed:
Mbps (MegaBit Per Second)
MB/s (MegaByte per second)
To understand your problem we need to notice that 1 byte = 8 bits. Also, that the unit LibreSpeed (and most internet providers) uses is Mbps.
The unit your current program are measuring in is MB/s since you are using the length of the list (each element of the list is 1 byte = 8 bit:
await for (var bytes in resp) {
bytesDownloaded += bytes.length;
}
And never multiply that number by 8 later in your code. You are then comparing this number against the number from LibreSpeed which uses Mbps (same as most internet providers) which means your number is 8 times smaller that expected.

Is there any way to save mulaw audio stream from twilio in a file

I am using Twilio voice stream feature and i don't want to use Twilio record functionality. When Twilio starts sending voice stream to my server i want to store it into disk as an audio file in realtime.
I was running into the same issue today and figured a way to generate a WAVE Header for the mu-law header:
If you're following Twilio's blog post, that's the code I ended implementing:
wss.on('connection', (socket) => {
socket.on('message', (msg) => {
const { event, ...message } = JSON.parse(msg);
switch (event) {
case 'start':
let streamSid = message.start.streamSid;
socket.wstream = fs.createWriteStream(__dirname + `/${Date.now()}.wav`, { encoding: 'binary' });
// This is a mu-law header for a WAV-file compatible with twilio format
socket.wstream.write(Buffer.from([
0x52,0x49,0x46,0x46,0x62,0xb8,0x00,0x00,0x57,0x41,0x56,0x45,0x66,0x6d,0x74,0x20,
0x12,0x00,0x00,0x00,0x07,0x00,0x01,0x00,0x40,0x1f,0x00,0x00,0x80,0x3e,0x00,0x00,
0x02,0x00,0x04,0x00,0x00,0x00,0x66,0x61,0x63,0x74,0x04,0x00,0x00,0x00,0xc5,0x5b,
0x00,0x00,0x64,0x61,0x74,0x61,0x00,0x00,0x00,0x00, // Those last 4 bytes are the data length
]));
break;
case 'media':
// decode the base64-encoded data and write to stream
socket.wstream.write(Buffer.from(message.media.payload, 'base64'));
break;
case 'stop':
// Now the only thing missing is to write the number of data bytes in the header
socket.wstream.write("", () => {
let fd = fs.openSync(socket.wstream.path, 'r+'); // `r+` mode is needed in order to write to arbitrary position
let count = socket.wstream.bytesWritten;
count -= 58; // The header itself is 58 bytes long and we only want the data byte length
console.log(count)
fs.writeSync(
fd,
Buffer.from([
count % 256,
(count >> 8) % 256,
(count >> 16) % 256,
(count >> 24) % 256,
]),
0,
4, // Write 4 bytes
54, // starts writing at byte 54 in the file
);
});
break;
}
});
});
You can use FFmpeg to convert the Twilio mulaw to a regular WAV file.
If you use the class below, then you will just need to send the Twilio stream buffers when they arrive.
Something like:
recording = StreamAudioRecording(tempDirectory)
recording.start_recording(call_id)
<loop over buffer packets arriving>
recording.write_buffer(buffer)
recording_audio_path = recording.stop_recording()
This is the class implementation
import os
RAW_AUDIO_FILE_EXTENSION = "ulaw"
CONVERTED_AUDIO_FILE_EXTENSION = "wav"
class StreamAudioRecording:
def __init__(self, audio_recording_path):
self.audio_recording_path = audio_recording_path
self.f = None
self.audio_file_path = None
def start_recording(self, call_id):
self.audio_file_path = os.path.join(self.audio_recording_path, f" .
{call_id}.{RAW_AUDIO_FILE_EXTENSION}")
self.f = open(self.audio_file_path, 'wb')
def write_buffer(self, buffer):
self.f.write(buffer)
def stop_recording(self):
self.f.close()
converted_audio_path =
self.audio_file_path.replace(RAW_AUDIO_FILE_EXTENSION,
CONVERTED_AUDIO_FILE_EXTENSION)
self.convert_call_recording(self.audio_file_path, converted_audio_path)
return converted_audio_path
#staticmethod
def convert_call_recording(mulaw_path, wav_path):
command = f"ffmpeg -y -loglevel panic -f mulaw -ar 8k -ac 1 -i {mulaw_path} {wav_path}"
os.system(command)
If your using Node.js, the solution that #tdeo provided works great. I was inspired and I made a simple library using this solution. It's available now on npm.
https://www.npmjs.com/package/twilio-media-stream-save-audio-file

Emgucv cannot train more than 210 images using EigenFaceRecognizer it stop writing new details or data

Good day everyone I am relatively new to OpenCV using .net wrapper Emgucv my program is simple face detection and recognition, first I train user faces, at least 20 images of 100x100pixel per user and write (EigenFaceRecognizer) the data to yml files, then load this files(user images and data in yml) before running real time recognition or comparing, it worked perfectly fine with 9 user (9x20 = 180 images). However when i try to register or train another user I notice the (EigenFaceRecognizer) stop writing the data in yml. How do we solve this? The format of my data with yml extension below
opencv_eigenfaces:
threshold: .Inf
num_components: 10
mean: !!opencv-matrix
rows: 1
cols: 4096
dt: d
data: []
The trainingData.yml https://www.dropbox.com/s/itm58o24lka9wa3/trainingData.yml?dl=0
I figure it out the problem is just not enough time in writing the data so I need to increase the delay.
private async Task LoadData()
{
outputBox.Clear();
var i = 0;
var itemData = Directory.EnumerateFiles("trainingset/", "*.bmp");
var enumerable = itemData as IList<string> ?? itemData.ToList();
var total = enumerable.Count();
_arrayNumber = new int[total];
var listMat = new List<Mat>();
foreach (var file in enumerable)
{
var inputImg = Image.FromFile(file);
_inputEmGuImage = new Image<Bgr, byte>(new Bitmap(inputImg));
var imgGray = _inputEmGuImage.Convert<Gray, byte>();
listMat.Add(imgGray.Mat);
var number = file.Split('/')[1].ToString().Split('_')[0];
if (number != "")
{
_arrayNumber[i] = int.Parse(number);
}
i++;
processImg.Image = _inputEmGuImage.ToBitmap();
outputBox.AppendText($"Person Id: {number} {Environment.NewLine}");
if (total == i)
{
fisherFaceRecognizer.Train(listMat.ToArray(), _arrayNumber);
fisherFaceRecognizer.Write(YlmPath);
// FaceRecognition.Train(listMat.ToArray(), _arrayNumber);
// FaceRecognition.Write(YlmPath);
MessageBox.Show(#"Total of " + _arrayNumber.Length + #" successfully loaded");
}
await Task.Delay(10);
}
}

Zebra Printer - Not Printing PNG Stream *Provided my own answer*

I think I'm very close to getting this to print. However it still isn't. There is no exception thrown and it does seem to be hitting the zebra printer, but nothing. Its a long shot as I think most people are in the same position I am and know little about it. Any help anyone can give no matter how small will be welcomed, I'm losing the will to live
using (var response = request.GetResponse())
{
using (var responseStream = response.GetResponseStream())
{
using (var stream = new MemoryStream())
{
if (responseStream == null)
{
return;
}
responseStream.CopyTo(stream);
stream.Position = 0;
using (var zipout = ZipFile.Read(stream))
{
using (var ms = new MemoryStream())
{
foreach (var e in zipout.Where(e => e.FileName.Contains(".png")))
{
e.Extract(ms);
}
if (ms.Length <= 0)
{
return;
}
var binaryData = ms.ToArray();
byte[] compressedFileData;
// Compress the data using the LZ77 algorithm.
using (var outStream = new MemoryStream())
{
using (var compress = new DeflateStream(outStream, CompressionMode.Compress, true))
{
compress.Write(binaryData, 0, binaryData.Length);
compress.Flush();
compress.Close();
}
compressedFileData = outStream.ToArray();
}
// Encode the compressed data using the MIME Base64 algorithm.
var base64 = Convert.ToBase64String(compressedFileData);
// Calculate a CRC across the encoded data.
var crc = Calc(Convert.FromBase64String(base64));
// Add a unique header to differentiate the new format from the existing ASCII hexadecimal encoding.
var finalData = string.Format(":Z64:{0}:{1}", base64, crc);
var zplToSend = "~DYR:LOGO,P,P," + finalData.Length + ",," + finalData;
const string PrintImage = "^XA^FO0,0^IMR:LOGO.PNG^FS^XZ";
try
{
var client = new System.Net.Sockets.TcpClient();
client.Connect(IpAddress, Port);
var writer = new StreamWriter(client.GetStream(), Encoding.UTF8);
writer.Write(zplToSend);
writer.Flush();
writer.Write(PrintImage);
writer.Close();
client.Close();
}
catch (Exception ex)
{
// Catch Exception
}
}
}
}
}
}
private static ushort Calc(byte[] data)
{
ushort wCrc = 0;
for (var i = 0; i < data.Length; i++)
{
wCrc ^= (ushort)(data[i] << 8);
for (var j = 0; j < 8; j++)
{
if ((wCrc & 0x8000) != 0)
{
wCrc = (ushort)((wCrc << 1) ^ 0x1021);
}
else
{
wCrc <<= 1;
}
}
}
return wCrc;
}
The following code is working for me. The issue was the commands, these are very very important! Overview of the command I have used below, more can be found here
PrintImage
^XA
Start Format Description The ^XA command is used at the beginning of ZPL II code. It is the opening bracket and indicates the start of a new label format. This command is substituted with a single ASCII control character STX (control-B, hexadecimal 02). Format ^XA Comments Valid ZPL II format requires that label formats should start with the ^XA command and end with the ^XZ command.
^FO
Field Origin Description The ^FO command sets a field origin, relative to the label home (^LH) position. ^FO sets the upper-left corner of the field area by defining points along the x-axis and y-axis independent of the rotation. Format ^FOx,y,z
x = x-axis location (in dots) Accepted Values: 0 to 32000 Default
Value: 0
y = y-axis location (in dots) Accepted Values: 0 to 32000
Default Value: 0
z = justification The z parameter is only
supported in firmware versions V60.14.x, V50.14.x, or later. Accepted
Values: 0 = left justification 1 = right justification 2 = auto
justification (script dependent) Default Value: last accepted ^FW
value or ^FW default
^IM
Image Move Description The ^IM command performs a direct move of an image from storage area into the bitmap. The command is identical to the ^XG command (Recall Graphic), except there are no sizing parameters. Format ^IMd:o.x
d = location of stored object Accepted Values: R:, E:, B:, and A: Default Value: search priority
o = object name Accepted Values: 1 to 8 alphanumeric characters Default Value: if a name is not specified, UNKNOWN is used
x = extension Fixed Value: .GRF, .PNG
^FS
Field Separator Description The ^FS command denotes the end of the field definition. Alternatively, ^FS command can also be issued as a single ASCII control code SI (Control-O, hexadecimal 0F). Format ^FS
^XZ
End Format Description The ^XZ command is the ending (closing) bracket. It indicates the end of a label format. When this command is received, a label prints. This command can also be issued as a single ASCII control character ETX (Control-C, hexadecimal 03). Format ^XZ Comments Label formats must start with the ^XA command and end with the ^XZ command to be in valid ZPL II format.
zplToSend
^MN
Media Tracking Description This command specifies the media type being used and the black mark offset in dots. This bulleted list shows the types of media associated with this command:
Continuous Media – this media has no physical characteristic (such as a web, notch, perforation, black mark) to separate labels. Label length is determined by the ^LL command.
Continuous Media, variable length – same as Continuous Media, but if portions of the printed label fall outside of the defined label length, the label size will automatically be extended to contain them. This label length extension applies only to the current label. Note that ^MNV still requires the use of the ^LL command to define the initial desired label length.
Non-continuous Media – this media has some type of physical characteristic (such as web, notch, perforation, black mark) to separate the labels.
Format ^MNa,b
a = media being used Accepted Values: N = continuous media Y = non-continuous media web sensing d, e W = non-continuous media web sensing d, e M = non-continuous media mark sensing A = auto-detects the type of media during calibration d, f V = continuous media, variable length g Default Value: a value must be entered or the command is ignored
b = black mark offset in dots This sets the expected location of the media mark relative to the point of separation between documents. If set to 0, the media mark is expected to be found at the point of separation. (i.e., the perforation, cut point, etc.) All values are listed in dots. This parameter is ignored unless the a parameter is set to M. If this parameter is missing, the default value is used. Accepted Values: -80 to 283 for direct-thermal only printers -240 to 566 for 600 dpi printers -75 to 283 for KR403 printers -120 to 283 for all other printers Default Value: 0
~DY
Download Objects Description The ~DY command downloads to the printer graphic objects or fonts in any supported format. This command can be used in place of ~DG for more saving and loading options. ~DY is the preferred command to download TrueType fonts on printers with firmware later than X.13. It is faster than ~DU. The ~DY command also supports downloading wireless certificate files. Format ~DYd:f,b,x,t,w,data
Note
When using certificate files, your printer supports:
- Using Privacy Enhanced Mail (PEM) formatted certificate files.
- Using the client certificate and private key as two files, each downloaded separately.
- Using exportable PAC files for EAP-FAST.
- Zebra recommends using Linear sty
d = file location .NRD and .PAC files reside on E: in firmware versions V60.15.x, V50.15.x, or later. Accepted Values: R:, E:, B:, and A: Default Value: R:
f = file name Accepted Values: 1 to 8 alphanumeric characters Default Value: if a name is not specified, UNKNOWN is used
b = format downloaded in data field .TTE and .TTF are only supported in firmware versions V60.14.x, V50.14.x, or later. Accepted Values: A = uncompressed (ZB64, ASCII) B = uncompressed (.TTE, .TTF, binary) C = AR-compressed (used only by Zebra’s BAR-ONE® v5) P = portable network graphic (.PNG) - ZB64 encoded Default Value: a value must be specified
clearDownLabel
^ID
Description The ^ID command deletes objects, graphics, fonts, and stored formats from storage areas. Objects can be deleted selectively or in groups. This command can be used within a printing format to delete objects before saving new ones, or in a stand-alone format to delete objects.
The image name and extension support the use of the asterisk (*) as a wild card. This allows you to easily delete a selected groups of objects. Format ^IDd:o.x
d = location of stored object Accepted Values: R:, E:, B:, and A: Default Value: R:
o = object name Accepted Values: any 1 to 8 character name Default Value: if a name is not specified, UNKNOWN is used
x = extension Accepted Values: any extension conforming to Zebra conventions
Default Value: .GRF
const string PrintImage = "^XA^FO0,0,0^IME:LOGO.PNG^FS^XZ";
var zplImageData = string.Empty;
using (var response = request.GetResponse())
{
using (var responseStream = response.GetResponseStream())
{
using (var stream = new MemoryStream())
{
if (responseStream == null)
{
return;
}
responseStream.CopyTo(stream);
stream.Position = 0;
using (var zipout = ZipFile.Read(stream))
{
using (var ms = new MemoryStream())
{
foreach (var e in zipout.Where(e => e.FileName.Contains(".png")))
{
e.Extract(ms);
}
if (ms.Length <= 0)
{
return;
}
var binaryData = ms.ToArray();
foreach (var b in binaryData)
{
var hexRep = string.Format("{0:X}", b);
if (hexRep.Length == 1)
{
hexRep = "0" + hexRep;
}
zplImageData += hexRep;
}
var zplToSend = "^XA" + "^FO0,0,0" + "^MNN" + "~DYE:LOGO,P,P," + binaryData.Length + ",," + zplImageData + "^XZ";
var label = GenerateStreamFromString(zplToSend);
var client = new System.Net.Sockets.TcpClient();
client.Connect(IpAddress, Port);
label.CopyTo(client.GetStream());
label.Flush();
client.Close();
var cmd = GenerateStreamFromString(PrintImage);
var client2 = new System.Net.Sockets.TcpClient();
client2.Connect(IpAddress, Port);
cmd.CopyTo(client2.GetStream());
cmd.Flush();
client2.Close();var clearDownLabel = GenerateStreamFromString("^XA^IDR:LOGO.PNG^FS^XZ");
var client3 = new System.Net.Sockets.TcpClient();
client3.Connect(IpAddress, Port);
clearDownLabel.CopyTo(client3.GetStream());
clearDownLabel.Flush();
client3.Close();
}
}
}
}
}
}
Easy once you know how.
Zebra ZPL logo example in base64
Python3
import crcmod
import base64
crc16 = crcmod.predefined.mkCrcFun('xmodem')
s = hex(crc16(ZPL_LOGO.encode()))[2:]
print (f"crc16: {s}")
Poorly documented may I say the least

Real FFT output

I have implemented fft into at32ucb series ucontroller using kiss fft library and currently struggling with the output of the fft.
My intention is to analyse sound coming from piezo speaker.
Currently, the frequency of the sounder is 420Hz which I successfully got from the fft output (cross checked with an oscilloscope). However, the output frequency is just half of expected if I put function generator waveform into the system.
I suspect its the frequency bin calculation formula which I got wrong; currently using, fft_peak_magnitude_index*sampling frequency / fft_size.
My input is real and doing real fft. (output samples = N/2)
And also doing iir filtering and windowing before fft.
Any suggestion would be a great help!
// IIR filter calculation, n = 256 fft points
for (ctr=0; ctr<n; ctr++)
{
// filter calculation
y[ctr] = num_coef[0]*x[ctr];
y[ctr] += (num_coef[1]*x[ctr-1]) - (den_coef[1]*y[ctr-1]);
y[ctr] += (num_coef[2]*x[ctr-2]) - (den_coef[2]*y[ctr-2]);
y1[ctr] = y[ctr] - 510; //eliminate dc offset
// hamming window
hamming[ctr] = (0.54-((0.46) * cos(2*M_PI*ctr/n)));
window[ctr] = hamming[ctr]*y1[ctr];
fft_input[ctr].r = window[ctr];
fft_input[ctr].i = 0;
fft_output[ctr].r = 0;
fft_output[ctr].i = 0;
}
kiss_fftr_cfg fftConfig = kiss_fftr_alloc(n,0,NULL,NULL);
kiss_fftr(fftConfig, (kiss_fft_scalar * )fft_input, fft_output);
peak = 0;
freq_bin = 0;
for (ctr=0; ctr<n1; ctr++)
{
fft_mag[ctr] = 10*(sqrt((fft_output[ctr].r * fft_output[ctr].r) + (fft_output[ctr].i * fft_output[ctr].i)))/(0.5*n);
if(fft_mag[ctr] > peak)
{
peak = fft_mag[ctr];
freq_bin = ctr;
}
frequency = (freq_bin*(10989/n)); // 10989 is the sampling freq
//************************************
//Usart write
char filtResult[10];
//sprintf(filtResult, "%04d %04d %04d\n", (int)peak, (int)freq_bin, (int)frequency);
sprintf(filtResult, "%04d %04d %04d\n", (int)x[ctr], (int)fft_mag[ctr], (int)frequency);
char c;
char *ptr = &filtResult[0];
do
{
c = *ptr;
ptr++;
usart_bw_write_char(&AVR32_USART2, (int)c);
// sendByte(c);
} while (c != '\n');
}
The main problem is likely to be how you declared fft_input.
Based on your previous question, you are allocating fft_input as an array of kiss_fft_cpx. The function kiss_fftr on the other hand expect an array of scalar. By casting the input array into a kiss_fft_scalar with:
kiss_fftr(fftConfig, (kiss_fft_scalar * )fft_input, fft_output);
KissFFT essentially sees an array of real-valued data which contains zeros every second sample (what you filled in as imaginary parts). This is effectively an upsampled version (although without interpolation) of your original signal, i.e. a signal with effectively twice the sampling rate (which is not accounted for in your freq_bin to frequency conversion). To fix this, I suggest you pack your data into a kiss_fft_scalar array:
kiss_fft_scalar fft_input[n];
...
for (ctr=0; ctr<n; ctr++)
{
...
fft_input[ctr] = window[ctr];
...
}
kiss_fftr_cfg fftConfig = kiss_fftr_alloc(n,0,NULL,NULL);
kiss_fftr(fftConfig, fft_input, fft_output);
Note also that while looking for the peak magnitude, you probably are only interested in the final largest peak, instead of the running maximum. As such, you could limit the loop to only computing the peak (using freq_bin instead of ctr as an array index in the following sprintf statements if needed):
for (ctr=0; ctr<n1; ctr++)
{
fft_mag[ctr] = 10*(sqrt((fft_output[ctr].r * fft_output[ctr].r) + (fft_output[ctr].i * fft_output[ctr].i)))/(0.5*n);
if(fft_mag[ctr] > peak)
{
peak = fft_mag[ctr];
freq_bin = ctr;
}
} // close the loop here before computing "frequency"
Finally, when computing the frequency associated with the bin with the largest magnitude, you need the ensure the computation is done using floating point arithmetic. If as I suspect n is an integer, your formula would be performing the 10989/n factor using integer arithmetic resulting in truncation. This can be simply remedied with:
frequency = (freq_bin*(10989.0/n)); // 10989 is the sampling freq

Resources