### Get kiwirecorder.py help Source: https://github.com/jks-prv/kiwiclient/blob/master/README.md Obtain the complete list of options for kiwirecorder.py by running the help command. ```bash python3 kiwirecorder.py --help ``` ```bash make help ``` -------------------------------- ### Install libsamplerate dylib on macOS using Homebrew Source: https://github.com/jks-prv/kiwiclient/blob/master/samplerate/_samplerate_data/README.md Install libsamplerate using Homebrew and copy the resulting dylib to the current directory. Verify dependencies using otool. ```bash brew install libsamplerate cp /usr/local/lib/libsamplerate.dylib . # There should be no further dependencies: otool -L libsamplerate.dylib ``` -------------------------------- ### Setup for Waterfall Data Analysis Source: https://github.com/jks-prv/kiwiclient/blob/master/waterfall_data_analysis.ipynb Initializes plotting environment and imports necessary libraries for data manipulation and binary file reading. ```python %pylab inline import struct ``` -------------------------------- ### Run kiwiclientd with two simultaneous channels Source: https://context7.com/jks-prv/kiwiclient/llms.txt Starts the `kiwiclientd` daemon to create two virtual sound cards, mapping rigctl ports to 6400 and 6401. Use this for simultaneous reception on different frequencies or modes. ```bash python3 kiwiclientd.py -s sdr.example.com -p 8073 \ -f 14074,7074 -m usb \ --snddev kiwisnd0,kiwisnd1 \ --rigctl-port 6400,6401 --enable-rigctl ``` -------------------------------- ### Configure LPM and IOC with kiwifax.py Source: https://context7.com/jks-prv/kiwiclient/llms.txt Set the Lines Per Minute (LPM) and Index of Cooperation (IOC) for fax decoding. This example sets LPM to 60 and IOC to 576. ```bash # 60 LPM fax (default is 120), IOC 576 (default) python3 kiwifax.py -s sdr.example.com -f 4610 -l 60 -i 576 ``` -------------------------------- ### Force Start Decoding with kiwifax.py Source: https://context7.com/jks-prv/kiwiclient/llms.txt Force the decoding process to start immediately without waiting for the start tone. This is useful for capturing transmissions that may have already begun. Use the -F flag. ```bash # Force start immediately without waiting for start tone (e.g., mid-transmission) python3 kiwifax.py -s sdr.example.com -f 7880 -F ``` -------------------------------- ### Convert Frequency to Legacy Counter - Python Source: https://context7.com/jks-prv/kiwiclient/llms.txt Computes the legacy counter value needed for the `SET start=` API (Kiwi server < v1.329) and the actual start frequency in kHz. ```python # Convert a start frequency to a counter for old API counter, actual_start = stream.start_frequency_to_counter(14000.0) print(f'counter={counter}, actual_start={actual_start:.3f} kHz') ``` -------------------------------- ### microkiwi_waterfall.py Expected Output Source: https://context7.com/jks-prv/kiwiclient/llms.txt Example output from the microkiwi_waterfall.py script, showing server details, waterfall bin information, frequency range, and computed SNR metrics. ```bash # Expected output: # KiwiSDR Server: 192.168.1.82:8073 # Number of waterfall bins: 1024 # Zoom factor: 0 # Start 0.000, Stop 30.000, Center 15.000, Span 30.000 (MHz) # Average SNR computation... # Waterfall with 1024 bins: median= -92.50 dB, p95= -71.30 dB - SNR= 21.20 rbw= 29.297 kHz ``` -------------------------------- ### Start and manage KiwiWorker thread Source: https://context7.com/jks-prv/kiwiclient/llms.txt Launches a `KiwiWorker` thread to manage a `KiwiSDRStream` connection. This worker handles automatic reconnection, back-off on busy servers, and HTTP redirect following for robust multi-Kiwi recording. ```python import threading from kiwi import KiwiSDRStream, KiwiWorker run_event = threading.Event() run_event.set() camp_wait_event = threading.Event() camp_wait_event.set() # args = (recorder_instance, options, is_reader, delay_run, run_event, camp_wait_event) worker = KiwiWorker(args=(my_recorder, opts, True, False, run_event, camp_wait_event)) worker.start() try: while run_event.is_set(): time.sleep(0.1) except KeyboardInterrupt: run_event.clear() worker._event.set() worker.join() # KiwiWorker automatically handles: # KiwiTooBusyError → waits busy_timeout seconds, retries busy_retries times # KiwiRedirectError → follows HTTP redirect to secondary proxy server # KiwiServerTerminatedConnection → waits 5 s and reconnects # KiwiTimeLimitError → clean exit ``` -------------------------------- ### Receive JMH Tokyo Meteo fax with kiwifax.py Source: https://context7.com/jks-prv/kiwiclient/llms.txt Receive and save HF radiofax signals. This example tunes to 13988.5 kHz and saves the output with the station ID 'tokyo'. Expected output files include a PNG image and a log file. ```bash # Receive JMH Tokyo Meteo fax on 13988.5 kHz python3 kiwifax.py -s sdr.example.com -f 13988.5 --station tokyo # Expected output files: 20240601T1200Z_13988500_tokyo.png, ... # Log: log_sdr.example.com_8073_13988500.log ``` -------------------------------- ### Streaming Raw IQ Samples with kiwirecorder.py Source: https://context7.com/jks-prv/kiwiclient/llms.txt Stream raw S16LE samples to stdout for processing by other tools like dumphfdl. Use the --nc flag for netcat mode. ```bash python3 kiwirecorder.py -s sdr.example.com -f 8942 -m iq --nc | dumphfdl ... ``` -------------------------------- ### Convert IQ WAV to WSPR .c2 format (multiple files) Source: https://context7.com/jks-prv/kiwiclient/llms.txt Converts multiple IQ WAV files matching a pattern (e.g., `*.wav`) into the `.c2` binary format for WSPR decoding. Ensure the input WAV files meet the recording requirements (`--resample 375 --kiwi-wav`). ```bash # Convert multiple files at once python3 kiwi_iq_wav_to_c2.py *.wav ``` -------------------------------- ### Camp on Existing Channel with kiwirecorder.py Source: https://context7.com/jks-prv/kiwiclient/llms.txt Camp on a specific existing Kiwi channel to record whatever signal it is tuned to. Use the --camp option followed by the channel number. ```bash python3 kiwirecorder.py -s sdr.example.com --camp 0 ``` -------------------------------- ### Stream Audio to Default Sound Card with kiwiclientd.py Source: https://context7.com/jks-prv/kiwiclient/llms.txt Stream audio from a KiwiSDR to the default sound card and enable a hamlib rigctld-compatible network interface on port 6400. Use --enable-rigctl to activate the rigctl interface. ```bash # Stream USB audio to default sound card, rigctl on port 6400 python3 kiwiclientd.py -s sdr.example.com -f 14074 -m usb --enable-rigctl ``` -------------------------------- ### Convert IQ WAV to WSPR .c2 format (single file) Source: https://context7.com/jks-prv/kiwiclient/llms.txt Converts a single IQ WAV file, recorded with specific parameters (`--resample 375 --kiwi-wav`), into the `.c2` binary format required by `wsprd` for WSPR decoding. The output filename follows the `wsprd` expected format. ```bash # Convert a single IQ WAV file python3 kiwi_iq_wav_to_c2.py 20240601T120000Z_14095600_mysite_iq.wav # Output: 240601_1200.c2 (filename format wsprd expects) ``` -------------------------------- ### Connect fldigi to kiwiclientd using Hamlib Source: https://context7.com/jks-prv/kiwiclient/llms.txt Instructions for configuring fldigi to connect to `kiwiclientd` via Hamlib's rigctl. Ensure the rigctl port in fldigi matches the `--rigctl-port` specified for `kiwiclientd`. ```text # Connect fldigi to kiwiclientd: in fldigi configure hamlib as: # Rig: Hamlib NET rigctl, host 127.0.0.1, port 6400 # Key extra options vs kiwirecorder: # --snddev / --sound-device : target sound card name # --enable-rigctl : start rigctl listener # --rigctl-port : port for rigctl (default 6400) # --rigctl-address : bind address (default 127.0.0.1) # --if : IF frequency Hz for IQ frequency shift # --blocksize : sound player block size in frames # --thresh : squelch threshold dB ``` -------------------------------- ### Build libsamplerate DLLs on Windows using MXE Source: https://github.com/jks-prv/kiwiclient/blob/master/samplerate/_samplerate_data/README.md Clone the MXE repository and use the provided script to build libsamplerate DLLs for Windows. This method is suitable for cross-compiling on macOS. ```bash git clone https://github.com/mxe/mxe.git ./build-samplerate.sh ``` -------------------------------- ### Continuous Frequency Scanning with kiwirecorder.py Source: https://context7.com/jks-prv/kiwiclient/llms.txt Use a YAML file to define continuous frequency scans. Ensure the YAML file does not contain a 'threshold' key for this mode. ```bash python3 kiwirecorder.py -s sdr.example.com --scan-yaml scan_continuous.yaml ``` -------------------------------- ### Instantiate and run Rigctld emulator Source: https://context7.com/jks-prv/kiwiclient/llms.txt Initializes the `Rigctld` emulator, which emulates the Hamlib rigctld protocol for software like fldigi. It translates commands into KiwiSDR `set_mod` calls. Ensure a `KiwiSDRStream` instance is already connected before instantiation. ```python from kiwi.rigctld import Rigctld # Instantiate with a KiwiSDRStream instance already connected rigctld = Rigctld(kiwisdrstream=my_stream, port=6400, ipaddr='127.0.0.1') # Call run() in a polling loop (already done automatically by KiwiWorker) while True: rigctld.run() # non-blocking: accepts connections, processes commands # Supported rigctl commands: # f → get frequency (returns Hz) # F → set frequency # m → get mode + high-cut passband # M [passband] → set mode # v → get VFO (always VFOA) # s → get split (always 0) # dump_state → rig capabilities table for hamlib # chk_vfo → VFO check # q → quit / close connection rigctld.close() ``` -------------------------------- ### kiwirecorder.py - Recording Audio, IQ, and Waterfall Source: https://context7.com/jks-prv/kiwiclient/llms.txt Command-line utility for recording audio, IQ data, and waterfall imagery from KiwiSDR devices. Supports various configurations including resampling, squelch, and file formats. ```APIDOC ## `kiwirecorder.py` — Record audio, IQ, and waterfall to files The main recording program. Supports simultaneous connections to multiple Kiwis, squelch, frequency scanning, resampling, waterfall PNG output, DX label management, netcat streaming, and reverse connections. ```bash # Record 30 s of AM audio from a public KiwiSDR to a timestamped WAV python3 kiwirecorder.py -s sdr.example.com -p 8073 -f 9600 -m am --tlimit 30 # Record IQ samples at 375 Hz (WSPR-ready) with GNSS timestamps python3 kiwirecorder.py -s sdr.example.com -f 14095.6 -m iq \ --kiwi-wav --resample 375 --tlimit 120 --station mysite # Record from two Kiwis simultaneously on different frequencies python3 kiwirecorder.py \ -s kiwi1.example.com,kiwi2.example.com \ -p 8073,8073 \ -f 7000,14000 \ -m usb --tlimit 60 --station kiwi1,kiwi2 # Squelch recording: open when RSSI > median+15 dB, tail 2 s python3 kiwirecorder.py -s sdr.example.com -f 156800 -m nbfm \ -T 15 --squelch-tail 2.0 # Waterfall + PNG snapshot with auto-range python3 kiwirecorder.py -s sdr.example.com -f 10000 --wf --wf-png \ --wf-auto --zoom 2 --speed 4 --tlimit 5 # DX label listing (2.5–5 MHz range), results written to dx.json python3 kiwirecorder.py -s sdr.example.com --admin --pw adminpass \ --dx 2500 5000 # Add a DX label python3 kiwirecorder.py -s sdr.example.com --admin --pw adminpass \ --dx-add --dx-ident "WWV" --dx-notes "Time station" -f 10000 -m am # Delete a DX label by index (index from --dx list) python3 kiwirecorder.py -s sdr.example.com --admin --pw adminpass \ --dx-del 42 # AGC from YAML file python3 kiwirecorder.py -s sdr.example.com -f 7040 -m usb \ --agc-yaml default_agc.yaml # Frequency scanning with squelch (scan_squelch.yaml): # Scan: threshold: 20 / wait: 1 / dwell: 6 / frequencies: [4024, 4030, 4039] python3 kiwirecorder.py -s sdr.example.com --scan-yaml scan_squelch.yaml ``` ``` -------------------------------- ### Record IQ samples with GNSS timestamps Source: https://github.com/jks-prv/kiwiclient/blob/master/README.md Use the -m iq option with --kiwi-wav and --station to record IQ samples. A gnss_pos/ directory will be created if it exists, containing latitude and longitude in a .txt file. ```bash python3 kiwirecorder.py -m iq --kiwi-wav --station=[name] ``` -------------------------------- ### microkiwi_waterfall.py Options Source: https://context7.com/jks-prv/kiwiclient/llms.txt Command-line options for the microkiwi_waterfall.py script, detailing server, port, lines, zoom, offset, file output, and verbose mode. ```bash # Options: # -s SERVER : KiwiSDR hostname or IP (default 192.168.1.82) # -p PORT : port (default 8073) # -l N : number of waterfall lines to collect (default 100) # -z ZOOM : zoom factor 0–14 (default 0 = full 30 MHz) # -o OFFSET : start frequency kHz (default 0) # -f FILE : save raw binary data to FILE (optional) # -v 1 : verbose output ``` -------------------------------- ### Run kiwiclientd with custom rigctl blocksize Source: https://context7.com/jks-prv/kiwiclient/llms.txt Sets a specific blocksize (in frames) for the rigctl listener to potentially reduce latency. This is useful when integrating with software that requires lower latency. ```bash python3 kiwiclientd.py -s sdr.example.com -f 14074 -m usb \ --enable-rigctl --blocksize 512 ``` -------------------------------- ### Use IQ Stream Input with kiwifax.py Source: https://context7.com/jks-prv/kiwiclient/llms.txt Utilize an IQ stream as input for radiofax decoding, which is an experimental feature. Use the --iq-stream flag. ```bash # Use IQ stream input (experimental) instead of USB demod python3 kiwifax.py -s sdr.example.com -f 9165 --iq-stream ``` -------------------------------- ### Netcat Streaming with WAV Header using kiwirecorder.py Source: https://context7.com/jks-prv/kiwiclient/llms.txt Stream audio with a WAV header to stdout, suitable for piping to audio processing tools like sox or ffmpeg. The --nc-wav flag prepends the WAV header. ```bash python3 kiwirecorder.py -s sdr.example.com -f 7000 -m usb --nc --nc-wav \ | sox -t wav - -t wav output.wav ``` -------------------------------- ### Enable Noise Blanker - Python Source: https://context7.com/jks-prv/kiwiclient/llms.txt Configures the KiwiSDR's standard noise blanker (NB_STD algorithm) with gate time and threshold percentage. Gate time ranges from 100–5000 µs, and threshold from 0–100 %. ```python # Enable NB: 200 µs gate, 60% threshold stream.set_noise_blanker(gate=200, thresh=60) ``` ```python # Minimum gate (fastest), moderate threshold stream.set_noise_blanker(gate=100, thresh=50) ``` -------------------------------- ### Resample Audio for Sound Card Compatibility with kiwiclientd.py Source: https://context7.com/jks-prv/kiwiclient/llms.txt Resample the audio output to a specific rate (e.g., 48000 Hz) if the target sound card does not support the native sample rate. Use the --resample option. ```bash # Resample to 48000 Hz for sound cards that don't accept 12000 Hz native python3 kiwiclientd.py -s sdr.example.com -f 14074 -m usb \ --resample 48000 --enable-rigctl ``` -------------------------------- ### Stream Audio to Named Virtual Sound Card with kiwiclientd.py Source: https://context7.com/jks-prv/kiwiclient/llms.txt Stream audio to a specific named virtual sound card, such as a PulseAudio sink. This allows routing audio to specific applications. Use the --sound-device option. ```bash # Stream to a named virtual sound card (e.g. PulseAudio sink) python3 kiwiclientd.py -s sdr.example.com -f 7074 -m usb \ --sound-device "kiwisdr_virtual" --enable-rigctl --rigctl-port 6400 ``` -------------------------------- ### Record from Multiple Kiwis Simultaneously - Bash Source: https://context7.com/jks-prv/kiwiclient/llms.txt Records audio from two KiwiSDRs simultaneously on different frequencies. Requires specifying server addresses, ports, frequencies, and modes for each Kiwi. ```bash # Record from two Kiwis simultaneously on different frequencies python3 kiwirecorder.py \ -s kiwi1.example.com,kiwi2.example.com \ -p 8073,8073 \ -f 7000,14000 \ -m usb --tlimit 60 --station kiwi1,kiwi2 ``` -------------------------------- ### Run kiwiclientd in IQ mode with IF shift Source: https://context7.com/jks-prv/kiwiclient/llms.txt Configures `kiwiclientd` for IQ mode, allowing SDR software to use an IF shift. Specify the IF offset in Hz and the desired resampling rate. ```bash python3 kiwiclientd.py -s sdr.example.com -f 14000 -m iq \ --if 12 --resample 48000 --enable-rigctl ``` -------------------------------- ### Implement Custom KiwiSDR Receiver Source: https://context7.com/jks-prv/kiwiclient/llms.txt Subclass `KiwiSDRStream` to create custom receivers. Override methods like `_process_audio_samples` and `_setup_rx_params` to handle incoming data and configure the receiver. Ensure all necessary options are passed to the `KiwiSDRStream` constructor. ```python from kiwi import KiwiSDRStream, KiwiWorker class MyReceiver(KiwiSDRStream): def __init__(self, options): super().__init__() self._options = options self._type = 'SND' # 'SND' for audio/IQ, 'W/F' for waterfall def _setup_rx_params(self): # Called once after the server sends its sample rate self.set_name('my_client') self.set_freq(self._options.frequency) # kHz self.set_agc(on=True) # enable AGC def _process_audio_samples(self, seq, samples, rssi, fmt): # seq: sequence number, samples: np.int16 array, rssi: float dBm print(f'seq={seq:#010x} RSSI={rssi:.1f} dBm len={len(samples)}') def _process_iq_samples(self, seq, samples, rssi, gps, fmt): # samples: np.complex64 array, gps: dict with GPS timestamps or None import numpy as np power_db = 10 * np.log10(np.mean(np.abs(samples)**2) + 1e-20) print(f'IQ block {seq:#010x}: power={power_db:.1f} dB') def _process_waterfall_samples(self, seq, samples): # samples: array of uint8 values (0-255 → roughly -200..0 dBm) dBm = [int(s) - 255 for s in samples] peak = max(dBm) print(f'WF seq={seq} peak={peak} dBm') import optparse, time opts = optparse.Values() opts.frequency = 7000.0 # kHz opts.modulation = 'usb' opts.lp_cut = None opts.hp_cut = None opts.agc_gain = None opts.compression = True opts.nb = False opts.nb_gate = 100 opts.nb_thresh = 50 opts.nb_test = False opts.de_emp = False opts.freq_pbc = False opts.freq_offset = 0 opts.resample = 0 opts.S_meter = -1 opts.tlimit = 30.0 opts.sound = False opts.test_mode = False opts.scan_yaml = None opts.no_api = False opts.bad_cmd = False opts.devel = None opts.wf_comp = False opts.camp_chan = -1 opts.camp_allow_1ch = False opts.wideband = False opts.ADC_OV = False opts.quiet = True opts.not_quiet = False opts.log_level = 'warn' opts.tstamp = False opts.stats = False opts.multiple_connections = 0 opts.idx = 0 opts.server_host = 'kiwisdr.example.com' opts.server_port = 8073 opts.password = '' opts.tlimit_password = '' opts.admin = False opts.nolocal = False opts.socket_timeout = 10 opts.ws_timestamp = int(time.time()) & 0xffffffff opts.is_kiwi_wav = False recv = MyReceiver(opts) recv.connect('kiwisdr.example.com', 8073) recv.open() try: while True: recv.run() except Exception: pass recv.close() ``` -------------------------------- ### Apply Sample Rate Correction with kiwifax.py Source: https://context7.com/jks-prv/kiwiclient/llms.txt Apply a sample rate correction coefficient to compensate for frequency drift. A positive coefficient is used if lines appear too short. Use the --sr-coeff option. ```bash # Apply sample rate correction of +7 ppm (lines too long → positive) python3 kiwifax.py -s sdr.example.com -f 7795 --sr-coeff 7.0 ``` -------------------------------- ### Run microkiwi_waterfall.py to Collect Waterfall Data Source: https://context7.com/jks-prv/kiwiclient/llms.txt A lightweight script to connect to a KiwiSDR via WebSocket, collect waterfall data, compute SNR, and optionally save binary data. Use the options to configure server, port, lines, zoom, offset, and output file. ```bash # Print SNR only (no file saved) python3 microkiwi_waterfall.py -s 192.168.1.82 -p 8073 -l 100 ``` ```bash # Save 200 waterfall lines to binary file, zoom=3, start at 14 MHz python3 microkiwi_waterfall.py -s 192.168.1.82 -p 8073 \ -l 200 -z 3 -o 14000 -f waterfall_20240601.bin ``` -------------------------------- ### Invoke WAV file processing with Makefile Source: https://github.com/jks-prv/kiwiclient/blob/master/README.md Invoke the processing of WAV files using a Makefile rule. Replace 'filename.wav' with the actual file name. ```bash make proc f=filename.wav ``` -------------------------------- ### Record AM Audio - Bash Source: https://context7.com/jks-prv/kiwiclient/llms.txt Records 30 seconds of AM audio from a specified KiwiSDR to a timestamped WAV file. Requires specifying the server, port, frequency, and mode. ```bash # Record 30 s of AM audio from a public KiwiSDR to a timestamped WAV python3 kiwirecorder.py -s sdr.example.com -p 8073 -f 9600 -m am --tlimit 30 ``` -------------------------------- ### Load AGC Settings from YAML - Bash Source: https://context7.com/jks-prv/kiwiclient/llms.txt Applies AGC settings defined in a YAML file to the KiwiSDR. This allows for persistent and configurable AGC profiles. ```bash # AGC from YAML file python3 kiwirecorder.py -s sdr.example.com -f 7040 -m usb \ --agc-yaml default_agc.yaml ``` -------------------------------- ### Record IQ Samples with GNSS Timestamps - Bash Source: https://context7.com/jks-prv/kiwiclient/llms.txt Records IQ samples at 375 Hz, suitable for WSPR, with GNSS timestamps. Includes options for resampling, time limit, and station identification. ```bash # Record IQ samples at 375 Hz (WSPR-ready) with GNSS timestamps python3 kiwirecorder.py -s sdr.example.com -f 14095.6 -m iq \ --kiwi-wav --resample 375 --tlimit 120 --station mysite ``` -------------------------------- ### Limit Page Height and Dump Spectra with kiwifax.py Source: https://context7.com/jks-prv/kiwiclient/llms.txt Limit the maximum number of lines per page and dump debug spectra and pixel data. Use --max-height to set the line limit and --dump-spectra/--dump-pixels for debugging. ```bash # Limit to 2300 lines per page (default), dump debug spectra python3 kiwifax.py -s sdr.example.com -f 13988.5 --max-height 3000 \ --dump-spectra --dump-pixels ``` -------------------------------- ### Squelch Recording - Bash Source: https://context7.com/jks-prv/kiwiclient/llms.txt Records audio with squelch enabled, opening when RSSI exceeds a threshold (median+15 dB) and maintaining a 2-second tail after signal loss. ```bash # Squelch recording: open when RSSI > median+15 dB, tail 2 s python3 kiwirecorder.py -s sdr.example.com -f 156800 -m nbfm \ -T 15 --squelch-tail 2.0 ``` -------------------------------- ### Configure and run squelch scan Source: https://context7.com/jks-prv/kiwiclient/llms.txt Executes a frequency scan using a YAML configuration file where the scanner stops and records when a signal's threshold is exceeded. The `threshold` parameter defines the dB above the noise floor required to open the squelch. ```bash # Run squelch scan — records when any frequency exceeds SNR threshold python3 kiwirecorder.py -s sdr.example.com -m usb --scan-yaml scan_squelch.yaml ``` -------------------------------- ### Compile Octave extension for WAV files Source: https://github.com/jks-prv/kiwiclient/blob/master/README.md Compile the Octave extension for reading WAV files with GNSS timestamps. The compilation details can be found in read_kiwi_iq_wav.cc. ```bash make install ``` -------------------------------- ### Process recorded WAV files in Octave Source: https://github.com/jks-prv/kiwiclient/blob/master/README.md Use the provided Octave function proc_kiwi_iq_wav.m to process recorded WAV files. Type 'help proc_kiwi_iq_wav' in Octave for documentation. ```octave help proc_kiwi_iq_wav ``` -------------------------------- ### Read KiwiSDR IQ WAV Files - Simple Function - Python Source: https://context7.com/jks-prv/kiwiclient/llms.txt Uses a convenience function to read GNSS-timestamped IQ WAV files. Returns time and IQ sample arrays. Useful for smaller files or when immediate data access is needed. ```python from kiwi.wavreader import KiwiIQWavReader, read_kiwi_iq_wav import numpy as np # --- Simple convenience function --- t, z = read_kiwi_iq_wav('20240601T120000Z_14074000_usb.wav') print(f'samples={len(z)}, duration={t[-1]-t[0]:.3f}s, fs={len(z)/(t[-1]-t[0]):.1f} Hz') ``` -------------------------------- ### Waterfall and PNG Snapshot - Bash Source: https://context7.com/jks-prv/kiwiclient/llms.txt Records waterfall data and generates a PNG snapshot with automatic range adjustment. Options control zoom level, speed, and recording duration. ```bash # Waterfall + PNG snapshot with auto-range python3 kiwirecorder.py -s sdr.example.com -f 10000 --wf --wf-png \ --wf-auto --zoom 2 --speed 4 --tlimit 5 ``` -------------------------------- ### Check WAV file integrity Source: https://github.com/jks-prv/kiwiclient/blob/master/README.md Check the integrity of a .wav file using the client/wavreader.py script. Replace 'filename.wav' with the actual file name. ```bash make wav f=filename.wav ``` -------------------------------- ### S-meter RSSI Averaging with kiwirecorder.py Source: https://context7.com/jks-prv/kiwiclient/llms.txt Report the average RSSI readings after a specified number of averages, along with a timestamp. Use the --S-meter option followed by the number of averages and --ts for timestamp. ```bash python3 kiwirecorder.py -s sdr.example.com -f 14000 -m am \ --S-meter 10 --ts ``` -------------------------------- ### Set Modulation and Passband - Python Source: https://context7.com/jks-prv/kiwiclient/llms.txt Configures the SDR's modulation type and explicit passband frequencies. Default passbands are available for common modes like LSB, USB, CW, AM, IQ, and NBFM. ```python stream.set_mod('amn', -2500, 2500, 9600.0) ``` -------------------------------- ### Configure Automatic Gain Control (AGC) - Python Source: https://context7.com/jks-prv/kiwiclient/llms.txt Controls automatic gain or sets a fixed manual gain level. All parameters are optional with sensible defaults. ```python # Enable AGC with fast decay stream.set_agc(on=True, hang=False, thresh=-100, slope=6, decay=300, gain=50) ``` ```python # Disable AGC, fixed gain 30 dB stream.set_agc(on=False, gain=30) ``` ```python # Load AGC settings from a YAML file (kiwirecorder --agc-yaml option) # default_agc.yaml: # AGC: # 'on': False # hang: False # thresh: -100 # slope: 6 # decay: 1000 # gain: 50 ``` -------------------------------- ### Set Modulation and Passband Source: https://context7.com/jks-prv/kiwiclient/llms.txt Use `set_mod` to configure the receiver's modulation, passband, and center frequency. Pass `None` for `lc` and `hc` to use default passband values. Supported modulations include `am`, `lsb`, `usb`, `iq`, and others. ```python # Set to USB, 300–2700 Hz passband, 14.074 MHz stream.set_mod('usb', 300, 2700, 14074.0) ``` ```python # Set to IQ (stereo), default ±5 kHz passband stream.set_mod('iq', None, None, 7040.0) ``` -------------------------------- ### Add DX Label - Bash Source: https://context7.com/jks-prv/kiwiclient/llms.txt Adds a new DX label with specified identification and notes to the KiwiSDR. Requires administrative credentials and frequency/mode information. ```bash # Add a DX label python3 kiwirecorder.py -s sdr.example.com --admin --pw adminpass \ --dx-add --dx-ident "WWV" --dx-notes "Time station" -f 10000 -m am ``` -------------------------------- ### Read KiwiSDR IQ WAV Files - Iterator - Python Source: https://context7.com/jks-prv/kiwiclient/llms.txt Utilizes an iterator class for reading large KiwiSDR IQ WAV files or for streaming processing. It yields chunks of time and IQ data, skipping initial frames for rate estimation. ```python # --- Iterator for large files / streaming processing --- reader = KiwiIQWavReader('20240601T120000Z_7040000_iq.wav') print('Advertised sample rate:', reader.get_samplerate(), 'Hz') for t_chunk, z_chunk in reader: if t_chunk is None: # first two frames skipped for rate estimation continue power = 10 * np.log10(np.mean(np.abs(z_chunk)**2)) gps_t = t_chunk[0] print(f't={gps_t:.6f} power={power:.1f} dBFS n={len(z_chunk)}') ``` -------------------------------- ### Decode Kiwi WAV Filename and Convert to C2 Source: https://context7.com/jks-prv/kiwiclient/llms.txt Programmatically decodes a KiwiSDR WAV filename to extract C2 name and frequency, and converts WAV files to C2 format. Requires the `kiwi_iq_wav_to_c2` module. ```python # Programmatic use from kiwi_iq_wav_to_c2 import convert_kiwi_wav_to_c2, decode_kiwi_wav_filename c2_name, freq_kHz = decode_kiwi_wav_filename('20240601T120000Z_14095600_iq.wav') # c2_name = '240601_1200.c2', freq_kHz = 14095.6 convert_kiwi_wav_to_c2('20240601T120000Z_14095600_iq.wav') # Creates: 240601_1200.c2 ``` -------------------------------- ### Frequency Scanning with Squelch - Bash Source: https://context7.com/jks-prv/kiwiclient/llms.txt Configures the KiwiSDR to scan through a list of frequencies with squelch enabled. The scan behavior is defined in a YAML file, specifying threshold, wait times, dwell time, and frequencies. ```bash # Frequency scanning with squelch (scan_squelch.yaml): # Scan: threshold: 20 / wait: 1 / dwell: 6 / frequencies: [4024, 4030, 4039] python3 kiwirecorder.py -s sdr.example.com --scan-yaml scan_squelch.yaml ``` -------------------------------- ### Plot Signal Level Distributions Source: https://github.com/jks-prv/kiwiclient/blob/master/waterfall_data_analysis.ipynb Generates histograms to show the distribution of signal levels for both instantaneous and average data. Sets x-axis limits to focus on relevant dB ranges. ```python figure(figsize=(20,8)) _=hist(waterfall_array[0,:], bins=40, normed=True) xlim(-110,0) xlabel("Signal level (dB)") ylabel("Occurrences") title("Instantaneous power level distribution") figure(figsize=(20,8)) _=hist(avg_wf, bins=40, normed=True) xlim(-110,0) xlabel("Signal level (dB)") ylabel("Occurrences") title("Average power level distribution") ``` -------------------------------- ### Configure and run continuous scan Source: https://context7.com/jks-prv/kiwiclient/llms.txt Runs a continuous frequency scan based on a YAML configuration. The scanner cycles through all specified frequencies without stopping, recording each for a defined `dwell` period. This mode is used when no specific squelch threshold is required. ```bash # Run continuous scan — records each frequency for dwell seconds, then moves on python3 kiwirecorder.py -s sdr.example.com -m am --scan-yaml scan_continuous.yaml ``` -------------------------------- ### List DX Labels - Bash Source: https://context7.com/jks-prv/kiwiclient/llms.txt Lists DX labels within a specified frequency range (2.5–5 MHz). Results are written to a JSON file named `dx.json`. Requires administrative credentials. ```bash # DX label listing (2.5–5 MHz range), results written to dx.json python3 kiwirecorder.py -s sdr.example.com --admin --pw adminpass \ --dx 2500 5000 ``` -------------------------------- ### KiwiSDRStream.set_noise_blanker Source: https://context7.com/jks-prv/kiwiclient/llms.txt Enable and configure the standard noise blanker (NB_STD algorithm) for the SDR stream. Parameters include gate time and threshold percentage. ```APIDOC ## `KiwiSDRStream.set_noise_blanker` — Enable noise blanker Configures the KiwiSDR's standard noise blanker (NB_STD algorithm) with gate time and threshold percentage. ```python # Enable NB: 200 µs gate, 60% threshold stream.set_noise_blanker(gate=200, thresh=60) # Minimum gate (fastest), moderate threshold stream.set_noise_blanker(gate=100, thresh=50) # gate: 100–5000 µs; thresh: 0–100 % ``` ``` -------------------------------- ### Compute SNR Estimation Source: https://github.com/jks-prv/kiwiclient/blob/master/waterfall_data_analysis.ipynb Calculates an estimation of the Signal-to-Noise Ratio (SNR) using the median and 95th percentile of the average power level data. Prints the estimated SNR values. ```python median = np.median(avg_wf) perc95 = np.percentile(avg_wf, 95) print "SNR estimation: median: %f dB, 95th perc.: %f dB, SNR: %f dB" % (median, perc95, perc95-median) ``` -------------------------------- ### Read Binary Waterfall File Source: https://github.com/jks-prv/kiwiclient/blob/master/waterfall_data_analysis.ipynb Reads header and data from a binary waterfall file. Assumes a specific header format and reshapes the data into a 2D numpy array. Adjusts data values and calculates the average spectrum. ```python header_len = 8+26 # 2 unsigned int for center_freq and span: 8 bytes PLUS 26 bytes for datetime nbin = 1024 with open("wf.bin", "rb") as fd: buff = fd.read() length = len(buff[header_len:]) n_t = length / nbin header = struct.unpack('2I26s', buff[:header_len]) data = struct.unpack('%dB'%length, buff[header_len:]) waterfall_array = np.reshape(np.array(data[:]), (n_t, nbin)) waterfall_array -= 255 avg_wf = np.mean(waterfall_array[:,:], axis=0) center_frequency, span, rec_time = header start_freq = center_frequency - span/2 stop_freq = center_frequency + span/2 print "Recording date:", rec_time ``` -------------------------------- ### KiwiSDRStream.zoom_to_span / start_frequency_to_counter Source: https://context7.com/jks-prv/kiwiclient/llms.txt Convert zoom levels to frequency spans in kHz, or compute legacy counter values for older API versions. Useful for understanding waterfall geometry and API compatibility. ```APIDOC ## `KiwiSDRStream.zoom_to_span` / `start_frequency_to_counter` — Waterfall geometry Convert zoom level to frequency span in kHz, or compute the legacy counter value needed for the `SET start=` API (Kiwi server < v1.329). ```python stream = KiwiSDRStream() # zoom=0 → full 30 MHz span span_khz = stream.zoom_to_span(0) # 30000.0 kHz # zoom=5 → 30000/32 = 937.5 kHz span span_khz = stream.zoom_to_span(5) # 937.5 kHz # Convert a start frequency to a counter for old API counter, actual_start = stream.start_frequency_to_counter(14000.0) print(f'counter={counter}, actual_start={actual_start:.3f} kHz') # counter=7680, actual_start=13989.258 kHz ``` ``` -------------------------------- ### Convert Zoom Level to Frequency Span - Python Source: https://context7.com/jks-prv/kiwiclient/llms.txt Converts a zoom level to its corresponding frequency span in kHz. Zoom level 0 represents the full 30 MHz span. ```python stream = KiwiSDRStream() # zoom=0 → full 30 MHz span span_khz = stream.zoom_to_span(0) # 30000.0 kHz # zoom=5 → 30000/32 = 937.5 kHz span span_khz = stream.zoom_to_span(5) # 937.5 kHz ``` -------------------------------- ### KiwiSDRStream Base Class Source: https://context7.com/jks-prv/kiwiclient/llms.txt The central base class for creating custom KiwiSDR receivers. It handles WebSocket connections, authentication, and data stream dispatching. Users should subclass this and override specific methods to process audio, IQ, or waterfall data. ```APIDOC ## KiwiSDRStream — Base WebSocket stream client The central base class in `kiwi/client.py`. Subclass it and override `_process_audio_samples`, `_process_iq_samples`, `_process_waterfall_samples`, and `_setup_rx_params` to build custom receivers. It handles connection, authentication, keepalive, ADPCM decoding, and dispatching incoming frames. ```python from kiwi import KiwiSDRStream, KiwiWorker class MyReceiver(KiwiSDRStream): def __init__(self, options): super().__init__() self._options = options self._type = 'SND' # 'SND' for audio/IQ, 'W/F' for waterfall def _setup_rx_params(self): # Called once after the server sends its sample rate self.set_name('my_client') self.set_freq(self._options.frequency) # kHz self.set_agc(on=True) # enable AGC def _process_audio_samples(self, seq, samples, rssi, fmt): # seq: sequence number, samples: np.int16 array, rssi: float dBm print(f'seq={seq:#010x} RSSI={rssi:.1f} dBm len={len(samples)}') def _process_iq_samples(self, seq, samples, rssi, gps, fmt): # samples: np.complex64 array, gps: dict with GPS timestamps or None import numpy as np power_db = 10 * np.log10(np.mean(np.abs(samples)**2) + 1e-20) print(f'IQ block {seq:#010x}: power={power_db:.1f} dB') def _process_waterfall_samples(self, seq, samples): # samples: array of uint8 values (0-255 → roughly -200..0 dBm) dBm = [int(s) - 255 for s in samples] peak = max(dBm) print(f'WF seq={seq} peak={peak} dBm') import optparse, time opts = optparse.Values() opts.frequency = 7000.0 # kHz opts.modulation = 'usb' opts.lp_cut = None opts.hp_cut = None opts.agc_gain = None opts.compression = True opts.nb = False opts.nb_gate = 100 opts.nb_thresh = 50 opts.nb_test = False opts.de_emp = False opts.freq_pbc = False opts.freq_offset = 0 opts.resample = 0 opts.S_meter = -1 opts.tlimit = 30.0 opts.sound = False opts.test_mode = False opts.scan_yaml = None opts.no_api = False opts.bad_cmd = False opts.devel = None opts.wf_comp = False opts.camp_chan = -1 opts.camp_allow_1ch = False opts.wideband = False opts.ADC_OV = False opts.quiet = True opts.not_quiet = False opts.log_level = 'warn' opts.tstamp = False opts.stats = False opts.multiple_connections = 0 opts.idx = 0 opts.server_host = 'kiwisdr.example.com' opts.server_port = 8073 opts.password = '' opts.tlimit_password = '' opts.admin = False opts.nolocal = False opts.socket_timeout = 10 opts.ws_timestamp = int(time.time()) & 0xffffffff opts.is_kiwi_wav = False recv = MyReceiver(opts) recv.connect('kiwisdr.example.com', 8073) recv.open() try: while True: recv.run() except Exception: pass recv.close() ``` ``` -------------------------------- ### KiwiIQWavReader Source: https://context7.com/jks-prv/kiwiclient/llms.txt Read GNSS-timestamped IQ WAV files using the KiwiSDR's non-standard format. This iterator class provides access to interleaved GNSS-timestamp and data chunks. ```APIDOC ## `KiwiIQWavReader` — Read GNSS-timestamped IQ WAV files Iterator class in `kiwi/wavreader.py` that reads the non-standard KiwiSDR IQ WAV format, which interleaves `kiwi` GNSS-timestamp chunks with `data` chunks. Returns `(t, z)` tuples: `t` is a `float64` GPS-second time array, `z` is `complex64` IQ samples normalised to ±1. ```python from kiwi.wavreader import KiwiIQWavReader, read_kiwi_iq_wav import numpy as np # --- Simple convenience function --- t, z = read_kiwi_iq_wav('20240601T120000Z_14074000_usb.wav') print(f'samples={len(z)}, duration={t[-1]-t[0]:.3f}s, fs={len(z)/(t[-1]-t[0]):.1f} Hz') # samples=11250, duration=30.000s, fs=375.0 Hz # --- Iterator for large files / streaming processing --- reader = KiwiIQWavReader('20240601T120000Z_7040000_iq.wav') print('Advertised sample rate:', reader.get_samplerate(), 'Hz') for t_chunk, z_chunk in reader: if t_chunk is None: # first two frames skipped for rate estimation continue power = 10 * np.log10(np.mean(np.abs(z_chunk)**2)) gps_t = t_chunk[0] print(f't={gps_t:.6f} power={power:.1f} dBFS n={len(z_chunk)}') # t=466823.886 power=-42.3 dBFS n=375 # t=466824.886 power=-43.1 dBFS n=375 ``` ``` -------------------------------- ### Plot Waterfall Spectrogram Source: https://github.com/jks-prv/kiwiclient/blob/master/waterfall_data_analysis.ipynb Visualizes the waterfall data as a spectrogram. Sets custom x-axis ticks to represent frequency based on center frequency and span. Uses a 'jet' colormap and sets color limits for better visualization. ```python figure(figsize=(40,8)) nticks = 11 xticks(np.linspace(0,nbin,nticks), np.linspace(start_freq, stop_freq, nticks)) pcolormesh(waterfall_array[:,1:], cmap=cm.jet , vmin=-100, vmax=-46) title("Recording time: %s"%rec_time) colorbar() ``` -------------------------------- ### Plot Multiple Spectra Source: https://github.com/jks-prv/kiwiclient/blob/master/waterfall_data_analysis.ipynb Plots several individual spectra from the waterfall data. Sets custom x-axis ticks for frequency. This is useful for examining the signal at different points in time. ```python figure(figsize=(20,8)) nticks = 11 xticks(np.linspace(0,nbin,nticks), np.linspace(start_freq, stop_freq, nticks)) for spectrum in waterfall_array[1:10]: plot(spectrum[1:]) ```